Allocate per-VPE SGIs when initializing the GIC-specific part of the
VPE data structure.

Signed-off-by: Marc Zyngier <m...@kernel.org>
---
 drivers/irqchip/irq-gic-v4.c       | 68 +++++++++++++++++++++++++++++-
 include/linux/irqchip/arm-gic-v4.h |  2 +
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c
index 117ba6db023d..99b33f60ac63 100644
--- a/drivers/irqchip/irq-gic-v4.c
+++ b/drivers/irqchip/irq-gic-v4.c
@@ -92,6 +92,47 @@ static bool has_v4_1(void)
        return !!sgi_domain_ops;
 }
 
+static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
+{
+       char *name;
+       int sgi_base;
+
+       if (!has_v4_1())
+               return 0;
+
+       name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current));
+       if (!name)
+               goto err;
+
+       vpe->fwnode = irq_domain_alloc_named_id_fwnode(name, idx);
+       if (!vpe->fwnode)
+               goto err;
+
+       kfree(name);
+       name = NULL;
+
+       vpe->sgi_domain = irq_domain_create_linear(vpe->fwnode, 16,
+                                                  sgi_domain_ops, vpe);
+       if (!vpe->sgi_domain)
+               goto err;
+
+       sgi_base = __irq_domain_alloc_irqs(vpe->sgi_domain, -1, 16,
+                                              NUMA_NO_NODE, vpe,
+                                              false, NULL);
+       if (sgi_base <= 0)
+               goto err;
+
+       return 0;
+
+err:
+       if (vpe->sgi_domain)
+               irq_domain_remove(vpe->sgi_domain);
+       if (vpe->fwnode)
+               irq_domain_free_fwnode(vpe->fwnode);
+       kfree(name);
+       return -ENOMEM;
+}
+
 int its_alloc_vcpu_irqs(struct its_vm *vm)
 {
        int vpe_base_irq, i;
@@ -118,8 +159,13 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
        if (vpe_base_irq <= 0)
                goto err;
 
-       for (i = 0; i < vm->nr_vpes; i++)
+       for (i = 0; i < vm->nr_vpes; i++) {
+               int ret;
                vm->vpes[i]->irq = vpe_base_irq + i;
+               ret = its_alloc_vcpu_sgis(vm->vpes[i], i);
+               if (ret)
+                       goto err;
+       }
 
        return 0;
 
@@ -132,8 +178,28 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
        return -ENOMEM;
 }
 
+static void its_free_sgi_irqs(struct its_vm *vm)
+{
+       int i;
+
+       if (!has_v4_1())
+               return;
+
+       for (i = 0; i < vm->nr_vpes; i++) {
+               unsigned int irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);
+
+               if (WARN_ON(!irq))
+                       continue;
+
+               irq_domain_free_irqs(irq, 16);
+               irq_domain_remove(vm->vpes[i]->sgi_domain);
+               irq_domain_free_fwnode(vm->vpes[i]->fwnode);
+       }
+}
+
 void its_free_vcpu_irqs(struct its_vm *vm)
 {
+       its_free_sgi_irqs(vm);
        irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes);
        irq_domain_remove(vm->domain);
        irq_domain_free_fwnode(vm->fwnode);
diff --git a/include/linux/irqchip/arm-gic-v4.h 
b/include/linux/irqchip/arm-gic-v4.h
index cca4198fa1d5..9fbd0418f569 100644
--- a/include/linux/irqchip/arm-gic-v4.h
+++ b/include/linux/irqchip/arm-gic-v4.h
@@ -49,6 +49,8 @@ struct its_vpe {
                };
                /* GICv4.1 implementations */
                struct {
+                       struct fwnode_handle    *fwnode;
+                       struct irq_domain       *sgi_domain;
                        struct {
                                u8      priority;
                                bool    enabled;
-- 
2.20.1

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to