[PATCH 02/23] irqchip/rvic: Add support for untrusted interrupt allocation

Marc Zyngier maz at kernel.org
Thu Sep 3 11:25:49 EDT 2020


Signed-off-by: Marc Zyngier <maz at kernel.org>
---
 drivers/irqchip/irq-rvic.c | 47 +++++++++++++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-rvic.c b/drivers/irqchip/irq-rvic.c
index 6f37aa4318b6..2747a452202f 100644
--- a/drivers/irqchip/irq-rvic.c
+++ b/drivers/irqchip/irq-rvic.c
@@ -37,6 +37,8 @@ static DEFINE_PER_CPU(unsigned long *, trusted_masked);
 struct rvic_data {
 	struct fwnode_handle	*fwnode;
 	struct irq_domain	*domain;
+	unsigned long 		*bitmap;
+	struct mutex		lock;
 	unsigned int		nr_trusted;
 	unsigned int		nr_untrusted;
 };
@@ -356,9 +358,26 @@ static int rvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 	irq_hw_number_t hwirq;
 	int i, ret;
 
-	ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
-	if (ret)
-		return ret;
+	if (fwspec) {
+		ret = irq_domain_translate_twocell(domain, fwspec,
+						   &hwirq, &type);
+		if (ret)
+			return ret;
+	} else {
+		/* rVID wants untrusted interrupts */
+		mutex_lock(&rvic.lock);
+		hwirq = bitmap_find_next_zero_area(rvic.bitmap,
+						   rvic.nr_untrusted,
+						   0, nr_irqs, 0);
+		if (hwirq < rvic.nr_untrusted)
+			bitmap_set(rvic.bitmap, hwirq, nr_irqs);
+		mutex_unlock(&rvic.lock);
+
+		if (hwirq >= rvic.nr_untrusted)
+			return -ENOSPC;
+
+		hwirq += rvic.nr_trusted;
+	}
 
 	for (i = 0; i < nr_irqs; i++) {
 		unsigned int intid = hwirq + i;
@@ -376,6 +395,12 @@ static int rvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 					    domain->host_data,
 					    handle_percpu_devid_irq,
 					    NULL, NULL);
+		} else if (intid < (rvic.nr_trusted + rvic.nr_untrusted)) {
+			irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
+			irq_domain_set_info(domain, irq, intid, &rvic_chip,
+					    domain->host_data,
+					    handle_fasteoi_irq,
+					    NULL, NULL);
 		} else {
 			return -EINVAL;
 		}
@@ -391,6 +416,11 @@ static void rvic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
 
 	for (i = 0; i < nr_irqs; i++) {
 		struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
+		if (d->hwirq >= rvic.nr_trusted) {
+			mutex_lock(&rvic.lock);
+			__clear_bit(d->hwirq, rvic.bitmap);
+			mutex_unlock(&rvic.lock);
+		}
 		irq_set_handler(virq + i, NULL);
 		irq_domain_reset_irq_data(d);
 	}
@@ -523,6 +553,12 @@ static int __init rvic_init(struct device_node *node,
 		return -ENOMEM;
 	}
 
+	rvic.bitmap = bitmap_alloc(rvic.nr_untrusted, GFP_KERNEL | __GFP_ZERO);
+	if (!rvic.bitmap) {
+		pr_warn("Failed to allocate untrusted bitmap\n");
+		goto free_domain;
+	}
+
 	for_each_possible_cpu(cpu) {
 		unsigned long *map = bitmap_alloc(rvic.nr_trusted, GFP_KERNEL);
 
@@ -537,6 +573,8 @@ static int __init rvic_init(struct device_node *node,
 		per_cpu(trusted_masked, cpu) = map;
 	}
 
+	mutex_init(&rvic.lock);
+
 	rvic_smp_init(rvic.fwnode);
 	set_handle_irq(rvic_handle_irq);
 
@@ -546,6 +584,9 @@ static int __init rvic_init(struct device_node *node,
 	for_each_possible_cpu(cpu)
 		kfree(per_cpu(trusted_masked, cpu));
 
+	kfree(rvic.bitmap);
+
+free_domain:
 	irq_domain_remove(rvic.domain);
 
 	return -ENOMEM;
-- 
2.27.0




More information about the linux-arm-kernel mailing list