linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/11] Various IRQ and GIC fixes and clean-ups
@ 2016-05-10 15:14 Jon Hunter
  2016-05-10 15:14 ` [PATCH 01/11] genirq: Ensure IRQ descriptor is valid when setting-up the IRQ Jon Hunter
                   ` (10 more replies)
  0 siblings, 11 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

Most of these patches were originally part of the series to add support
for the Tegra210 AGIC [0]. However, given that series has grown and some
of the changes to the IRQ core needed some more review/testing, per an
offline discussion with Marc Z, I have split out the more trivial fixes
and clean-up patches from the core changes.

[0] http://marc.info/?l=linux-tegra&m=146237957525813&w=2

Jon Hunter (11):
  genirq: Ensure IRQ descriptor is valid when setting-up the IRQ
  irqdomain: Warn if we fail to set the IRQ type
  irqchip: Mask the non-type/sense bits when translating an IRQ
  irqchip/gic: Don't unnecessarily write the IRQ configuration
  irqchip/gic: WARN if setting the interrupt type for a PPI fails
  irqchip/gic: Don't initialise chip if mapping IO space fails
  irqchip/gic: Remove static irq_chip definition for eoimode1
  irqchip/gic: Return an error if GIC initialisation fails
  irqchip/gic: Pass GIC pointer to save/restore functions
  irqchip/gic: Store GIC configuration parameters
  irqchip/gic: Add helper functions for GIC setup and teardown

 drivers/irqchip/irq-crossbar.c   |   2 +-
 drivers/irqchip/irq-gic-common.c |  20 ++-
 drivers/irqchip/irq-gic.c        | 315 +++++++++++++++++++++++++--------------
 drivers/irqchip/irq-tegra.c      |   2 +-
 kernel/irq/irqdomain.c           |   3 +-
 kernel/irq/manage.c              |   2 +-
 6 files changed, 221 insertions(+), 123 deletions(-)

-- 
2.1.4

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

* [PATCH 01/11] genirq: Ensure IRQ descriptor is valid when setting-up the IRQ
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type Jon Hunter
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

In the function, setup_irq(), we don't check that the descriptor
returned from irq_to_desc() is valid before we start using it. For
example chip_bus_lock() called from setup_irq(), assumes that the
descriptor pointer is valid and doesn't check before dereferencing it.

In many other functions including setup/free_percpu_irq() we do check
that the descriptor returned is not NULL and therefore add the same test
to setup_irq() to ensure the descriptor returned is valid.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 kernel/irq/manage.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index cc1cc641d653..ef0bc02c3a70 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1407,7 +1407,7 @@ int setup_irq(unsigned int irq, struct irqaction *act)
 	int retval;
 	struct irq_desc *desc = irq_to_desc(irq);
 
-	if (WARN_ON(irq_settings_is_per_cpu_devid(desc)))
+	if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
 		return -EINVAL;
 	chip_bus_lock(desc);
 	retval = __setup_irq(irq, desc, act);
-- 
2.1.4

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

* [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
  2016-05-10 15:14 ` [PATCH 01/11] genirq: Ensure IRQ descriptor is valid when setting-up the IRQ Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 17:25   ` Marc Zyngier
  2016-05-10 15:14 ` [PATCH 03/11] irqchip: Mask the non-type/sense bits when translating an IRQ Jon Hunter
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

When setting the IRQ type we don't check the return value to see if it
is set correctly. Due to this, failures to set the IRQ type have gone
unnoticed and because these failures were not catastrophic have not had
an impact on the system.

Ideally, we should return an error if we fail to set the type, however,
this could cause non-catastrophic failures to prevent devices from
working. Therefore, for now add a warning so that any bad interrupt
configurations can be corrected.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 kernel/irq/irqdomain.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 8798b6c9e945..09060072cc28 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -610,7 +610,8 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
 	/* Set type if specified and different than the current one */
 	if (type != IRQ_TYPE_NONE &&
 	    type != irq_get_trigger_type(virq))
-		irq_set_irq_type(virq, type);
+		if (irq_set_irq_type(virq, type))
+			pr_warn("failed to set type for irq %d\n", virq);
 	return virq;
 }
 EXPORT_SYMBOL_GPL(irq_create_fwspec_mapping);
-- 
2.1.4

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

* [PATCH 03/11] irqchip: Mask the non-type/sense bits when translating an IRQ
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
  2016-05-10 15:14 ` [PATCH 01/11] genirq: Ensure IRQ descriptor is valid when setting-up the IRQ Jon Hunter
  2016-05-10 15:14 ` [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 04/11] irqchip/gic: Don't unnecessarily write the IRQ configuration Jon Hunter
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

The firmware parameter that contains the IRQ sense bits may also contain
other data. When return the IRQ type, bits outside of these sense bits
should be masked. If these bits are not masked and
irq_create_fwspec_mapping() is called to map an IRQ, then the comparison
of the type returned from irq_domain_translate() will never match
that returned by irq_get_trigger_type() (because this function masks the
none sense bits) and so we will always call irq_set_irq_type() to program
the type even if it was not really necessary.

Currently, the downside to this is unnecessarily re-programmming the type
but nevertheless this should be avoided.

The Tegra LIC and TI Crossbar irqchips all have client instances (from
reviewing the device-tree sources) where bits outside the IRQ sense bits
are set, but do not mask these bits. Therefore, ensure these bits are
masked for these irqchips.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-crossbar.c | 2 +-
 drivers/irqchip/irq-tegra.c    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c
index 75573fa431ba..1eef56a89b1f 100644
--- a/drivers/irqchip/irq-crossbar.c
+++ b/drivers/irqchip/irq-crossbar.c
@@ -183,7 +183,7 @@ static int crossbar_domain_translate(struct irq_domain *d,
 			return -EINVAL;
 
 		*hwirq = fwspec->param[1];
-		*type = fwspec->param[2];
+		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
 		return 0;
 	}
 
diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
index 50be9639e27e..e902f081e16c 100644
--- a/drivers/irqchip/irq-tegra.c
+++ b/drivers/irqchip/irq-tegra.c
@@ -235,7 +235,7 @@ static int tegra_ictlr_domain_translate(struct irq_domain *d,
 			return -EINVAL;
 
 		*hwirq = fwspec->param[1];
-		*type = fwspec->param[2];
+		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
 		return 0;
 	}
 
-- 
2.1.4

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

* [PATCH 04/11] irqchip/gic: Don't unnecessarily write the IRQ configuration
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (2 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 03/11] irqchip: Mask the non-type/sense bits when translating an IRQ Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 05/11] irqchip/gic: WARN if setting the interrupt type for a PPI fails Jon Hunter
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

If the interrupt configuration matches the current configuration, then
don't bother writing the configuration again.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-gic-common.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 2e9443be2b14..eeeefa244933 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -63,13 +63,17 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
 	else if (type & IRQ_TYPE_EDGE_BOTH)
 		val |= confmask;
 
+	/* If the current configuration is the same, then we are done */
+	if (val == oldval)
+		return 0;
+
 	/*
 	 * Write back the new configuration, and possibly re-enable
-	 * the interrupt. If we tried to write a new configuration and failed,
+	 * the interrupt. If we fail to write a new configuration,
 	 * return an error.
 	 */
 	writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
-	if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
+	if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val)
 		ret = -EINVAL;
 
 	if (sync_access)
-- 
2.1.4

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

* [PATCH 05/11] irqchip/gic: WARN if setting the interrupt type for a PPI fails
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (3 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 04/11] irqchip/gic: Don't unnecessarily write the IRQ configuration Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 06/11] irqchip/gic: Don't initialise chip if mapping IO space fails Jon Hunter
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

Setting the interrupt type for private peripheral interrupts (PPIs) may
not be supported by a given GIC because it is IMPLEMENTATION DEFINED
whether this is allowed. There is no way to know if setting the type is
supported for a given GIC and so the value written is read back to
verify it matches the desired configuration. If it does not match then
an error is return.

There are cases where the interrupt configuration read from firmware
(such as a device-tree blob), has been incorrect and hence
gic_configure_irq() has returned an error. This error has gone
undetected because the error code returned was ignored but the interrupt
still worked fine because the configuration for the interrupt could not
be overwritten.

Given that this has done undetected and that failing to set the
configuration for a PPI may not be a catastrophic, don't return an error
but WARN if we fail to configure a PPI. This will allows us to fix up
any places in the kernel where we should be checking the return status
and maintain backward compatibility with firmware images that may have
incorrect PPI configurations.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-gic-common.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index eeeefa244933..89e7423f0ebb 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -69,12 +69,20 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
 
 	/*
 	 * Write back the new configuration, and possibly re-enable
-	 * the interrupt. If we fail to write a new configuration,
-	 * return an error.
+	 * the interrupt. If we fail to write a new configuration for
+	 * an SPI then WARN and return an error. If we fail to write the
+	 * configuration for a PPI this is most likely because the GIC
+	 * does not allow us to set the configuration or we are in a
+	 * non-secure mode, and hence it may not be catastrophic.
 	 */
 	writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
-	if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val)
-		ret = -EINVAL;
+	if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val) {
+		if (WARN_ON(irq >= 32))
+			ret = -EINVAL;
+		else
+			pr_warn("GIC: PPI%d is secure or misconfigured\n",
+				irq - 16);
+	}
 
 	if (sync_access)
 		sync_access();
-- 
2.1.4

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

* [PATCH 06/11] irqchip/gic: Don't initialise chip if mapping IO space fails
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (4 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 05/11] irqchip/gic: WARN if setting the interrupt type for a PPI fails Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 07/11] irqchip/gic: Remove static irq_chip definition for eoimode1 Jon Hunter
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

If we fail to map the address space for the GIC distributor or CPU
interface, then don't attempt to initialise the chip, just WARN and
return.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-gic.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 30d05a4639e4..070c87bbfce8 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1225,10 +1225,14 @@ gic_of_init(struct device_node *node, struct device_node *parent)
 		return -ENODEV;
 
 	dist_base = of_iomap(node, 0);
-	WARN(!dist_base, "unable to map gic dist registers\n");
+	if (WARN(!dist_base, "unable to map gic dist registers\n"))
+		return -ENOMEM;
 
 	cpu_base = of_iomap(node, 1);
-	WARN(!cpu_base, "unable to map gic cpu registers\n");
+	if (WARN(!cpu_base, "unable to map gic cpu registers\n")) {
+		iounmap(dist_base);
+		return -ENOMEM;
+	}
 
 	/*
 	 * Disable split EOI/Deactivate if either HYP is not available
-- 
2.1.4

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

* [PATCH 07/11] irqchip/gic: Remove static irq_chip definition for eoimode1
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (5 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 06/11] irqchip/gic: Don't initialise chip if mapping IO space fails Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 08/11] irqchip/gic: Return an error if GIC initialisation fails Jon Hunter
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

There are only 3 differences (not including the name) in the definitions
of the gic_chip and gic_eoimode1_chip structures. Instead of statically
defining the gic_eoimode1_chip structure, remove it and populate the
eoimode1 functions dynamically for the appropriate GIC irqchips.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-gic.c | 22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 070c87bbfce8..d84fa36a7932 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -393,20 +393,6 @@ static struct irq_chip gic_chip = {
 				  IRQCHIP_MASK_ON_SUSPEND,
 };
 
-static struct irq_chip gic_eoimode1_chip = {
-	.name			= "GICv2",
-	.irq_mask		= gic_eoimode1_mask_irq,
-	.irq_unmask		= gic_unmask_irq,
-	.irq_eoi		= gic_eoimode1_eoi_irq,
-	.irq_set_type		= gic_set_type,
-	.irq_get_irqchip_state	= gic_irq_get_irqchip_state,
-	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,
-	.irq_set_vcpu_affinity	= gic_irq_set_vcpu_affinity,
-	.flags			= IRQCHIP_SET_TYPE_MASKED |
-				  IRQCHIP_SKIP_SET_WAKE |
-				  IRQCHIP_MASK_ON_SUSPEND,
-};
-
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
 	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
@@ -1027,10 +1013,14 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 	gic = &gic_data[gic_nr];
 
 	/* Initialize irq_chip */
+	gic->chip = gic_chip;
+
 	if (static_key_true(&supports_deactivate) && gic_nr == 0) {
-		gic->chip = gic_eoimode1_chip;
+		gic->chip.irq_mask = gic_eoimode1_mask_irq;
+		gic->chip.irq_eoi = gic_eoimode1_eoi_irq;
+		gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity;
+		gic->chip.name = "GICv2";
 	} else {
-		gic->chip = gic_chip;
 		gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
 	}
 
-- 
2.1.4

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

* [PATCH 08/11] irqchip/gic: Return an error if GIC initialisation fails
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (6 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 07/11] irqchip/gic: Remove static irq_chip definition for eoimode1 Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 09/11] irqchip/gic: Pass GIC pointer to save/restore functions Jon Hunter
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

If the GIC initialisation fails, then currently we do not return an error
or clean-up afterwards. Although for root controllers, this failure may be
fatal anyway, for secondary controllers, it may not be fatal and so return
an error on failure and clean-up.

Update the functions gic_cpu_init() and gic_pm_init() to return an error
instead of calling BUG() and perform any necessary clean-up.

For non-banked GIC controllers, make sure that we free any memory
allocated if we fail to initialise the IRQ domain. Please note that
free_percpu() only frees memory if the pointer passed to it is not NULL
and so it is unnecessary to check if both pointers are valid or not.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 99 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 73 insertions(+), 26 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d84fa36a7932..f32897c587b8 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -461,7 +461,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 	writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL);
 }
 
-static void gic_cpu_init(struct gic_chip_data *gic)
+static int gic_cpu_init(struct gic_chip_data *gic)
 {
 	void __iomem *dist_base = gic_data_dist_base(gic);
 	void __iomem *base = gic_data_cpu_base(gic);
@@ -477,7 +477,9 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 		/*
 		 * Get what the GIC says our CPU mask is.
 		 */
-		BUG_ON(cpu >= NR_GIC_CPU_IF);
+		if (WARN_ON(cpu >= NR_GIC_CPU_IF))
+			return -EINVAL;
+
 		gic_check_cpu_features();
 		cpu_mask = gic_get_cpumask(gic);
 		gic_cpu_map[cpu] = cpu_mask;
@@ -495,6 +497,8 @@ static void gic_cpu_init(struct gic_chip_data *gic)
 
 	writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
 	gic_cpu_if_up(gic);
+
+	return 0;
 }
 
 int gic_cpu_if_down(unsigned int gic_nr)
@@ -708,26 +712,39 @@ static struct notifier_block gic_notifier_block = {
 	.notifier_call = gic_notifier,
 };
 
-static void __init gic_pm_init(struct gic_chip_data *gic)
+static int __init gic_pm_init(struct gic_chip_data *gic)
 {
 	gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
 		sizeof(u32));
-	BUG_ON(!gic->saved_ppi_enable);
+	if (WARN_ON(!gic->saved_ppi_enable))
+		return -ENOMEM;
 
 	gic->saved_ppi_active = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
 		sizeof(u32));
-	BUG_ON(!gic->saved_ppi_active);
+	if (WARN_ON(!gic->saved_ppi_active))
+		goto free_ppi_enable;
 
 	gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
 		sizeof(u32));
-	BUG_ON(!gic->saved_ppi_conf);
+	if (WARN_ON(!gic->saved_ppi_conf))
+		goto free_ppi_active;
 
 	if (gic == &gic_data[0])
 		cpu_pm_register_notifier(&gic_notifier_block);
+
+	return 0;
+
+free_ppi_active:
+	free_percpu(gic->saved_ppi_active);
+free_ppi_enable:
+	free_percpu(gic->saved_ppi_enable);
+
+	return -ENOMEM;
 }
 #else
-static void __init gic_pm_init(struct gic_chip_data *gic)
+static int __init gic_pm_init(struct gic_chip_data *gic)
 {
+	return 0;
 }
 #endif
 
@@ -1000,13 +1017,13 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
 	.unmap = gic_irq_domain_unmap,
 };
 
-static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
+static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 			   void __iomem *dist_base, void __iomem *cpu_base,
 			   u32 percpu_offset, struct fwnode_handle *handle)
 {
 	irq_hw_number_t hwirq_base;
 	struct gic_chip_data *gic;
-	int gic_irqs, irq_base, i;
+	int gic_irqs, irq_base, i, ret;
 
 	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
 
@@ -1019,7 +1036,7 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 		gic->chip.irq_mask = gic_eoimode1_mask_irq;
 		gic->chip.irq_eoi = gic_eoimode1_eoi_irq;
 		gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity;
-		gic->chip.name = "GICv2";
+		gic->chip.name = kasprintf(GFP_KERNEL, "GICv2");
 	} else {
 		gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
 	}
@@ -1029,17 +1046,16 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 		gic->chip.irq_set_affinity = gic_set_affinity;
 #endif
 
-#ifdef CONFIG_GIC_NON_BANKED
-	if (percpu_offset) { /* Frankein-GIC without banked registers... */
+	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) {
+		/* Frankein-GIC without banked registers... */
 		unsigned int cpu;
 
 		gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
 		gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
 		if (WARN_ON(!gic->dist_base.percpu_base ||
 			    !gic->cpu_base.percpu_base)) {
-			free_percpu(gic->dist_base.percpu_base);
-			free_percpu(gic->cpu_base.percpu_base);
-			return;
+			ret = -ENOMEM;
+			goto error;
 		}
 
 		for_each_possible_cpu(cpu) {
@@ -1051,9 +1067,8 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 		}
 
 		gic_set_base_accessor(gic, gic_get_percpu_base);
-	} else
-#endif
-	{			/* Normal, sane GIC... */
+	} else {
+		/* Normal, sane GIC... */
 		WARN(percpu_offset,
 		     "GIC_NON_BANKED not enabled, ignoring %08x offset!",
 		     percpu_offset);
@@ -1103,8 +1118,10 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 					hwirq_base, &gic_irq_domain_ops, gic);
 	}
 
-	if (WARN_ON(!gic->domain))
-		return;
+	if (WARN_ON(!gic->domain)) {
+		ret = -ENODEV;
+		goto error;
+	}
 
 	if (gic_nr == 0) {
 		/*
@@ -1124,8 +1141,25 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 	}
 
 	gic_dist_init(gic);
-	gic_cpu_init(gic);
-	gic_pm_init(gic);
+	ret = gic_cpu_init(gic);
+	if (ret)
+		goto error;
+
+	ret = gic_pm_init(gic);
+	if (ret)
+		goto error;
+
+	return 0;
+
+error:
+	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) {
+		free_percpu(gic->dist_base.percpu_base);
+		free_percpu(gic->cpu_base.percpu_base);
+	}
+
+	kfree(gic->chip.name);
+
+	return ret;
 }
 
 void __init gic_init(unsigned int gic_nr, int irq_start,
@@ -1209,7 +1243,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
 	void __iomem *cpu_base;
 	void __iomem *dist_base;
 	u32 percpu_offset;
-	int irq;
+	int irq, ret;
 
 	if (WARN_ON(!node))
 		return -ENODEV;
@@ -1234,8 +1268,14 @@ gic_of_init(struct device_node *node, struct device_node *parent)
 	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
 		percpu_offset = 0;
 
-	__gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset,
+	ret = __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset,
 			 &node->fwnode);
+	if (ret) {
+		iounmap(dist_base);
+		iounmap(cpu_base);
+		return ret;
+	}
+
 	if (!gic_cnt) {
 		gic_init_physaddr(node);
 		gic_of_setup_kvm_info(node);
@@ -1374,7 +1414,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 	struct acpi_madt_generic_distributor *dist;
 	void __iomem *cpu_base, *dist_base;
 	struct fwnode_handle *domain_handle;
-	int count;
+	int count, ret;
 
 	/* Collect CPU base addresses */
 	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
@@ -1417,7 +1457,14 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 		return -ENOMEM;
 	}
 
-	__gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
+	ret = __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
+	if (ret) {
+		pr_err("Failed to initialise GIC\n");
+		irq_domain_free_fwnode(domain_handle);
+		iounmap(cpu_base);
+		iounmap(dist_base);
+		return ret;
+	}
 
 	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
 
-- 
2.1.4

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

* [PATCH 09/11] irqchip/gic: Pass GIC pointer to save/restore functions
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (7 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 08/11] irqchip/gic: Return an error if GIC initialisation fails Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 10/11] irqchip/gic: Store GIC configuration parameters Jon Hunter
  2016-05-10 15:14 ` [PATCH 11/11] irqchip/gic: Add helper functions for GIC setup and teardown Jon Hunter
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

Instead of passing the GIC index to the save/restore functions pass a
pointer to the GIC chip data. This will allow these save/restore
functions to be re-used by a platform driver where the GIC chip data
structure is allocated dynamically and so there is no applicable index
for identifying the GIC.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-gic.c | 74 +++++++++++++++++++++++++----------------------
 1 file changed, 39 insertions(+), 35 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index f32897c587b8..93a84acd6a03 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -524,34 +524,35 @@ int gic_cpu_if_down(unsigned int gic_nr)
  * this function, no interrupts will be delivered by the GIC, and another
  * platform-specific wakeup source must be enabled.
  */
-static void gic_dist_save(unsigned int gic_nr)
+static void gic_dist_save(struct gic_chip_data *gic)
 {
 	unsigned int gic_irqs;
 	void __iomem *dist_base;
 	int i;
 
-	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+	if (WARN_ON(!gic))
+		return;
 
-	gic_irqs = gic_data[gic_nr].gic_irqs;
-	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+	gic_irqs = gic->gic_irqs;
+	dist_base = gic_data_dist_base(gic);
 
 	if (!dist_base)
 		return;
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
-		gic_data[gic_nr].saved_spi_conf[i] =
+		gic->saved_spi_conf[i] =
 			readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
-		gic_data[gic_nr].saved_spi_target[i] =
+		gic->saved_spi_target[i] =
 			readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
-		gic_data[gic_nr].saved_spi_enable[i] =
+		gic->saved_spi_enable[i] =
 			readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
-		gic_data[gic_nr].saved_spi_active[i] =
+		gic->saved_spi_active[i] =
 			readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
 }
 
@@ -562,16 +563,17 @@ static void gic_dist_save(unsigned int gic_nr)
  * handled normally, but any edge interrupts that occured will not be seen by
  * the GIC and need to be handled by the platform-specific wakeup source.
  */
-static void gic_dist_restore(unsigned int gic_nr)
+static void gic_dist_restore(struct gic_chip_data *gic)
 {
 	unsigned int gic_irqs;
 	unsigned int i;
 	void __iomem *dist_base;
 
-	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+	if (WARN_ON(!gic))
+		return;
 
-	gic_irqs = gic_data[gic_nr].gic_irqs;
-	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+	gic_irqs = gic->gic_irqs;
+	dist_base = gic_data_dist_base(gic);
 
 	if (!dist_base)
 		return;
@@ -579,7 +581,7 @@ static void gic_dist_restore(unsigned int gic_nr)
 	writel_relaxed(GICD_DISABLE, dist_base + GIC_DIST_CTRL);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
-		writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
+		writel_relaxed(gic->saved_spi_conf[i],
 			dist_base + GIC_DIST_CONFIG + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
@@ -587,85 +589,87 @@ static void gic_dist_restore(unsigned int gic_nr)
 			dist_base + GIC_DIST_PRI + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
-		writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
+		writel_relaxed(gic->saved_spi_target[i],
 			dist_base + GIC_DIST_TARGET + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
 		writel_relaxed(GICD_INT_EN_CLR_X32,
 			dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
-		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
+		writel_relaxed(gic->saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 	}
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
 		writel_relaxed(GICD_INT_EN_CLR_X32,
 			dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
-		writel_relaxed(gic_data[gic_nr].saved_spi_active[i],
+		writel_relaxed(gic->saved_spi_active[i],
 			dist_base + GIC_DIST_ACTIVE_SET + i * 4);
 	}
 
 	writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL);
 }
 
-static void gic_cpu_save(unsigned int gic_nr)
+static void gic_cpu_save(struct gic_chip_data *gic)
 {
 	int i;
 	u32 *ptr;
 	void __iomem *dist_base;
 	void __iomem *cpu_base;
 
-	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+	if (WARN_ON(!gic))
+		return;
 
-	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
-	cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
+	dist_base = gic_data_dist_base(gic);
+	cpu_base = gic_data_cpu_base(gic);
 
 	if (!dist_base || !cpu_base)
 		return;
 
-	ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+	ptr = raw_cpu_ptr(gic->saved_ppi_enable);
 	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
 		ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+	ptr = raw_cpu_ptr(gic->saved_ppi_active);
 	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
 		ptr[i] = readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
 
-	ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+	ptr = raw_cpu_ptr(gic->saved_ppi_conf);
 	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
 		ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
 
 }
 
-static void gic_cpu_restore(unsigned int gic_nr)
+static void gic_cpu_restore(struct gic_chip_data *gic)
 {
 	int i;
 	u32 *ptr;
 	void __iomem *dist_base;
 	void __iomem *cpu_base;
 
-	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+	if (WARN_ON(!gic))
+		return;
 
-	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
-	cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
+	dist_base = gic_data_dist_base(gic);
+	cpu_base = gic_data_cpu_base(gic);
 
 	if (!dist_base || !cpu_base)
 		return;
 
-	ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+	ptr = raw_cpu_ptr(gic->saved_ppi_enable);
 	for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
 		writel_relaxed(GICD_INT_EN_CLR_X32,
 			       dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
 		writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
 	}
 
-	ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+	ptr = raw_cpu_ptr(gic->saved_ppi_active);
 	for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
 		writel_relaxed(GICD_INT_EN_CLR_X32,
 			       dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
 		writel_relaxed(ptr[i], dist_base + GIC_DIST_ACTIVE_SET + i * 4);
 	}
 
-	ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+	ptr = raw_cpu_ptr(gic->saved_ppi_conf);
 	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
 		writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
 
@@ -674,7 +678,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
 					dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
-	gic_cpu_if_up(&gic_data[gic_nr]);
+	gic_cpu_if_up(gic);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -689,18 +693,18 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
 #endif
 		switch (cmd) {
 		case CPU_PM_ENTER:
-			gic_cpu_save(i);
+			gic_cpu_save(&gic_data[i]);
 			break;
 		case CPU_PM_ENTER_FAILED:
 		case CPU_PM_EXIT:
-			gic_cpu_restore(i);
+			gic_cpu_restore(&gic_data[i]);
 			break;
 		case CPU_CLUSTER_PM_ENTER:
-			gic_dist_save(i);
+			gic_dist_save(&gic_data[i]);
 			break;
 		case CPU_CLUSTER_PM_ENTER_FAILED:
 		case CPU_CLUSTER_PM_EXIT:
-			gic_dist_restore(i);
+			gic_dist_restore(&gic_data[i]);
 			break;
 		}
 	}
-- 
2.1.4

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

* [PATCH 10/11] irqchip/gic: Store GIC configuration parameters
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (8 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 09/11] irqchip/gic: Pass GIC pointer to save/restore functions Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  2016-05-10 15:14 ` [PATCH 11/11] irqchip/gic: Add helper functions for GIC setup and teardown Jon Hunter
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

Store the GIC configuration parameters in the GIC chip data structure.
This will allow us to simplify the code by reducing the number of
parameters passed between functions.

Update the __gic_init_bases() function so that we only need to pass a
pointer to the GIC chip data structure and no longer need to pass the
GIC index in order to look-up the chip data.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 115 ++++++++++++++++++++++++++--------------------
 1 file changed, 66 insertions(+), 49 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 93a84acd6a03..435ff2e1795a 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -72,6 +72,9 @@ struct gic_chip_data {
 	struct irq_chip chip;
 	union gic_base dist_base;
 	union gic_base cpu_base;
+	void __iomem *raw_dist_base;
+	void __iomem *raw_cpu_base;
+	u32 percpu_offset;
 #ifdef CONFIG_CPU_PM
 	u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
 	u32 saved_spi_active[DIV_ROUND_UP(1020, 32)];
@@ -1021,36 +1024,34 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
 	.unmap = gic_irq_domain_unmap,
 };
 
-static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
-			   void __iomem *dist_base, void __iomem *cpu_base,
-			   u32 percpu_offset, struct fwnode_handle *handle)
+static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start,
+				   struct fwnode_handle *handle)
 {
 	irq_hw_number_t hwirq_base;
-	struct gic_chip_data *gic;
 	int gic_irqs, irq_base, i, ret;
 
-	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
-
-	gic = &gic_data[gic_nr];
+	if (WARN_ON(!gic || gic->domain))
+		return -EINVAL;
 
 	/* Initialize irq_chip */
 	gic->chip = gic_chip;
 
-	if (static_key_true(&supports_deactivate) && gic_nr == 0) {
+	if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) {
 		gic->chip.irq_mask = gic_eoimode1_mask_irq;
 		gic->chip.irq_eoi = gic_eoimode1_eoi_irq;
 		gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity;
 		gic->chip.name = kasprintf(GFP_KERNEL, "GICv2");
 	} else {
-		gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
+		gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d",
+					   (int)(gic - &gic_data[0]));
 	}
 
 #ifdef CONFIG_SMP
-	if (gic_nr == 0)
+	if (gic == &gic_data[0])
 		gic->chip.irq_set_affinity = gic_set_affinity;
 #endif
 
-	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) {
+	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) {
 		/* Frankein-GIC without banked registers... */
 		unsigned int cpu;
 
@@ -1065,19 +1066,21 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 		for_each_possible_cpu(cpu) {
 			u32 mpidr = cpu_logical_map(cpu);
 			u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-			unsigned long offset = percpu_offset * core_id;
-			*per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
-			*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
+			unsigned long offset = gic->percpu_offset * core_id;
+			*per_cpu_ptr(gic->dist_base.percpu_base, cpu) =
+				gic->raw_dist_base + offset;
+			*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) =
+				gic->raw_cpu_base + offset;
 		}
 
 		gic_set_base_accessor(gic, gic_get_percpu_base);
 	} else {
 		/* Normal, sane GIC... */
-		WARN(percpu_offset,
+		WARN(gic->percpu_offset,
 		     "GIC_NON_BANKED not enabled, ignoring %08x offset!",
-		     percpu_offset);
-		gic->dist_base.common_base = dist_base;
-		gic->cpu_base.common_base = cpu_base;
+		     gic->percpu_offset);
+		gic->dist_base.common_base = gic->raw_dist_base;
+		gic->cpu_base.common_base = gic->raw_cpu_base;
 		gic_set_base_accessor(gic, gic_get_common_base);
 	}
 
@@ -1100,7 +1103,7 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 		 * For primary GICs, skip over SGIs.
 		 * For secondary GICs, skip over PPIs, too.
 		 */
-		if (gic_nr == 0 && (irq_start & 31) > 0) {
+		if (gic == &gic_data[0] && (irq_start & 31) > 0) {
 			hwirq_base = 16;
 			if (irq_start != -1)
 				irq_start = (irq_start & ~31) + 16;
@@ -1127,7 +1130,7 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 		goto error;
 	}
 
-	if (gic_nr == 0) {
+	if (gic == &gic_data[0]) {
 		/*
 		 * Initialize the CPU interface map to all CPUs.
 		 * It will be refined as each CPU probes its ID.
@@ -1156,7 +1159,7 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 	return 0;
 
 error:
-	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) {
+	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) {
 		free_percpu(gic->dist_base.percpu_base);
 		free_percpu(gic->cpu_base.percpu_base);
 	}
@@ -1169,12 +1172,22 @@ error:
 void __init gic_init(unsigned int gic_nr, int irq_start,
 		     void __iomem *dist_base, void __iomem *cpu_base)
 {
+	struct gic_chip_data *gic;
+
+	if (WARN_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR))
+		return;
+
 	/*
 	 * Non-DT/ACPI systems won't run a hypervisor, so let's not
 	 * bother with these...
 	 */
 	static_key_slow_dec(&supports_deactivate);
-	__gic_init_bases(gic_nr, irq_start, dist_base, cpu_base, 0, NULL);
+
+	gic = &gic_data[gic_nr];
+	gic->raw_dist_base = dist_base;
+	gic->raw_cpu_base = cpu_base;
+
+	__gic_init_bases(gic, irq_start, NULL);
 }
 
 #ifdef CONFIG_OF
@@ -1244,21 +1257,24 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
 int __init
 gic_of_init(struct device_node *node, struct device_node *parent)
 {
-	void __iomem *cpu_base;
-	void __iomem *dist_base;
-	u32 percpu_offset;
+	struct gic_chip_data *gic;
 	int irq, ret;
 
 	if (WARN_ON(!node))
 		return -ENODEV;
 
-	dist_base = of_iomap(node, 0);
-	if (WARN(!dist_base, "unable to map gic dist registers\n"))
+	if (WARN_ON(gic_cnt >= CONFIG_ARM_GIC_MAX_NR))
+		return -EINVAL;
+
+	gic = &gic_data[gic_cnt];
+
+	gic->raw_dist_base = of_iomap(node, 0);
+	if (WARN(!gic->raw_dist_base, "unable to map gic dist registers\n"))
 		return -ENOMEM;
 
-	cpu_base = of_iomap(node, 1);
-	if (WARN(!cpu_base, "unable to map gic cpu registers\n")) {
-		iounmap(dist_base);
+	gic->raw_cpu_base = of_iomap(node, 1);
+	if (WARN(!gic->raw_cpu_base, "unable to map gic cpu registers\n")) {
+		iounmap(gic->raw_dist_base);
 		return -ENOMEM;
 	}
 
@@ -1266,17 +1282,16 @@ gic_of_init(struct device_node *node, struct device_node *parent)
 	 * Disable split EOI/Deactivate if either HYP is not available
 	 * or the CPU interface is too small.
 	 */
-	if (gic_cnt == 0 && !gic_check_eoimode(node, &cpu_base))
+	if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base))
 		static_key_slow_dec(&supports_deactivate);
 
-	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
-		percpu_offset = 0;
+	if (of_property_read_u32(node, "cpu-offset", &gic->percpu_offset))
+		gic->percpu_offset = 0;
 
-	ret = __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset,
-			 &node->fwnode);
+	ret = __gic_init_bases(gic, -1, &node->fwnode);
 	if (ret) {
-		iounmap(dist_base);
-		iounmap(cpu_base);
+		iounmap(gic->raw_dist_base);
+		iounmap(gic->raw_cpu_base);
 		return ret;
 	}
 
@@ -1416,8 +1431,8 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 				   const unsigned long end)
 {
 	struct acpi_madt_generic_distributor *dist;
-	void __iomem *cpu_base, *dist_base;
 	struct fwnode_handle *domain_handle;
+	struct gic_chip_data *gic = &gic_data[0];
 	int count, ret;
 
 	/* Collect CPU base addresses */
@@ -1428,17 +1443,19 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 		return -EINVAL;
 	}
 
-	cpu_base = ioremap(acpi_data.cpu_phys_base, ACPI_GIC_CPU_IF_MEM_SIZE);
-	if (!cpu_base) {
+	gic->raw_cpu_base = ioremap(acpi_data.cpu_phys_base,
+				    ACPI_GIC_CPU_IF_MEM_SIZE);
+	if (!gic->raw_cpu_base) {
 		pr_err("Unable to map GICC registers\n");
 		return -ENOMEM;
 	}
 
 	dist = (struct acpi_madt_generic_distributor *)header;
-	dist_base = ioremap(dist->base_address, ACPI_GICV2_DIST_MEM_SIZE);
-	if (!dist_base) {
+	gic->raw_dist_base = ioremap(dist->base_address,
+				     ACPI_GICV2_DIST_MEM_SIZE);
+	if (!gic->raw_dist_base) {
 		pr_err("Unable to map GICD registers\n");
-		iounmap(cpu_base);
+		iounmap(gic->raw_cpu_base);
 		return -ENOMEM;
 	}
 
@@ -1453,20 +1470,20 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 	/*
 	 * Initialize GIC instance zero (no multi-GIC support).
 	 */
-	domain_handle = irq_domain_alloc_fwnode(dist_base);
+	domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base);
 	if (!domain_handle) {
 		pr_err("Unable to allocate domain handle\n");
-		iounmap(cpu_base);
-		iounmap(dist_base);
+		iounmap(gic->raw_cpu_base);
+		iounmap(gic->raw_dist_base);
 		return -ENOMEM;
 	}
 
-	ret = __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
+	ret = __gic_init_bases(gic, -1, domain_handle);
 	if (ret) {
 		pr_err("Failed to initialise GIC\n");
 		irq_domain_free_fwnode(domain_handle);
-		iounmap(cpu_base);
-		iounmap(dist_base);
+		iounmap(gic->raw_cpu_base);
+		iounmap(gic->raw_dist_base);
 		return ret;
 	}
 
-- 
2.1.4

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

* [PATCH 11/11] irqchip/gic: Add helper functions for GIC setup and teardown
  2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
                   ` (9 preceding siblings ...)
  2016-05-10 15:14 ` [PATCH 10/11] irqchip/gic: Store GIC configuration parameters Jon Hunter
@ 2016-05-10 15:14 ` Jon Hunter
  10 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 15:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra, Jon Hunter

Move the code that sets-up a GIC via device-tree into it's own
function and add a generic function for GIC teardown that can be used
for both device-tree and ACPI to unmap the GIC memory.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
 drivers/irqchip/irq-gic.c | 61 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 42 insertions(+), 19 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 435ff2e1795a..9aec6db6ebe5 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1190,6 +1190,17 @@ void __init gic_init(unsigned int gic_nr, int irq_start,
 	__gic_init_bases(gic, irq_start, NULL);
 }
 
+static void gic_teardown(struct gic_chip_data *gic)
+{
+	if (WARN_ON(!gic))
+		return;
+
+	if (gic->raw_dist_base)
+		iounmap(gic->raw_dist_base);
+	if (gic->raw_cpu_base)
+		iounmap(gic->raw_cpu_base);
+}
+
 #ifdef CONFIG_OF
 static int gic_cnt __initdata;
 
@@ -1231,6 +1242,30 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
 	return true;
 }
 
+static int gic_of_setup(struct gic_chip_data *gic, struct device_node *node)
+{
+	if (!gic || !node)
+		return -EINVAL;
+
+	gic->raw_dist_base = of_iomap(node, 0);
+	if (WARN(!gic->raw_dist_base, "unable to map gic dist registers\n"))
+		goto error;
+
+	gic->raw_cpu_base = of_iomap(node, 1);
+	if (WARN(!gic->raw_cpu_base, "unable to map gic cpu registers\n"))
+		goto error;
+
+	if (of_property_read_u32(node, "cpu-offset", &gic->percpu_offset))
+		gic->percpu_offset = 0;
+
+	return 0;
+
+error:
+	gic_teardown(gic);
+
+	return -ENOMEM;
+}
+
 static void __init gic_of_setup_kvm_info(struct device_node *node)
 {
 	int ret;
@@ -1268,15 +1303,9 @@ gic_of_init(struct device_node *node, struct device_node *parent)
 
 	gic = &gic_data[gic_cnt];
 
-	gic->raw_dist_base = of_iomap(node, 0);
-	if (WARN(!gic->raw_dist_base, "unable to map gic dist registers\n"))
-		return -ENOMEM;
-
-	gic->raw_cpu_base = of_iomap(node, 1);
-	if (WARN(!gic->raw_cpu_base, "unable to map gic cpu registers\n")) {
-		iounmap(gic->raw_dist_base);
-		return -ENOMEM;
-	}
+	ret = gic_of_setup(gic, node);
+	if (ret)
+		return ret;
 
 	/*
 	 * Disable split EOI/Deactivate if either HYP is not available
@@ -1285,13 +1314,9 @@ gic_of_init(struct device_node *node, struct device_node *parent)
 	if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base))
 		static_key_slow_dec(&supports_deactivate);
 
-	if (of_property_read_u32(node, "cpu-offset", &gic->percpu_offset))
-		gic->percpu_offset = 0;
-
 	ret = __gic_init_bases(gic, -1, &node->fwnode);
 	if (ret) {
-		iounmap(gic->raw_dist_base);
-		iounmap(gic->raw_cpu_base);
+		gic_teardown(gic);
 		return ret;
 	}
 
@@ -1455,7 +1480,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 				     ACPI_GICV2_DIST_MEM_SIZE);
 	if (!gic->raw_dist_base) {
 		pr_err("Unable to map GICD registers\n");
-		iounmap(gic->raw_cpu_base);
+		gic_teardown(gic);
 		return -ENOMEM;
 	}
 
@@ -1473,8 +1498,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 	domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base);
 	if (!domain_handle) {
 		pr_err("Unable to allocate domain handle\n");
-		iounmap(gic->raw_cpu_base);
-		iounmap(gic->raw_dist_base);
+		gic_teardown(gic);
 		return -ENOMEM;
 	}
 
@@ -1482,8 +1506,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
 	if (ret) {
 		pr_err("Failed to initialise GIC\n");
 		irq_domain_free_fwnode(domain_handle);
-		iounmap(gic->raw_cpu_base);
-		iounmap(gic->raw_dist_base);
+		gic_teardown(gic);
 		return ret;
 	}
 
-- 
2.1.4

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

* Re: [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type
  2016-05-10 15:14 ` [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type Jon Hunter
@ 2016-05-10 17:25   ` Marc Zyngier
  2016-05-10 18:00     ` Jon Hunter
  0 siblings, 1 reply; 15+ messages in thread
From: Marc Zyngier @ 2016-05-10 17:25 UTC (permalink / raw)
  To: Jon Hunter; +Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra

On 10/05/16 16:14, Jon Hunter wrote:
> When setting the IRQ type we don't check the return value to see if it
> is set correctly. Due to this, failures to set the IRQ type have gone
> unnoticed and because these failures were not catastrophic have not had
> an impact on the system.
> 
> Ideally, we should return an error if we fail to set the type, however,
> this could cause non-catastrophic failures to prevent devices from
> working. Therefore, for now add a warning so that any bad interrupt
> configurations can be corrected.
> 
> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
> ---
>  kernel/irq/irqdomain.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
> index 8798b6c9e945..09060072cc28 100644
> --- a/kernel/irq/irqdomain.c
> +++ b/kernel/irq/irqdomain.c
> @@ -610,7 +610,8 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
>  	/* Set type if specified and different than the current one */
>  	if (type != IRQ_TYPE_NONE &&
>  	    type != irq_get_trigger_type(virq))
> -		irq_set_irq_type(virq, type);
> +		if (irq_set_irq_type(virq, type))
> +			pr_warn("failed to set type for irq %d\n", virq);

This warning triggers on all per-cpu interrupts, because
irq_set_irq_type() uses IRQ_GET_DESC_CHECK_GLOBAL and not
IRQ_GET_DESC_CHECK_PERCPU. Which sort of makes sense because the trigger
is per-cpu and not global. We'd need some similar check in
enable_percpu_irq, but at that stage, we've already lost the context
coming from the firmware.

Which only proves one thing: per-cpu interrupts have never been
configured on the allocation path, and we've been living pretty
dangerously so far. They do work (at least on ARM) because of the
following reasons:

1) the triggers are already configured (firmware, read-only...)
2) the handle_percpu_devid_irq handler doesn't distinguish between flows

It is probably broken on all other architectures, which kind of sucks.
At this point, I'm really tempted to drop this patch and to aim towards
something similar to what you had in patches 5 and 6 in your previous
series. I'll have a think tonight.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type
  2016-05-10 17:25   ` Marc Zyngier
@ 2016-05-10 18:00     ` Jon Hunter
  2016-05-10 18:06       ` Jon Hunter
  0 siblings, 1 reply; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 18:00 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra


On 10/05/16 18:25, Marc Zyngier wrote:
> On 10/05/16 16:14, Jon Hunter wrote:
>> When setting the IRQ type we don't check the return value to see if it
>> is set correctly. Due to this, failures to set the IRQ type have gone
>> unnoticed and because these failures were not catastrophic have not had
>> an impact on the system.
>>
>> Ideally, we should return an error if we fail to set the type, however,
>> this could cause non-catastrophic failures to prevent devices from
>> working. Therefore, for now add a warning so that any bad interrupt
>> configurations can be corrected.
>>
>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>> ---
>>  kernel/irq/irqdomain.c | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
>> index 8798b6c9e945..09060072cc28 100644
>> --- a/kernel/irq/irqdomain.c
>> +++ b/kernel/irq/irqdomain.c
>> @@ -610,7 +610,8 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
>>  	/* Set type if specified and different than the current one */
>>  	if (type != IRQ_TYPE_NONE &&
>>  	    type != irq_get_trigger_type(virq))
>> -		irq_set_irq_type(virq, type);
>> +		if (irq_set_irq_type(virq, type))
>> +			pr_warn("failed to set type for irq %d\n", virq);
> 
> This warning triggers on all per-cpu interrupts, because
> irq_set_irq_type() uses IRQ_GET_DESC_CHECK_GLOBAL and not
> IRQ_GET_DESC_CHECK_PERCPU. Which sort of makes sense because the trigger
> is per-cpu and not global. We'd need some similar check in
> enable_percpu_irq, but at that stage, we've already lost the context
> coming from the firmware.
> 
> Which only proves one thing: per-cpu interrupts have never been
> configured on the allocation path, and we've been living pretty
> dangerously so far. They do work (at least on ARM) because of the
> following reasons:
> 
> 1) the triggers are already configured (firmware, read-only...)
> 2) the handle_percpu_devid_irq handler doesn't distinguish between flows
> 
> It is probably broken on all other architectures, which kind of sucks.
> At this point, I'm really tempted to drop this patch and to aim towards
> something similar to what you had in patches 5 and 6 in your previous
> series. I'll have a think tonight.

OK. I will hold off on posting the other patches for the minute.

Cheers
Jon

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

* Re: [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type
  2016-05-10 18:00     ` Jon Hunter
@ 2016-05-10 18:06       ` Jon Hunter
  0 siblings, 0 replies; 15+ messages in thread
From: Jon Hunter @ 2016-05-10 18:06 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Thomas Gleixner, Jason Cooper, linux-kernel, linux-tegra


On 10/05/16 19:00, Jon Hunter wrote:
> 
> On 10/05/16 18:25, Marc Zyngier wrote:
>> On 10/05/16 16:14, Jon Hunter wrote:
>>> When setting the IRQ type we don't check the return value to see if it
>>> is set correctly. Due to this, failures to set the IRQ type have gone
>>> unnoticed and because these failures were not catastrophic have not had
>>> an impact on the system.
>>>
>>> Ideally, we should return an error if we fail to set the type, however,
>>> this could cause non-catastrophic failures to prevent devices from
>>> working. Therefore, for now add a warning so that any bad interrupt
>>> configurations can be corrected.
>>>
>>> Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
>>> ---
>>>  kernel/irq/irqdomain.c | 3 ++-
>>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
>>> index 8798b6c9e945..09060072cc28 100644
>>> --- a/kernel/irq/irqdomain.c
>>> +++ b/kernel/irq/irqdomain.c
>>> @@ -610,7 +610,8 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
>>>  	/* Set type if specified and different than the current one */
>>>  	if (type != IRQ_TYPE_NONE &&
>>>  	    type != irq_get_trigger_type(virq))
>>> -		irq_set_irq_type(virq, type);
>>> +		if (irq_set_irq_type(virq, type))
>>> +			pr_warn("failed to set type for irq %d\n", virq);
>>
>> This warning triggers on all per-cpu interrupts, because
>> irq_set_irq_type() uses IRQ_GET_DESC_CHECK_GLOBAL and not
>> IRQ_GET_DESC_CHECK_PERCPU. Which sort of makes sense because the trigger
>> is per-cpu and not global. We'd need some similar check in
>> enable_percpu_irq, but at that stage, we've already lost the context
>> coming from the firmware.
>>
>> Which only proves one thing: per-cpu interrupts have never been
>> configured on the allocation path, and we've been living pretty
>> dangerously so far. They do work (at least on ARM) because of the
>> following reasons:
>>
>> 1) the triggers are already configured (firmware, read-only...)
>> 2) the handle_percpu_devid_irq handler doesn't distinguish between flows
>>
>> It is probably broken on all other architectures, which kind of sucks.
>> At this point, I'm really tempted to drop this patch and to aim towards
>> something similar to what you had in patches 5 and 6 in your previous
>> series. I'll have a think tonight.
> 
> OK. I will hold off on posting the other patches for the minute.

By the way, it is fine if you want to drop this one for now and just
include the other 10 in your pull request.

Cheers
Jon

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

end of thread, other threads:[~2016-05-10 18:06 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-10 15:14 [PATCH 00/11] Various IRQ and GIC fixes and clean-ups Jon Hunter
2016-05-10 15:14 ` [PATCH 01/11] genirq: Ensure IRQ descriptor is valid when setting-up the IRQ Jon Hunter
2016-05-10 15:14 ` [PATCH 02/11] irqdomain: Warn if we fail to set the IRQ type Jon Hunter
2016-05-10 17:25   ` Marc Zyngier
2016-05-10 18:00     ` Jon Hunter
2016-05-10 18:06       ` Jon Hunter
2016-05-10 15:14 ` [PATCH 03/11] irqchip: Mask the non-type/sense bits when translating an IRQ Jon Hunter
2016-05-10 15:14 ` [PATCH 04/11] irqchip/gic: Don't unnecessarily write the IRQ configuration Jon Hunter
2016-05-10 15:14 ` [PATCH 05/11] irqchip/gic: WARN if setting the interrupt type for a PPI fails Jon Hunter
2016-05-10 15:14 ` [PATCH 06/11] irqchip/gic: Don't initialise chip if mapping IO space fails Jon Hunter
2016-05-10 15:14 ` [PATCH 07/11] irqchip/gic: Remove static irq_chip definition for eoimode1 Jon Hunter
2016-05-10 15:14 ` [PATCH 08/11] irqchip/gic: Return an error if GIC initialisation fails Jon Hunter
2016-05-10 15:14 ` [PATCH 09/11] irqchip/gic: Pass GIC pointer to save/restore functions Jon Hunter
2016-05-10 15:14 ` [PATCH 10/11] irqchip/gic: Store GIC configuration parameters Jon Hunter
2016-05-10 15:14 ` [PATCH 11/11] irqchip/gic: Add helper functions for GIC setup and teardown Jon Hunter

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).