KVM: ARM: vgic: register kvm_device_ops dynamically
Now that we have a dynamic means to register kvm_device_ops, use that for the ARM VGIC, instead of relying on the static table. Cc: Gleb Natapov <gleb@kernel.org> Cc: Paolo Bonzini <pbonzini@redhat.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
d60eacb070
commit
c06a841bf3
@ -1069,7 +1069,6 @@ int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type);
|
|||||||
extern struct kvm_device_ops kvm_mpic_ops;
|
extern struct kvm_device_ops kvm_mpic_ops;
|
||||||
extern struct kvm_device_ops kvm_xics_ops;
|
extern struct kvm_device_ops kvm_xics_ops;
|
||||||
extern struct kvm_device_ops kvm_vfio_ops;
|
extern struct kvm_device_ops kvm_vfio_ops;
|
||||||
extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
|
|
||||||
extern struct kvm_device_ops kvm_flic_ops;
|
extern struct kvm_device_ops kvm_flic_ops;
|
||||||
|
|
||||||
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
|
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
|
||||||
|
@ -1522,83 +1522,6 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vgic_init_maintenance_interrupt(void *info)
|
|
||||||
{
|
|
||||||
enable_percpu_irq(vgic->maint_irq, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vgic_cpu_notify(struct notifier_block *self,
|
|
||||||
unsigned long action, void *cpu)
|
|
||||||
{
|
|
||||||
switch (action) {
|
|
||||||
case CPU_STARTING:
|
|
||||||
case CPU_STARTING_FROZEN:
|
|
||||||
vgic_init_maintenance_interrupt(NULL);
|
|
||||||
break;
|
|
||||||
case CPU_DYING:
|
|
||||||
case CPU_DYING_FROZEN:
|
|
||||||
disable_percpu_irq(vgic->maint_irq);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NOTIFY_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct notifier_block vgic_cpu_nb = {
|
|
||||||
.notifier_call = vgic_cpu_notify,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id vgic_ids[] = {
|
|
||||||
{ .compatible = "arm,cortex-a15-gic", .data = vgic_v2_probe, },
|
|
||||||
{ .compatible = "arm,gic-v3", .data = vgic_v3_probe, },
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
|
|
||||||
int kvm_vgic_hyp_init(void)
|
|
||||||
{
|
|
||||||
const struct of_device_id *matched_id;
|
|
||||||
int (*vgic_probe)(struct device_node *,const struct vgic_ops **,
|
|
||||||
const struct vgic_params **);
|
|
||||||
struct device_node *vgic_node;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
vgic_node = of_find_matching_node_and_match(NULL,
|
|
||||||
vgic_ids, &matched_id);
|
|
||||||
if (!vgic_node) {
|
|
||||||
kvm_err("error: no compatible GIC node found\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
vgic_probe = matched_id->data;
|
|
||||||
ret = vgic_probe(vgic_node, &vgic_ops, &vgic);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = request_percpu_irq(vgic->maint_irq, vgic_maintenance_handler,
|
|
||||||
"vgic", kvm_get_running_vcpus());
|
|
||||||
if (ret) {
|
|
||||||
kvm_err("Cannot register interrupt %d\n", vgic->maint_irq);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = __register_cpu_notifier(&vgic_cpu_nb);
|
|
||||||
if (ret) {
|
|
||||||
kvm_err("Cannot register vgic CPU notifier\n");
|
|
||||||
goto out_free_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Callback into for arch code for setup */
|
|
||||||
vgic_arch_setup(vgic);
|
|
||||||
|
|
||||||
on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_free_irq:
|
|
||||||
free_percpu_irq(vgic->maint_irq, kvm_get_running_vcpus());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_vgic_init - Initialize global VGIC state before running any VCPUs
|
* kvm_vgic_init - Initialize global VGIC state before running any VCPUs
|
||||||
* @kvm: pointer to the kvm struct
|
* @kvm: pointer to the kvm struct
|
||||||
@ -2062,7 +1985,7 @@ static int vgic_create(struct kvm_device *dev, u32 type)
|
|||||||
return kvm_vgic_create(dev->kvm);
|
return kvm_vgic_create(dev->kvm);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kvm_device_ops kvm_arm_vgic_v2_ops = {
|
static struct kvm_device_ops kvm_arm_vgic_v2_ops = {
|
||||||
.name = "kvm-arm-vgic",
|
.name = "kvm-arm-vgic",
|
||||||
.create = vgic_create,
|
.create = vgic_create,
|
||||||
.destroy = vgic_destroy,
|
.destroy = vgic_destroy,
|
||||||
@ -2070,3 +1993,81 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
|
|||||||
.get_attr = vgic_get_attr,
|
.get_attr = vgic_get_attr,
|
||||||
.has_attr = vgic_has_attr,
|
.has_attr = vgic_has_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void vgic_init_maintenance_interrupt(void *info)
|
||||||
|
{
|
||||||
|
enable_percpu_irq(vgic->maint_irq, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vgic_cpu_notify(struct notifier_block *self,
|
||||||
|
unsigned long action, void *cpu)
|
||||||
|
{
|
||||||
|
switch (action) {
|
||||||
|
case CPU_STARTING:
|
||||||
|
case CPU_STARTING_FROZEN:
|
||||||
|
vgic_init_maintenance_interrupt(NULL);
|
||||||
|
break;
|
||||||
|
case CPU_DYING:
|
||||||
|
case CPU_DYING_FROZEN:
|
||||||
|
disable_percpu_irq(vgic->maint_irq);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block vgic_cpu_nb = {
|
||||||
|
.notifier_call = vgic_cpu_notify,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id vgic_ids[] = {
|
||||||
|
{ .compatible = "arm,cortex-a15-gic", .data = vgic_v2_probe, },
|
||||||
|
{ .compatible = "arm,gic-v3", .data = vgic_v3_probe, },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
int kvm_vgic_hyp_init(void)
|
||||||
|
{
|
||||||
|
const struct of_device_id *matched_id;
|
||||||
|
int (*vgic_probe)(struct device_node *,const struct vgic_ops **,
|
||||||
|
const struct vgic_params **);
|
||||||
|
struct device_node *vgic_node;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
vgic_node = of_find_matching_node_and_match(NULL,
|
||||||
|
vgic_ids, &matched_id);
|
||||||
|
if (!vgic_node) {
|
||||||
|
kvm_err("error: no compatible GIC node found\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
vgic_probe = matched_id->data;
|
||||||
|
ret = vgic_probe(vgic_node, &vgic_ops, &vgic);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = request_percpu_irq(vgic->maint_irq, vgic_maintenance_handler,
|
||||||
|
"vgic", kvm_get_running_vcpus());
|
||||||
|
if (ret) {
|
||||||
|
kvm_err("Cannot register interrupt %d\n", vgic->maint_irq);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = __register_cpu_notifier(&vgic_cpu_nb);
|
||||||
|
if (ret) {
|
||||||
|
kvm_err("Cannot register vgic CPU notifier\n");
|
||||||
|
goto out_free_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback into for arch code for setup */
|
||||||
|
vgic_arch_setup(vgic);
|
||||||
|
|
||||||
|
on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
|
||||||
|
|
||||||
|
return kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
|
||||||
|
KVM_DEV_TYPE_ARM_VGIC_V2);
|
||||||
|
|
||||||
|
out_free_irq:
|
||||||
|
free_percpu_irq(vgic->maint_irq, kvm_get_running_vcpus());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -2286,10 +2286,6 @@ static struct kvm_device_ops *kvm_device_ops_table[KVM_DEV_TYPE_MAX] = {
|
|||||||
[KVM_DEV_TYPE_VFIO] = &kvm_vfio_ops,
|
[KVM_DEV_TYPE_VFIO] = &kvm_vfio_ops,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_KVM_ARM_VGIC
|
|
||||||
[KVM_DEV_TYPE_ARM_VGIC_V2] = &kvm_arm_vgic_v2_ops,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_S390
|
#ifdef CONFIG_S390
|
||||||
[KVM_DEV_TYPE_FLIC] = &kvm_flic_ops,
|
[KVM_DEV_TYPE_FLIC] = &kvm_flic_ops,
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user