Skip to content

Commit

Permalink
RISC-V: KVM: Initial skeletal support for AIA
Browse files Browse the repository at this point in the history
To incrementally implement AIA support, we first add minimal skeletal
support which only compiles and detects AIA hardware support at the
boot-time but does not provide any functionality.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
  • Loading branch information
Anup Patel authored and Anup Patel committed Apr 21, 2023
1 parent e290dbb commit 54e4332
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 6 deletions.
6 changes: 6 additions & 0 deletions arch/riscv/include/asm/hwcap.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
#define RISCV_ISA_EXT_MAX 64
#define RISCV_ISA_EXT_NAME_LEN_MAX 32

#ifdef CONFIG_RISCV_M_MODE
#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SMAIA
#else
#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SSAIA
#endif

#ifndef __ASSEMBLY__

#include <linux/jump_label.h>
Expand Down
109 changes: 109 additions & 0 deletions arch/riscv/include/asm/kvm_aia.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2021 Western Digital Corporation or its affiliates.
* Copyright (C) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/

#ifndef __KVM_RISCV_AIA_H
#define __KVM_RISCV_AIA_H

#include <linux/jump_label.h>
#include <linux/kvm_types.h>

struct kvm_aia {
/* In-kernel irqchip created */
bool in_kernel;

/* In-kernel irqchip initialized */
bool initialized;
};

struct kvm_vcpu_aia {
};

#define kvm_riscv_aia_initialized(k) ((k)->arch.aia.initialized)

#define irqchip_in_kernel(k) ((k)->arch.aia.in_kernel)

DECLARE_STATIC_KEY_FALSE(kvm_riscv_aia_available);
#define kvm_riscv_aia_available() \
static_branch_unlikely(&kvm_riscv_aia_available)

static inline void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)
{
}

static inline void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
{
}

static inline bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu,
u64 mask)
{
return false;
}

static inline void kvm_riscv_vcpu_aia_update_hvip(struct kvm_vcpu *vcpu)
{
}

static inline void kvm_riscv_vcpu_aia_load(struct kvm_vcpu *vcpu, int cpu)
{
}

static inline void kvm_riscv_vcpu_aia_put(struct kvm_vcpu *vcpu)
{
}

static inline int kvm_riscv_vcpu_aia_get_csr(struct kvm_vcpu *vcpu,
unsigned long reg_num,
unsigned long *out_val)
{
*out_val = 0;
return 0;
}

static inline int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
unsigned long reg_num,
unsigned long val)
{
return 0;
}

#define KVM_RISCV_VCPU_AIA_CSR_FUNCS

static inline int kvm_riscv_vcpu_aia_update(struct kvm_vcpu *vcpu)
{
return 1;
}

static inline void kvm_riscv_vcpu_aia_reset(struct kvm_vcpu *vcpu)
{
}

static inline int kvm_riscv_vcpu_aia_init(struct kvm_vcpu *vcpu)
{
return 0;
}

static inline void kvm_riscv_vcpu_aia_deinit(struct kvm_vcpu *vcpu)
{
}

static inline void kvm_riscv_aia_init_vm(struct kvm *kvm)
{
}

static inline void kvm_riscv_aia_destroy_vm(struct kvm *kvm)
{
}

void kvm_riscv_aia_enable(void);
void kvm_riscv_aia_disable(void);
int kvm_riscv_aia_init(void);
void kvm_riscv_aia_exit(void);

#endif
7 changes: 7 additions & 0 deletions arch/riscv/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/kvm_types.h>
#include <linux/spinlock.h>
#include <asm/hwcap.h>
#include <asm/kvm_aia.h>
#include <asm/kvm_vcpu_fp.h>
#include <asm/kvm_vcpu_insn.h>
#include <asm/kvm_vcpu_sbi.h>
Expand Down Expand Up @@ -94,6 +95,9 @@ struct kvm_arch {

/* Guest Timer */
struct kvm_guest_timer timer;

/* AIA Guest/VM context */
struct kvm_aia aia;
};

struct kvm_cpu_trap {
Expand Down Expand Up @@ -221,6 +225,9 @@ struct kvm_vcpu_arch {
/* SBI context */
struct kvm_vcpu_sbi_context sbi_context;

/* AIA VCPU context */
struct kvm_vcpu_aia aia_context;

/* Cache pages needed to program page tables with spinlock held */
struct kvm_mmu_memory_cache mmu_page_cache;

Expand Down
1 change: 1 addition & 0 deletions arch/riscv/kvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ kvm-y += vcpu_sbi_replace.o
kvm-y += vcpu_sbi_hsm.o
kvm-y += vcpu_timer.o
kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o
kvm-y += aia.o
66 changes: 66 additions & 0 deletions arch/riscv/kvm/aia.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Western Digital Corporation or its affiliates.
* Copyright (C) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/

#include <linux/kvm_host.h>
#include <asm/hwcap.h>

DEFINE_STATIC_KEY_FALSE(kvm_riscv_aia_available);

static void aia_set_hvictl(bool ext_irq_pending)
{
unsigned long hvictl;

/*
* HVICTL.IID == 9 and HVICTL.IPRIO == 0 represents
* no interrupt in HVICTL.
*/

hvictl = (IRQ_S_EXT << HVICTL_IID_SHIFT) & HVICTL_IID;
hvictl |= ext_irq_pending;
csr_write(CSR_HVICTL, hvictl);
}

void kvm_riscv_aia_enable(void)
{
if (!kvm_riscv_aia_available())
return;

aia_set_hvictl(false);
csr_write(CSR_HVIPRIO1, 0x0);
csr_write(CSR_HVIPRIO2, 0x0);
#ifdef CONFIG_32BIT
csr_write(CSR_HVIPH, 0x0);
csr_write(CSR_HIDELEGH, 0x0);
csr_write(CSR_HVIPRIO1H, 0x0);
csr_write(CSR_HVIPRIO2H, 0x0);
#endif
}

void kvm_riscv_aia_disable(void)
{
if (!kvm_riscv_aia_available())
return;

aia_set_hvictl(false);
}

int kvm_riscv_aia_init(void)
{
if (!riscv_isa_extension_available(NULL, SxAIA))
return -ENODEV;

/* Enable KVM AIA support */
static_branch_enable(&kvm_riscv_aia_available);

return 0;
}

void kvm_riscv_aia_exit(void)
{
}
22 changes: 21 additions & 1 deletion arch/riscv/kvm/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@ int kvm_arch_hardware_enable(void)

csr_write(CSR_HVIP, 0);

kvm_riscv_aia_enable();

return 0;
}

void kvm_arch_hardware_disable(void)
{
kvm_riscv_aia_disable();

/*
* After clearing the hideleg CSR, the host kernel will receive
* spurious interrupts if hvip CSR has pending interrupts and the
Expand All @@ -63,6 +67,7 @@ void kvm_arch_hardware_disable(void)

static int __init riscv_kvm_init(void)
{
int rc;
const char *str;

if (!riscv_isa_extension_available(NULL, h)) {
Expand All @@ -84,6 +89,10 @@ static int __init riscv_kvm_init(void)

kvm_riscv_gstage_vmid_detect();

rc = kvm_riscv_aia_init();
if (rc && rc != -ENODEV)
return rc;

kvm_info("hypervisor extension available\n");

switch (kvm_riscv_gstage_mode()) {
Expand All @@ -106,12 +115,23 @@ static int __init riscv_kvm_init(void)

kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits());

return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
if (kvm_riscv_aia_available())
kvm_info("AIA available\n");

rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
if (rc) {
kvm_riscv_aia_exit();
return rc;
}

return 0;
}
module_init(riscv_kvm_init);

static void __exit riscv_kvm_exit(void)
{
kvm_riscv_aia_exit();

kvm_exit();
}
module_exit(riscv_kvm_exit);
Loading

0 comments on commit 54e4332

Please sign in to comment.