aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudeep Holla <sudeep.holla@arm.com>2014-08-26 11:03:35 -0400
committerJason Cooper <jason@lakedaemon.net>2014-09-14 04:57:54 -0400
commit3708d52fc6bb34ae16399fe998d515dd7d188ab0 (patch)
tree598a7d545982c3f2c63a5d490d7bd77ae1ddb81c
parenta2c225101234bcef8f40497bd50ccb5e9c1fb527 (diff)
irqchip: gic-v3: Implement CPU PM notifier
When a CPU enters a low power state, the contents of the GICv3/4 system registers are lost. They need to be saved and restored if required. For now, since most of the GICv3 register are set some initial values and not modified at runtime, it is better to re-initialise rather than saving and restoring them. It may need to be saved and restored in future if required. This patch adds a notifier to disable the redistributor(if allowed) and Group1 interrupts when powering down the processor and to re-initialise the system registers on wakeup. Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Link: https://lkml.kernel.org/r/1409065415-20176-3-git-send-email-sudeep.holla@arm.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--drivers/irqchip/irq-gic-v3.c57
1 files changed, 46 insertions, 11 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 37062ba6704b..4afbbc835939 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -16,6 +16,7 @@
16 */ 16 */
17 17
18#include <linux/cpu.h> 18#include <linux/cpu.h>
19#include <linux/cpu_pm.h>
19#include <linux/delay.h> 20#include <linux/delay.h>
20#include <linux/interrupt.h> 21#include <linux/interrupt.h>
21#include <linux/of.h> 22#include <linux/of.h>
@@ -383,6 +384,21 @@ static int gic_populate_rdist(void)
383 return -ENODEV; 384 return -ENODEV;
384} 385}
385 386
387static void gic_cpu_sys_reg_init(void)
388{
389 /* Enable system registers */
390 gic_enable_sre();
391
392 /* Set priority mask register */
393 gic_write_pmr(DEFAULT_PMR_VALUE);
394
395 /* EOI deactivates interrupt too (mode 0) */
396 gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
397
398 /* ... and let's hit the road... */
399 gic_write_grpen1(1);
400}
401
386static void gic_cpu_init(void) 402static void gic_cpu_init(void)
387{ 403{
388 void __iomem *rbase; 404 void __iomem *rbase;
@@ -397,17 +413,8 @@ static void gic_cpu_init(void)
397 413
398 gic_cpu_config(rbase, gic_redist_wait_for_rwp); 414 gic_cpu_config(rbase, gic_redist_wait_for_rwp);
399 415
400 /* Enable system registers */ 416 /* initialise system registers */
401 gic_enable_sre(); 417 gic_cpu_sys_reg_init();
402
403 /* Set priority mask register */
404 gic_write_pmr(DEFAULT_PMR_VALUE);
405
406 /* EOI deactivates interrupt too (mode 0) */
407 gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
408
409 /* ... and let's hit the road... */
410 gic_write_grpen1(1);
411} 418}
412 419
413#ifdef CONFIG_SMP 420#ifdef CONFIG_SMP
@@ -543,6 +550,33 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
543#define gic_smp_init() do { } while(0) 550#define gic_smp_init() do { } while(0)
544#endif 551#endif
545 552
553#ifdef CONFIG_CPU_PM
554static int gic_cpu_pm_notifier(struct notifier_block *self,
555 unsigned long cmd, void *v)
556{
557 if (cmd == CPU_PM_EXIT) {
558 gic_enable_redist(true);
559 gic_cpu_sys_reg_init();
560 } else if (cmd == CPU_PM_ENTER) {
561 gic_write_grpen1(0);
562 gic_enable_redist(false);
563 }
564 return NOTIFY_OK;
565}
566
567static struct notifier_block gic_cpu_pm_notifier_block = {
568 .notifier_call = gic_cpu_pm_notifier,
569};
570
571static void gic_cpu_pm_init(void)
572{
573 cpu_pm_register_notifier(&gic_cpu_pm_notifier_block);
574}
575
576#else
577static inline void gic_cpu_pm_init(void) { }
578#endif /* CONFIG_CPU_PM */
579
546static struct irq_chip gic_chip = { 580static struct irq_chip gic_chip = {
547 .name = "GICv3", 581 .name = "GICv3",
548 .irq_mask = gic_mask_irq, 582 .irq_mask = gic_mask_irq,
@@ -682,6 +716,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
682 gic_smp_init(); 716 gic_smp_init();
683 gic_dist_init(); 717 gic_dist_init();
684 gic_cpu_init(); 718 gic_cpu_init();
719 gic_cpu_pm_init();
685 720
686 return 0; 721 return 0;
687 722