diff options
Diffstat (limited to 'virt/kvm/arm/vgic.c')
-rw-r--r-- | virt/kvm/arm/vgic.c | 48 |
1 files changed, 34 insertions, 14 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 56ff9bebb577..0e206091ebaf 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -76,6 +76,8 @@ #define IMPLEMENTER_ARM 0x43b #define GICC_ARCH_VERSION_V2 0x2 +#define vgic_nr_lr(vcpu) (vcpu->hw_cfg & HWCFG_NR_LR_MASK) + /* Physical address of vgic virtual cpu interface */ static phys_addr_t vgic_vcpu_base; @@ -97,7 +99,7 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu); static void vgic_update_state(struct kvm *kvm); static void vgic_kick_vcpus(struct kvm *kvm); static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg); -static u32 vgic_nr_lr; +static u32 vgic_hw_cfg; static unsigned int vgic_maint_irq; @@ -623,9 +625,9 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu) struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; int vcpu_id = vcpu->vcpu_id; int i, irq, source_cpu; - u32 *lr; + u32 *lr, nr_lr = vgic_nr_lr(vgic_cpu); - for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) { + for_each_set_bit(i, vgic_cpu->lr_used, nr_lr) { lr = &vgic_cpu->vgic_lr[i]; irq = LR_IRQID(*lr); source_cpu = LR_CPUID(*lr); @@ -1005,8 +1007,9 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu) { struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; int lr; + int nr_lr = vgic_nr_lr(vgic_cpu); - for_each_set_bit(lr, vgic_cpu->lr_used, vgic_cpu->nr_lr) { + for_each_set_bit(lr, vgic_cpu->lr_used, nr_lr) { int irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID; if (!vgic_irq_is_enabled(vcpu, irq)) { @@ -1025,6 +1028,7 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) { struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; int lr; + int nr_lr = vgic_nr_lr(vgic_cpu); /* Sanitize the input... */ BUG_ON(sgi_source_id & ~7); @@ -1046,9 +1050,8 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) } /* Try to use another LR for this interrupt */ - lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used, - vgic_cpu->nr_lr); - if (lr >= vgic_cpu->nr_lr) + lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used, nr_lr); + if (lr >= nr_lr) return false; kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id); @@ -1181,9 +1184,10 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) * active bit. */ int lr, irq; + int nr_lr = vgic_nr_lr(vgic_cpu); for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_eisr, - vgic_cpu->nr_lr) { + nr_lr) { irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID; vgic_irq_clear_active(vcpu, irq); @@ -1221,13 +1225,13 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; struct vgic_dist *dist = &vcpu->kvm->arch.vgic; int lr, pending; + int nr_lr = vgic_nr_lr(vgic_cpu); bool level_pending; level_pending = vgic_process_maintenance(vcpu); /* Clear mappings for empty LRs */ - for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr, - vgic_cpu->nr_lr) { + for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr, nr_lr) { int irq; if (!test_and_clear_bit(lr, vgic_cpu->lr_used)) @@ -1241,8 +1245,8 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) /* Check if we still have something up our sleeve... */ pending = find_first_zero_bit((unsigned long *)vgic_cpu->vgic_elrsr, - vgic_cpu->nr_lr); - if (level_pending || pending < vgic_cpu->nr_lr) + nr_lr); + if (level_pending || pending < nr_lr) set_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu); } @@ -1438,7 +1442,7 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu) */ vgic_cpu->vgic_vmcr = 0; - vgic_cpu->nr_lr = vgic_nr_lr; + vgic_cpu->hw_cfg = vgic_hw_cfg; vgic_cpu->vgic_hcr = GICH_HCR_EN; /* Get the show on the road... */ return 0; @@ -1470,17 +1474,32 @@ static struct notifier_block vgic_cpu_nb = { .notifier_call = vgic_cpu_notify, }; +static const struct of_device_id of_vgic_ids[] = { + { + .compatible = "arm,cortex-a15-gic", + .data = (void *)GICH_APR, + }, { + .compatible = "hisilicon,hip04-gic", + .data = (void *)HIP04_GICH_APR, + }, { + }, +}; + int kvm_vgic_hyp_init(void) { int ret; struct resource vctrl_res; struct resource vcpu_res; + const struct of_device_id *match; + u32 vgic_nr_lr; - vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic"); + vgic_node = of_find_matching_node_and_match(NULL, of_vgic_ids, &match); if (!vgic_node) { kvm_err("error: no compatible vgic node in DT\n"); return -ENODEV; } + /* High word of vgic_hw_cfg is the offset of GICH_APR. */ + vgic_hw_cfg = (unsigned int)match->data << HWCFG_APR_SHIFT; vgic_maint_irq = irq_of_parse_and_map(vgic_node, 0); if (!vgic_maint_irq) { @@ -1517,6 +1536,7 @@ int kvm_vgic_hyp_init(void) vgic_nr_lr = readl_relaxed(vgic_vctrl_base + GICH_VTR); vgic_nr_lr = (vgic_nr_lr & 0x3f) + 1; + vgic_hw_cfg |= vgic_nr_lr; ret = create_hyp_io_mappings(vgic_vctrl_base, vgic_vctrl_base + resource_size(&vctrl_res), |