LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 0/7] Partitioned percpu IRQ rework
@ 2018-04-24 14:36 Marc Zyngier
  2018-04-24 14:36 ` [PATCH 1/7] genirq/debugfs: Print percpu affinity for percpu_devid interrupts Marc Zyngier
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

Partitioned percpu interrupts are a very niche sport, even in the ARM
world. They occur when each CPU have a private device connected to a
per-CPU interrupt, but not all the devices are the same.

The best example of this occurs on the Rockchip rk3399 SoC, where all
the CPUs have a PMU connected to the same PPI (very good), except that
because this is a big-little system, we end-up with two different PMUs
(quite bad).

We already have some code to deal with this, but it integrates badly
with the debug infrastructure, and makes assumptions about the trigger
of the source interrupt (see the use of IRQ_TYPE_NONE in the GICv3
driver).

This series provides a better integration with debugfs, and cleans up
some of the most horrible parts of this code by simply moving the
plugging of the partition to the activate callback.

This has been tested on a (specially hack-up) KVM guest.

Thanks,

	M.

Marc Zyngier (7):
  genirq/debugfs: Print percpu affinity for percpu_devid interrupts
  genirq/debugfs: Use irq_print_chip method if available
  genirq/debugfs: Allow irq domain name to be overriden
  irqchip/partition-percpu: Override domain name in debugfs
  irqchip/partition-percpu: Refactor backend method calling
  irqchip/partition-percpu: Allow chained_desc to be NULL
  irqchip/partition-percpu: Move allocation of chained interrupt to
    activate

 drivers/irqchip/irq-gic-v3.c                 |  31 ++----
 drivers/irqchip/irq-partition-percpu.c       | 147 ++++++++++++++++++---------
 include/linux/irqchip/irq-partition-percpu.h |   4 +-
 include/linux/irqdomain.h                    |   1 +
 kernel/irq/debugfs.c                         |  13 ++-
 kernel/irq/irqdomain.c                       |  14 +++
 6 files changed, 138 insertions(+), 72 deletions(-)

-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/7] genirq/debugfs: Print percpu affinity for percpu_devid interrupts
  2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
@ 2018-04-24 14:36 ` Marc Zyngier
  2018-04-24 14:36 ` [PATCH 2/7] genirq/debugfs: Use irq_print_chip method if available Marc Zyngier
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

percpu_devid interrupts have their affinities stored in a different
field. Let's special-case it.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 kernel/irq/debugfs.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
index 4dadeb3d6666..da41150322e1 100644
--- a/kernel/irq/debugfs.c
+++ b/kernel/irq/debugfs.c
@@ -32,7 +32,10 @@ static void irq_debug_show_masks(struct seq_file *m, struct irq_desc *desc)
 	struct irq_data *data = irq_desc_get_irq_data(desc);
 	struct cpumask *msk;
 
-	msk = irq_data_get_affinity_mask(data);
+	if (irq_is_percpu_devid(data->irq))
+		msk = (struct cpumask *)desc->percpu_affinity;
+	else
+		msk = irq_data_get_affinity_mask(data);
 	seq_printf(m, "affinity: %*pbl\n", cpumask_pr_args(msk));
 #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
 	msk = irq_data_get_effective_affinity_mask(data);
-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/7] genirq/debugfs: Use irq_print_chip method if available
  2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
  2018-04-24 14:36 ` [PATCH 1/7] genirq/debugfs: Print percpu affinity for percpu_devid interrupts Marc Zyngier
@ 2018-04-24 14:36 ` Marc Zyngier
  2018-04-24 14:36 ` [PATCH 3/7] genirq/debugfs: Allow irq domain name to be overriden Marc Zyngier
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

If an irqchip has provided an irq_print_chip method, let's use
it instead of the name field directly.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 kernel/irq/debugfs.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
index da41150322e1..50e324110271 100644
--- a/kernel/irq/debugfs.c
+++ b/kernel/irq/debugfs.c
@@ -69,7 +69,13 @@ irq_debug_show_chip(struct seq_file *m, struct irq_data *data, int ind)
 		seq_printf(m, "chip: None\n");
 		return;
 	}
-	seq_printf(m, "%*schip:    %s\n", ind, "", chip->name);
+	seq_printf(m, "%*schip:    ", ind, "");
+	if (chip->irq_print_chip) {
+		chip->irq_print_chip(data, m);
+		seq_printf(m, "\n");
+	} else {
+		seq_printf(m, "%s\n", chip->name);
+	}
 	seq_printf(m, "%*sflags:   0x%lx\n", ind + 1, "", chip->flags);
 	irq_debug_show_bits(m, ind, chip->flags, irqchip_flags,
 			    ARRAY_SIZE(irqchip_flags));
-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/7] genirq/debugfs: Allow irq domain name to be overriden
  2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
  2018-04-24 14:36 ` [PATCH 1/7] genirq/debugfs: Print percpu affinity for percpu_devid interrupts Marc Zyngier
  2018-04-24 14:36 ` [PATCH 2/7] genirq/debugfs: Use irq_print_chip method if available Marc Zyngier
@ 2018-04-24 14:36 ` Marc Zyngier
  2018-04-24 14:36 ` [PATCH 4/7] irqchip/partition-percpu: Override domain name in debugfs Marc Zyngier
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

As for irqchip, it would be useful for a domain to generate its
name dynamically, and thus control the name that gets used in
debugfs.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqdomain.h |  1 +
 kernel/irq/irqdomain.c    | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 48c7e86bb556..a912b1cc1715 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -119,6 +119,7 @@ struct irq_domain_ops {
 			 unsigned long *out_hwirq, unsigned int *out_type);
 #endif
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+	char *(*override_name)(struct irq_domain *d);
 	void (*debug_show)(struct seq_file *m, struct irq_domain *d,
 			   struct irq_data *irqd, int ind);
 #endif
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 5d9fc01b60a6..521065c8bace 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -220,6 +220,20 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
 	domain->revmap_direct_max_irq = direct_max;
 	irq_domain_check_hierarchy(domain);
 
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+	if (domain->ops->override_name) {
+		char *new_name;
+
+		new_name = domain->ops->override_name(domain);
+		if (new_name) {
+			if (domain->flags & IRQ_DOMAIN_NAME_ALLOCATED)
+				kfree(domain->name);
+			domain->name = new_name;
+			domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
+		}
+	}
+#endif
+
 	mutex_lock(&irq_domain_mutex);
 	debugfs_add_domain_dir(domain);
 	list_add(&domain->link, &irq_domain_list);
-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 4/7] irqchip/partition-percpu: Override domain name in debugfs
  2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
                   ` (2 preceding siblings ...)
  2018-04-24 14:36 ` [PATCH 3/7] genirq/debugfs: Allow irq domain name to be overriden Marc Zyngier
@ 2018-04-24 14:36 ` Marc Zyngier
  2018-04-24 14:36 ` [PATCH 5/7] irqchip/partition-percpu: Refactor backend method calling Marc Zyngier
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

So far, domain names that implement a percpu_devid partition
inherit the main domain name, which leads to conflicts in debugfs
and results in the absence of important data.

Let's provide a callback that will repaint the default name, and
keep all the data available.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-partition-percpu.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c
index ccd72c2cbc23..229f96ab3e26 100644
--- a/drivers/irqchip/irq-partition-percpu.c
+++ b/drivers/irqchip/irq-partition-percpu.c
@@ -205,6 +205,15 @@ int partition_translate_id(struct partition_desc *desc, void *partition_id)
 	return i;
 }
 
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+static atomic_t part_id;
+static char *partition_override_name(struct irq_domain *domain)
+{
+	return kasprintf(GFP_KERNEL, "%s-part-%d",
+			 domain->name, atomic_fetch_inc(&part_id));
+}
+#endif
+
 struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
 					     struct partition_affinity *parts,
 					     int nr_parts,
@@ -223,6 +232,9 @@ struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
 	desc->ops = *ops;
 	desc->ops.free = partition_domain_free;
 	desc->ops.alloc = partition_domain_alloc;
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+	desc->ops.override_name = partition_override_name;
+#endif
 
 	d = irq_domain_create_linear(fwnode, nr_parts, &desc->ops, desc);
 	if (!d)
-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 5/7] irqchip/partition-percpu: Refactor backend method calling
  2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
                   ` (3 preceding siblings ...)
  2018-04-24 14:36 ` [PATCH 4/7] irqchip/partition-percpu: Override domain name in debugfs Marc Zyngier
@ 2018-04-24 14:36 ` Marc Zyngier
  2018-04-24 14:36 ` [PATCH 6/7] irqchip/partition-percpu: Allow chained_desc to be NULL Marc Zyngier
  2018-04-24 14:36 ` [PATCH 7/7] irqchip/partition-percpu: Move allocation of chained interrupt to activate Marc Zyngier
  6 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

The various methods provided by the partition-percpu irqchip are only
wrappers that end-up calling into the underlying irqchip. As we're
about to change the code a bit, let's start with introducing a set
of helpers that will make that transition much more painless.

No functionnal change.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-partition-percpu.c | 70 +++++++++++++++-------------------
 1 file changed, 30 insertions(+), 40 deletions(-)

diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c
index 229f96ab3e26..be0df6e0add9 100644
--- a/drivers/irqchip/irq-partition-percpu.c
+++ b/drivers/irqchip/irq-partition-percpu.c
@@ -39,68 +39,58 @@ static bool partition_check_cpu(struct partition_desc *part,
 	return cpumask_test_cpu(cpu, &part->parts[hwirq].mask);
 }
 
+#define PART_IF_METHOD(method, d)					\
+	struct partition_desc *part;					\
+	struct irq_chip *chip;						\
+	struct irq_data *data;						\
+									\
+	part = irq_data_get_irq_chip_data(d);				\
+	chip = irq_desc_get_chip(part->chained_desc);			\
+	data = irq_desc_get_irq_data(part->chained_desc);		\
+	if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&	\
+	    chip->method)
+
+#define PART_CALL_METHOD_VOID(method, d, ...)				\
+	do {								\
+		PART_IF_METHOD(method, d)				\
+			chip->method(data, ##__VA_ARGS__);		\
+	} while(0)
+
+#define PART_CALL_METHOD_INT(retval, method, d, ...)			\
+	({								\
+		int ret = retval;					\
+		PART_IF_METHOD(method, d)				\
+			ret = chip->method(data, ##__VA_ARGS__);	\
+		ret;							\
+	})
+
 static void partition_irq_mask(struct irq_data *d)
 {
-	struct partition_desc *part = irq_data_get_irq_chip_data(d);
-	struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
-	struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
-
-	if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
-	    chip->irq_mask)
-		chip->irq_mask(data);
+	PART_CALL_METHOD_VOID(irq_mask, d);
 }
 
 static void partition_irq_unmask(struct irq_data *d)
 {
-	struct partition_desc *part = irq_data_get_irq_chip_data(d);
-	struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
-	struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
-
-	if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
-	    chip->irq_unmask)
-		chip->irq_unmask(data);
+	PART_CALL_METHOD_VOID(irq_unmask, d);
 }
 
 static int partition_irq_set_irqchip_state(struct irq_data *d,
 					   enum irqchip_irq_state which,
 					   bool val)
 {
-	struct partition_desc *part = irq_data_get_irq_chip_data(d);
-	struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
-	struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
-
-	if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
-	    chip->irq_set_irqchip_state)
-		return chip->irq_set_irqchip_state(data, which, val);
-
-	return -EINVAL;
+	return PART_CALL_METHOD_INT(-EINVAL, irq_set_irqchip_state, d, which, val);
 }
 
 static int partition_irq_get_irqchip_state(struct irq_data *d,
 					   enum irqchip_irq_state which,
 					   bool *val)
 {
-	struct partition_desc *part = irq_data_get_irq_chip_data(d);
-	struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
-	struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
-
-	if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
-	    chip->irq_get_irqchip_state)
-		return chip->irq_get_irqchip_state(data, which, val);
-
-	return -EINVAL;
+	return PART_CALL_METHOD_INT(-EINVAL, irq_get_irqchip_state, d, which, val);
 }
 
 static int partition_irq_set_type(struct irq_data *d, unsigned int type)
 {
-	struct partition_desc *part = irq_data_get_irq_chip_data(d);
-	struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
-	struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
-
-	if (chip->irq_set_type)
-		return chip->irq_set_type(data, type);
-
-	return -EINVAL;
+	return PART_CALL_METHOD_INT(IRQ_SET_MASK_OK_NOCOPY, irq_set_type, d, type);
 }
 
 static void partition_irq_print_chip(struct irq_data *d, struct seq_file *p)
-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 6/7] irqchip/partition-percpu: Allow chained_desc to be NULL
  2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
                   ` (4 preceding siblings ...)
  2018-04-24 14:36 ` [PATCH 5/7] irqchip/partition-percpu: Refactor backend method calling Marc Zyngier
@ 2018-04-24 14:36 ` Marc Zyngier
  2018-04-24 14:36 ` [PATCH 7/7] irqchip/partition-percpu: Move allocation of chained interrupt to activate Marc Zyngier
  6 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

As we're about to delay the binding of the partionned interrupt
to the underlying irqchip, we can end-up in a situation where
chained_desc will be NULL, and the operation cannot be carried
out.

Let's make sure we don't explode if that happens.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-partition-percpu.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c
index be0df6e0add9..79a1ef0c0f73 100644
--- a/drivers/irqchip/irq-partition-percpu.c
+++ b/drivers/irqchip/irq-partition-percpu.c
@@ -33,6 +33,18 @@ struct partition_desc {
 	struct irq_domain_ops		ops;
 };
 
+static struct irq_data *partition_get_irqd_chip(struct partition_desc *part,
+						struct irq_chip **chip)
+{
+	if (part->chained_desc) {
+		*chip = irq_desc_get_chip(part->chained_desc);
+		return irq_desc_get_irq_data(part->chained_desc);
+	}
+
+	*chip = NULL;
+	return NULL;
+}
+
 static bool partition_check_cpu(struct partition_desc *part,
 				unsigned int cpu, unsigned int hwirq)
 {
@@ -45,9 +57,9 @@ static bool partition_check_cpu(struct partition_desc *part,
 	struct irq_data *data;						\
 									\
 	part = irq_data_get_irq_chip_data(d);				\
-	chip = irq_desc_get_chip(part->chained_desc);			\
-	data = irq_desc_get_irq_data(part->chained_desc);		\
-	if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&	\
+	data = partition_get_irqd_chip(part, &chip);			\
+	if (data &&							\
+	    partition_check_cpu(part, smp_processor_id(), d->hwirq) &&	\
 	    chip->method)
 
 #define PART_CALL_METHOD_VOID(method, d, ...)				\
@@ -96,10 +108,12 @@ static int partition_irq_set_type(struct irq_data *d, unsigned int type)
 static void partition_irq_print_chip(struct irq_data *d, struct seq_file *p)
 {
 	struct partition_desc *part = irq_data_get_irq_chip_data(d);
-	struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
-	struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
+	struct irq_chip *chip;
+	struct irq_data *data;
 
-	seq_printf(p, " %5s-%lu", chip->name, data->hwirq);
+	data = partition_get_irqd_chip(part, &chip);
+	if (data)
+		seq_printf(p, " %5s-%lu", chip->name, data->hwirq);
 }
 
 static struct irq_chip partition_irq_chip = {
-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 7/7] irqchip/partition-percpu: Move allocation of chained interrupt to activate
  2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
                   ` (5 preceding siblings ...)
  2018-04-24 14:36 ` [PATCH 6/7] irqchip/partition-percpu: Allow chained_desc to be NULL Marc Zyngier
@ 2018-04-24 14:36 ` Marc Zyngier
  6 siblings, 0 replies; 8+ messages in thread
From: Marc Zyngier @ 2018-04-24 14:36 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper; +Cc: linux-kernel

The partition-percpu helpers work by tying the real interrupt to an
affinity-driven chained irqchip. So far, all the interrupt that can be
partitionned are being created at boot time.

This is a waste of resource, and means that we need to bypass some of
the critical checks (such as the trigger configuration).

A much better approach would be to create the backing interrupt when
one of the muxed interrupts gets activated, making sure we do things
on demand, and expose the right trigger information to the rest of
the kernel.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-gic-v3.c                 | 31 +++++++------------
 drivers/irqchip/irq-partition-percpu.c       | 45 +++++++++++++++++++++++++---
 include/linux/irqchip/irq-partition-percpu.h |  4 +--
 3 files changed, 53 insertions(+), 27 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index e5d101418390..f4c6d2223191 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -922,8 +922,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
 	return 0;
 }
 
-#define GIC_IRQ_TYPE_PARTITION	(GIC_IRQ_TYPE_LPI + 1)
-
 static int gic_irq_domain_translate(struct irq_domain *d,
 				    struct irq_fwspec *fwspec,
 				    unsigned long *hwirq,
@@ -938,7 +936,6 @@ static int gic_irq_domain_translate(struct irq_domain *d,
 			*hwirq = fwspec->param[1] + 32;
 			break;
 		case 1:			/* PPI */
-		case GIC_IRQ_TYPE_PARTITION:
 			*hwirq = fwspec->param[1] + 16;
 			break;
 		case GIC_IRQ_TYPE_LPI:	/* LPI */
@@ -952,10 +949,8 @@ static int gic_irq_domain_translate(struct irq_domain *d,
 
 		/*
 		 * Make it clear that broken DTs are... broken.
-		 * Partitionned PPIs are an unfortunate exception.
 		 */
-		WARN_ON(*type == IRQ_TYPE_NONE &&
-			fwspec->param[0] != GIC_IRQ_TYPE_PARTITION);
+		WARN_ON(*type == IRQ_TYPE_NONE);
 		return 0;
 	}
 
@@ -1143,6 +1138,12 @@ static int __init gic_validate_dist_version(void __iomem *dist_base)
 	return 0;
 }
 
+static void partition_fwspec_convert(struct irq_fwspec *fwspec)
+{
+	BUG_ON(fwspec->param_count != 4);
+	fwspec->param_count = 3;
+}
+
 /* Create all possible partitions at boot time */
 static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
 {
@@ -1207,23 +1208,11 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
 	}
 
 	for (i = 0; i < 16; i++) {
-		unsigned int irq;
 		struct partition_desc *desc;
-		struct irq_fwspec ppi_fwspec = {
-			.fwnode		= gic_data.fwnode,
-			.param_count	= 3,
-			.param		= {
-				[0]	= GIC_IRQ_TYPE_PARTITION,
-				[1]	= i,
-				[2]	= IRQ_TYPE_NONE,
-			},
-		};
-
-		irq = irq_create_fwspec_mapping(&ppi_fwspec);
-		if (WARN_ON(!irq))
-			continue;
+
 		desc = partition_create_desc(gic_data.fwnode, parts, nr_parts,
-					     irq, &partition_domain_ops);
+					     partition_fwspec_convert,
+					     &partition_domain_ops);
 		if (WARN_ON(!desc))
 			continue;
 
diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c
index 79a1ef0c0f73..009ce5c97b05 100644
--- a/drivers/irqchip/irq-partition-percpu.c
+++ b/drivers/irqchip/irq-partition-percpu.c
@@ -25,12 +25,15 @@
 #include <linux/slab.h>
 
 struct partition_desc {
+	struct mutex			lock;
 	int				nr_parts;
 	struct partition_affinity	*parts;
 	struct irq_domain		*domain;
 	struct irq_desc			*chained_desc;
 	unsigned long			*bitmap;
 	struct irq_domain_ops		ops;
+	struct irq_fwspec		fwspec;
+	void (*convert)(struct irq_fwspec *fwspec);
 };
 
 static struct irq_data *partition_get_irqd_chip(struct partition_desc *part,
@@ -166,9 +169,14 @@ static int partition_domain_alloc(struct irq_domain *domain, unsigned int virq,
 
 	part = domain->host_data;
 
+	mutex_lock(&part->lock);
+	if (!part->fwspec.param_count) {
+		part->fwspec = *fwspec;
+		part->convert(&part->fwspec);
+	}
+	mutex_unlock(&part->lock);
+
 	set_bit(hwirq, part->bitmap);
-	irq_set_chained_handler_and_data(irq_desc_get_irq(part->chained_desc),
-					 partition_handle_irq, part);
 	irq_set_percpu_devid_partition(virq, &part->parts[hwirq].mask);
 	irq_domain_set_info(domain, virq, hwirq, &partition_irq_chip, part,
 			    handle_percpu_devid_irq, NULL, NULL);
@@ -209,6 +217,32 @@ int partition_translate_id(struct partition_desc *desc, void *partition_id)
 	return i;
 }
 
+static int partition_domain_activate(struct irq_domain *domain,
+				     struct irq_data *d, bool reserve)
+{
+	struct partition_desc *part = irq_data_get_irq_chip_data(d);
+	int ret = 0;
+
+	mutex_lock(&part->lock);
+	if (!part->chained_desc) {
+		unsigned int irq;
+
+		irq = irq_create_fwspec_mapping(&part->fwspec);
+		if (WARN_ON(!irq)) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		part->chained_desc = irq_to_desc(irq);
+		irq_set_chained_handler_and_data(irq,
+						 partition_handle_irq,
+						 part);
+	}
+out:
+	mutex_unlock(&part->lock);
+	return ret;
+}
+
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
 static atomic_t part_id;
 static char *partition_override_name(struct irq_domain *domain)
@@ -221,7 +255,7 @@ static char *partition_override_name(struct irq_domain *domain)
 struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
 					     struct partition_affinity *parts,
 					     int nr_parts,
-					     int chained_irq,
+					     void (*convert)(struct irq_fwspec *fwspec),
 					     const struct irq_domain_ops *ops)
 {
 	struct partition_desc *desc;
@@ -233,12 +267,16 @@ struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
 	if (!desc)
 		return NULL;
 
+	mutex_init(&desc->lock);
+
 	desc->ops = *ops;
 	desc->ops.free = partition_domain_free;
 	desc->ops.alloc = partition_domain_alloc;
+	desc->ops.activate = partition_domain_activate;
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
 	desc->ops.override_name = partition_override_name;
 #endif
+	desc->convert = convert;
 
 	d = irq_domain_create_linear(fwnode, nr_parts, &desc->ops, desc);
 	if (!d)
@@ -250,7 +288,6 @@ struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
 	if (WARN_ON(!desc->bitmap))
 		goto out;
 
-	desc->chained_desc = irq_to_desc(chained_irq);
 	desc->nr_parts = nr_parts;
 	desc->parts = parts;
 
diff --git a/include/linux/irqchip/irq-partition-percpu.h b/include/linux/irqchip/irq-partition-percpu.h
index 87433a5d1285..9c408005fa25 100644
--- a/include/linux/irqchip/irq-partition-percpu.h
+++ b/include/linux/irqchip/irq-partition-percpu.h
@@ -31,7 +31,7 @@ int partition_translate_id(struct partition_desc *desc, void *partition_id);
 struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
 					     struct partition_affinity *parts,
 					     int nr_parts,
-					     int chained_irq,
+					     void (*convert)(struct irq_fwspec *fwspec),
 					     const struct irq_domain_ops *ops);
 struct irq_domain *partition_get_domain(struct partition_desc *dsc);
 #else
@@ -45,7 +45,7 @@ static inline
 struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
 					     struct partition_affinity *parts,
 					     int nr_parts,
-					     int chained_irq,
+					     void (*convert)(struct irq_fwspec *fwspec),
 					     const struct irq_domain_ops *ops)
 {
 	return NULL;
-- 
2.14.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-04-24 14:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-24 14:36 [PATCH 0/7] Partitioned percpu IRQ rework Marc Zyngier
2018-04-24 14:36 ` [PATCH 1/7] genirq/debugfs: Print percpu affinity for percpu_devid interrupts Marc Zyngier
2018-04-24 14:36 ` [PATCH 2/7] genirq/debugfs: Use irq_print_chip method if available Marc Zyngier
2018-04-24 14:36 ` [PATCH 3/7] genirq/debugfs: Allow irq domain name to be overriden Marc Zyngier
2018-04-24 14:36 ` [PATCH 4/7] irqchip/partition-percpu: Override domain name in debugfs Marc Zyngier
2018-04-24 14:36 ` [PATCH 5/7] irqchip/partition-percpu: Refactor backend method calling Marc Zyngier
2018-04-24 14:36 ` [PATCH 6/7] irqchip/partition-percpu: Allow chained_desc to be NULL Marc Zyngier
2018-04-24 14:36 ` [PATCH 7/7] irqchip/partition-percpu: Move allocation of chained interrupt to activate Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).