Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 44 additions & 23 deletions arch/riscv/kvm/aia.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct aia_hgei_control {
raw_spinlock_t lock;
unsigned long free_bitmap;
struct kvm_vcpu *owners[BITS_PER_LONG];
unsigned int nr_hgei;
};
static DEFINE_PER_CPU(struct aia_hgei_control, aia_hgei);
static int hgei_parent_irq;
Expand Down Expand Up @@ -452,7 +453,7 @@ void kvm_riscv_aia_free_hgei(int cpu, int hgei)

raw_spin_lock_irqsave(&hgctrl->lock, flags);

if (hgei > 0 && hgei <= kvm_riscv_aia_nr_hgei) {
if (hgei > 0 && hgei <= hgctrl->nr_hgei) {
if (!(hgctrl->free_bitmap & BIT(hgei))) {
hgctrl->free_bitmap |= BIT(hgei);
hgctrl->owners[hgei] = NULL;
Expand Down Expand Up @@ -486,21 +487,8 @@ static irqreturn_t hgei_interrupt(int irq, void *dev_id)

static int aia_hgei_init(void)
{
int cpu, rc;
int rc;
struct irq_domain *domain;
struct aia_hgei_control *hgctrl;

/* Initialize per-CPU guest external interrupt line management */
for_each_possible_cpu(cpu) {
hgctrl = per_cpu_ptr(&aia_hgei, cpu);
raw_spin_lock_init(&hgctrl->lock);
if (kvm_riscv_aia_nr_hgei) {
hgctrl->free_bitmap =
BIT(kvm_riscv_aia_nr_hgei + 1) - 1;
hgctrl->free_bitmap &= ~BIT(0);
} else
hgctrl->free_bitmap = 0;
}

/* Skip SGEI interrupt setup for zero guest external interrupts */
if (!kvm_riscv_aia_nr_hgei)
Expand Down Expand Up @@ -545,9 +533,48 @@ static void aia_hgei_exit(void)

void kvm_riscv_aia_enable(void)
{
const struct imsic_global_config *gc;
const struct imsic_local_config *lc;
struct aia_hgei_control *hgctrl;

if (!kvm_riscv_aia_available())
return;

gc = imsic_get_global_config();
lc = (gc) ? this_cpu_ptr(gc->local) : NULL;
hgctrl = this_cpu_ptr(&aia_hgei);

/* Figure-out number of bits in HGEIE */
csr_write(CSR_HGEIE, -1UL);
hgctrl->nr_hgei = fls_long(csr_read(CSR_HGEIE));
csr_write(CSR_HGEIE, 0);
if (hgctrl->nr_hgei)
hgctrl->nr_hgei--;

/*
* Number of usable per-HART HGEI lines should be minimum of
* per-HART IMSIC guest files and number of bits in HGEIE.
*/
if (lc)
hgctrl->nr_hgei = min((ulong)hgctrl->nr_hgei, lc->nr_guest_files);
else
hgctrl->nr_hgei = 0;

/*
* The global number of usable HGEI lines should be minimum
* across all HARTs.
*/
kvm_riscv_aia_nr_hgei = min(kvm_riscv_aia_nr_hgei, hgctrl->nr_hgei);

if (hgctrl->nr_hgei) {
hgctrl->free_bitmap = BIT(hgctrl->nr_hgei + 1) - 1;
hgctrl->free_bitmap &= ~BIT(0);
} else {
hgctrl->free_bitmap = 0;
}

raw_spin_lock_init(&hgctrl->lock);

csr_write(CSR_HVICTL, aia_hvictl_value(false));
csr_write(CSR_HVIPRIO1, 0x0);
csr_write(CSR_HVIPRIO2, 0x0);
Expand Down Expand Up @@ -588,7 +615,7 @@ void kvm_riscv_aia_disable(void)

raw_spin_lock_irqsave(&hgctrl->lock, flags);

for (i = 0; i <= kvm_riscv_aia_nr_hgei; i++) {
for (i = 0; i <= hgctrl->nr_hgei; i++) {
vcpu = hgctrl->owners[i];
if (!vcpu)
continue;
Expand Down Expand Up @@ -634,14 +661,8 @@ int kvm_riscv_aia_init(void)
csr_write(CSR_HGEIE, 0);
if (kvm_riscv_aia_nr_hgei)
kvm_riscv_aia_nr_hgei--;

/*
* Number of usable HGEI lines should be minimum of per-HART
* IMSIC guest files and number of bits in HGEIE
*/
if (gc)
kvm_riscv_aia_nr_hgei = min((ulong)kvm_riscv_aia_nr_hgei,
gc->nr_guest_files);
kvm_riscv_aia_nr_hgei = min(kvm_riscv_aia_nr_hgei, gc->nr_guest_files);
else
kvm_riscv_aia_nr_hgei = 0;

Expand Down
9 changes: 4 additions & 5 deletions drivers/irqchip/irq-riscv-imsic-state.c
Original file line number Diff line number Diff line change
Expand Up @@ -920,13 +920,12 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
local->msi_va = mmios_va[index] + reloff;

/*
* KVM uses global->nr_guest_files to determine the available guest
* interrupt files on each CPU. Take the minimum number of guest
* interrupt files across all CPUs to avoid KVM incorrectly allocating
* an unexisted or unmapped guest interrupt file on some CPUs.
* KVM uses both local->nr_guest_files and global->nr_guest_files
* to determine the available guest interrupt files on each CPU.
*/
nr_guest_files = (resource_size(&mmios[index]) - reloff) / IMSIC_MMIO_PAGE_SZ - 1;
global->nr_guest_files = min(global->nr_guest_files, nr_guest_files);
local->nr_guest_files = min((BIT(global->guest_index_bits) - 1), nr_guest_files);
global->nr_guest_files = min(global->nr_guest_files, local->nr_guest_files);

nr_handlers++;
}
Expand Down
5 changes: 4 additions & 1 deletion include/linux/irqchip/riscv-imsic.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
struct imsic_local_config {
phys_addr_t msi_pa;
void __iomem *msi_va;

/* Number of guest interrupt files per-HART */
u32 nr_guest_files;
};

struct imsic_global_config {
Expand Down Expand Up @@ -68,7 +71,7 @@ struct imsic_global_config {
/* Number of guest interrupt identities */
u32 nr_guest_ids;

/* Number of guest interrupt files per core */
/* Number of guest interrupt files across all HARTs */
u32 nr_guest_files;

/* Per-CPU IMSIC addresses */
Expand Down