Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1416303 > unrolled thread
| Started by | Jon Hunter <jonathanh@nvidia.com> |
|---|---|
| First post | 2016-06-07 17:20 +0200 |
| Last post | 2016-06-07 17:20 +0200 |
| Articles | 5 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH V6 0/9] Add support for Tegra210 AGIC Jon Hunter <jonathanh@nvidia.com> - 2016-06-07 17:20 +0200
[PATCH V6 2/9] genirq: Look-up trigger type if not specified by caller Jon Hunter <jonathanh@nvidia.com> - 2016-06-07 17:20 +0200
[PATCH V6 4/9] genirq: Add runtime power management support for IRQ chips Jon Hunter <jonathanh@nvidia.com> - 2016-06-07 17:20 +0200
Re: [PATCH V6 4/9] genirq: Add runtime power management support for IRQ chips Kevin Hilman <khilman@baylibre.com> - 2016-06-11 00:10 +0200
[PATCH V6 5/9] irqchip/gic: Isolate early GIC initialisation code Jon Hunter <jonathanh@nvidia.com> - 2016-06-07 17:20 +0200
| From | Jon Hunter <jonathanh@nvidia.com> |
|---|---|
| Date | 2016-06-07 17:20 +0200 |
| Subject | [PATCH V6 0/9] Add support for Tegra210 AGIC |
| Message-ID | <rHqXn-4lt-15@gated-at.bofh.it> |
The Tegra210 has a 2nd level interrupt controller located in a separate power domain to the main GIC interrupt controller and hence requires runtime-pm support. Add a platform driver for the GICs that require runtime-pm and make the necessary changes to the genirq and irqdomain core to support IRQ chips that require runtime-pm. This series is based upon Marc Z's irq/irqchip-v4.7-rc1 branch [0]. Changes since V5: - Add call to pm_runtime_put_noidle() if irq-chip pm_runtime_get_sync() fails. - Removed unnecessary whitespace that was added incorrectly. Changes since V4: - Removed header file drivers/irqchip/irq-gic.h. - Avoid exporting gic_handle_cascade_irq entry point. - Renamed of_gic_init() to gic_of_init_child() to distinguish it from the existing gic_of_int(). - Corrected preprocessor directive for CONFIG_ARM_GIC_PM. Changes since V3: - Split the series into two, placing the clean-up/fixes patches into another series [1]. The remaining patches in this series are for adding runtime-pm support for irqchips and adding a platform driver of second level GICs. - Dropped the patch to prevent early init of GICs if 'clocks' or 'power-domains' properties are present and re-added the patch to add the compatibilty string for the Tegra210 AGIC. Changes since V2: - Corrected RPM support for irqchips in genirq core as pointed out by Kevin Hilman. - Corrected patch to save the irq type when mapping the interrupt. - Dropped changes to DT binding documentation and added patch to prevent early init of GICs if the 'clocks' and/or 'power-domains' DT properties are present (as we have discussed). - Moved platform driver code into it's own source file. - Separate changes for preparing for the platform driver into 3 patches in an attempt to make it more readable! - Added fix for checking an interrupt descriptor is valid during IRQ setup. Changes since V1: - Updated GIC to only WARN and not return an error if configuring a PPI fails but will still return an error if an SPI fails (per discussion with Marc). - Dropped change to mask sense bits for GIC-v3 (as this is not necessary) - Split patch to avoid setting interrupt type when mapping the IRQ into two patches per TGLX's feedback. - Changed name of irqchip device structure to "parent_device" - Moved call to irq_chip_pm_get() outside of chip_bus_lock(). - Dropped patch to remove clock names from GIC DT documentation and added AGIC clock names. - Update GIC platform driver to look-up clocks names from static list. [0] http://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/log/?h=irq/irqchip-4.7-rc1 [1] http://marc.info/?l=linux-tegra&m=146289329915585&w=2 Jon Hunter (9): irqdomain: Fix handling of type settings for existing mappings genirq: Look-up trigger type if not specified by caller irqdomain: Don't set type when mapping an IRQ genirq: Add runtime power management support for IRQ chips irqchip/gic: Isolate early GIC initialisation code irqchip/gic: Add helper function for chip initialisation irqchip/gic: Prepare for adding platform driver dt-bindings: arm-gic: Add documentation for Tegra210 AGIC irqchip/gic: Add platform driver for non-root GICs that require RPM .../bindings/interrupt-controller/arm,gic.txt | 3 +- drivers/irqchip/Kconfig | 6 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-gic-common.c | 4 +- drivers/irqchip/irq-gic-pm.c | 184 +++++++++++++++++++++ drivers/irqchip/irq-gic.c | 132 ++++++++++----- include/linux/irq.h | 4 + include/linux/irqchip/arm-gic.h | 11 ++ include/linux/irqdomain.h | 3 + kernel/irq/chip.c | 40 +++++ kernel/irq/internals.h | 1 + kernel/irq/irqdomain.c | 58 ++++++- kernel/irq/manage.c | 38 ++++- 13 files changed, 433 insertions(+), 52 deletions(-) create mode 100644 drivers/irqchip/irq-gic-pm.c -- 2.1.4
[toc] | [next] | [standalone]
| From | Jon Hunter <jonathanh@nvidia.com> |
|---|---|
| Date | 2016-06-07 17:20 +0200 |
| Subject | [PATCH V6 2/9] genirq: Look-up trigger type if not specified by caller |
| Message-ID | <rHqXo-4lt-51@gated-at.bofh.it> |
| In reply to | #1416303 |
For some devices the IRQ trigger type for a device is read from firmware, such as device-tree. The IRQ trigger type is typically read when the mapping for IRQ is created, which is before the IRQ is requested. Hence, the IRQ trigger type is programmed when mapping the IRQ and not when requesting the IRQ. Although this works for most cases, in order to support IRQ chips which require runtime power management, which may not be accessible prior to requesting the IRQ, it is desirable to look-up the IRQ trigger type when it is requested. Therefore, if the IRQ trigger type is not specified when __setup_irq() is called, look-up the saved IRQ trigger type. This will allow us to defer the programming of the trigger type from when the IRQ is mapped to when it is actually requested. Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> --- kernel/irq/manage.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ef0bc02c3a70..eaedeb74b49d 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1117,6 +1117,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) new->irq = irq; /* + * If the trigger type is not specified by the caller, + * then use the default for this interrupt. + */ + if (!(new->flags & IRQF_TRIGGER_MASK)) + new->flags |= irqd_get_trigger_type(&desc->irq_data); + + /* * Check whether the interrupt nests into another interrupt * thread. */ -- 2.1.4
[toc] | [prev] | [next] | [standalone]
| From | Jon Hunter <jonathanh@nvidia.com> |
|---|---|
| Date | 2016-06-07 17:20 +0200 |
| Subject | [PATCH V6 4/9] genirq: Add runtime power management support for IRQ chips |
| Message-ID | <rHqXo-4lt-53@gated-at.bofh.it> |
| In reply to | #1416303 |
Some IRQ chips may be located in a power domain outside of the CPU
subsystem and hence will require device specific runtime power
management. In order to support such IRQ chips, add a pointer for a
device structure to the irq_chip structure, and if this pointer is
populated by the IRQ chip driver and CONFIG_PM is selected in the kernel
configuration, then the pm_runtime_get/put APIs for this chip will be
called when an IRQ is requested/freed, respectively.
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
include/linux/irq.h | 4 ++++
kernel/irq/chip.c | 40 ++++++++++++++++++++++++++++++++++++++++
kernel/irq/internals.h | 1 +
kernel/irq/manage.c | 31 ++++++++++++++++++++++++++++++-
4 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 4d758a7c604a..6c92a847394d 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -315,6 +315,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
/**
* struct irq_chip - hardware interrupt chip descriptor
*
+ * @parent_device: pointer to parent device for irqchip
* @name: name for /proc/interrupts
* @irq_startup: start up the interrupt (defaults to ->enable if NULL)
* @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL)
@@ -354,6 +355,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
* @flags: chip specific flags
*/
struct irq_chip {
+ struct device *parent_device;
const char *name;
unsigned int (*irq_startup)(struct irq_data *data);
void (*irq_shutdown)(struct irq_data *data);
@@ -488,6 +490,8 @@ extern void handle_bad_irq(struct irq_desc *desc);
extern void handle_nested_irq(unsigned int irq);
extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg);
+extern int irq_chip_pm_get(struct irq_data *data);
+extern int irq_chip_pm_put(struct irq_data *data);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
extern void irq_chip_enable_parent(struct irq_data *data);
extern void irq_chip_disable_parent(struct irq_data *data);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 2f9f2b0e79f2..ad8131473774 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -1093,3 +1093,43 @@ int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
return 0;
}
+
+/**
+ * irq_chip_pm_get - Enable power for an IRQ chip
+ * @data: Pointer to interrupt specific data
+ *
+ * Enable the power to the IRQ chip referenced by the interrupt data
+ * structure.
+ */
+int irq_chip_pm_get(struct irq_data *data)
+{
+ int retval;
+
+ if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) {
+ retval = pm_runtime_get_sync(data->chip->parent_device);
+ if (retval < 0) {
+ pm_runtime_put_noidle(data->chip->parent_device);
+ return retval;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * irq_chip_pm_put - Disable power for an IRQ chip
+ * @data: Pointer to interrupt specific data
+ *
+ * Disable the power to the IRQ chip referenced by the interrupt data
+ * structure, belongs. Note that power will only be disabled, once this
+ * function has been called for all IRQs that have called irq_chip_pm_get().
+ */
+int irq_chip_pm_put(struct irq_data *data)
+{
+ int retval = 0;
+
+ if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device)
+ retval = pm_runtime_put(data->chip->parent_device);
+
+ return (retval < 0) ? retval : 0;
+}
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 09be2c903c6d..d5edcdc9382a 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -7,6 +7,7 @@
*/
#include <linux/irqdesc.h>
#include <linux/kernel_stat.h>
+#include <linux/pm_runtime.h>
#ifdef CONFIG_SPARSE_IRQ
# define IRQ_BITMAP_BITS (NR_IRQS + 8196)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index eaedeb74b49d..f8fd1fbc02ea 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1416,10 +1416,18 @@ int setup_irq(unsigned int irq, struct irqaction *act)
if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
return -EINVAL;
+
+ retval = irq_chip_pm_get(&desc->irq_data);
+ if (retval < 0)
+ return retval;
+
chip_bus_lock(desc);
retval = __setup_irq(irq, desc, act);
chip_bus_sync_unlock(desc);
+ if (retval)
+ irq_chip_pm_put(&desc->irq_data);
+
return retval;
}
EXPORT_SYMBOL_GPL(setup_irq);
@@ -1513,6 +1521,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
}
}
+ irq_chip_pm_put(&desc->irq_data);
module_put(desc->owner);
kfree(action->secondary);
return action;
@@ -1655,11 +1664,16 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
action->name = devname;
action->dev_id = dev_id;
+ retval = irq_chip_pm_get(&desc->irq_data);
+ if (retval < 0)
+ return retval;
+
chip_bus_lock(desc);
retval = __setup_irq(irq, desc, action);
chip_bus_sync_unlock(desc);
if (retval) {
+ irq_chip_pm_put(&desc->irq_data);
kfree(action->secondary);
kfree(action);
}
@@ -1829,6 +1843,7 @@ static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_
unregister_handler_proc(irq, action);
+ irq_chip_pm_put(&desc->irq_data);
module_put(desc->owner);
return action;
@@ -1891,10 +1906,18 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)
if (!desc || !irq_settings_is_per_cpu_devid(desc))
return -EINVAL;
+
+ retval = irq_chip_pm_get(&desc->irq_data);
+ if (retval < 0)
+ return retval;
+
chip_bus_lock(desc);
retval = __setup_irq(irq, desc, act);
chip_bus_sync_unlock(desc);
+ if (retval)
+ irq_chip_pm_put(&desc->irq_data);
+
return retval;
}
@@ -1938,12 +1961,18 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler,
action->name = devname;
action->percpu_dev_id = dev_id;
+ retval = irq_chip_pm_get(&desc->irq_data);
+ if (retval < 0)
+ return retval;
+
chip_bus_lock(desc);
retval = __setup_irq(irq, desc, action);
chip_bus_sync_unlock(desc);
- if (retval)
+ if (retval) {
+ irq_chip_pm_put(&desc->irq_data);
kfree(action);
+ }
return retval;
}
--
2.1.4
[toc] | [prev] | [next] | [standalone]
| From | Kevin Hilman <khilman@baylibre.com> |
|---|---|
| Date | 2016-06-11 00:10 +0200 |
| Subject | Re: [PATCH V6 4/9] genirq: Add runtime power management support for IRQ chips |
| Message-ID | <rICMP-2IE-51@gated-at.bofh.it> |
| In reply to | #1416306 |
Jon Hunter <jonathanh@nvidia.com> writes: > Some IRQ chips may be located in a power domain outside of the CPU > subsystem and hence will require device specific runtime power > management. In order to support such IRQ chips, add a pointer for a > device structure to the irq_chip structure, and if this pointer is > populated by the IRQ chip driver and CONFIG_PM is selected in the kernel > configuration, then the pm_runtime_get/put APIs for this chip will be > called when an IRQ is requested/freed, respectively. > > Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Reviewed-by: Kevin Hilman <khilman@baylibre.com>
[toc] | [prev] | [next] | [standalone]
| From | Jon Hunter <jonathanh@nvidia.com> |
|---|---|
| Date | 2016-06-07 17:20 +0200 |
| Subject | [PATCH V6 5/9] irqchip/gic: Isolate early GIC initialisation code |
| Message-ID | <rHqXo-4lt-57@gated-at.bofh.it> |
| In reply to | #1416303 |
To re-use the code that initialises the GIC (found in
__gic_init_bases()), from within a platform driver, it is necessary to
move the code from the __init section so that it is always present and
not removed. Unfortunately, it is not possible to simply drop the __init
from the function declaration for __gic_init_bases() because it contains
calls to set_smp_cross_call() and set_handle_irq() which are both
located in the __init section. Fortunately, these calls are only
required for the root controller and because the initial platform driver
will only support non-root controllers that can be initialised later in
the boot process, we can move these calls to another function.
Move the bulk of the code from __gic_init_bases() to a new function
called gic_init_bases() which is not located in the __init section and
can be used by the platform driver. Update __gic_init_bases() to call
gic_init_bases() and if necessary, set_smp_cross_call() and
set_handle_irq().
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
---
drivers/irqchip/irq-gic.c | 55 +++++++++++++++++++++++++++--------------------
1 file changed, 32 insertions(+), 23 deletions(-)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index fbc4ae2afd29..fa0dd98993fa 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1032,14 +1032,11 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
.unmap = gic_irq_domain_unmap,
};
-static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start,
- struct fwnode_handle *handle)
+static int gic_init_bases(struct gic_chip_data *gic, int irq_start,
+ struct fwnode_handle *handle)
{
irq_hw_number_t hwirq_base;
- int gic_irqs, irq_base, i, ret;
-
- if (WARN_ON(!gic || gic->domain))
- return -EINVAL;
+ int gic_irqs, irq_base, ret;
/* Initialize irq_chip */
gic->chip = gic_chip;
@@ -1138,23 +1135,6 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start,
goto error;
}
- if (gic == &gic_data[0]) {
- /*
- * Initialize the CPU interface map to all CPUs.
- * It will be refined as each CPU probes its ID.
- * This is only necessary for the primary GIC.
- */
- for (i = 0; i < NR_GIC_CPU_IF; i++)
- gic_cpu_map[i] = 0xff;
-#ifdef CONFIG_SMP
- set_smp_cross_call(gic_raise_softirq);
- register_cpu_notifier(&gic_cpu_notifier);
-#endif
- set_handle_irq(gic_handle_irq);
- if (static_key_true(&supports_deactivate))
- pr_info("GIC: Using split EOI/Deactivate mode\n");
- }
-
gic_dist_init(gic);
ret = gic_cpu_init(gic);
if (ret)
@@ -1177,6 +1157,35 @@ error:
return ret;
}
+static int __init __gic_init_bases(struct gic_chip_data *gic,
+ int irq_start,
+ struct fwnode_handle *handle)
+{
+ int i;
+
+ if (WARN_ON(!gic || gic->domain))
+ return -EINVAL;
+
+ if (gic == &gic_data[0]) {
+ /*
+ * Initialize the CPU interface map to all CPUs.
+ * It will be refined as each CPU probes its ID.
+ * This is only necessary for the primary GIC.
+ */
+ for (i = 0; i < NR_GIC_CPU_IF; i++)
+ gic_cpu_map[i] = 0xff;
+#ifdef CONFIG_SMP
+ set_smp_cross_call(gic_raise_softirq);
+ register_cpu_notifier(&gic_cpu_notifier);
+#endif
+ set_handle_irq(gic_handle_irq);
+ if (static_key_true(&supports_deactivate))
+ pr_info("GIC: Using split EOI/Deactivate mode\n");
+ }
+
+ return gic_init_bases(gic, irq_start, handle);
+}
+
void __init gic_init(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base)
{
--
2.1.4
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web