Commit 3708d52fc6bb34ae16399fe998d515dd7d188ab0

Authored by Sudeep Holla
Committed by Jason Cooper
1 parent a2c2251012

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>

Showing 1 changed file with 46 additions and 11 deletions Side-by-side Diff

drivers/irqchip/irq-gic-v3.c
... ... @@ -16,6 +16,7 @@
16 16 */
17 17  
18 18 #include <linux/cpu.h>
  19 +#include <linux/cpu_pm.h>
19 20 #include <linux/delay.h>
20 21 #include <linux/interrupt.h>
21 22 #include <linux/of.h>
... ... @@ -383,6 +384,21 @@
383 384 return -ENODEV;
384 385 }
385 386  
  387 +static 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 +
386 402 static void gic_cpu_init(void)
387 403 {
388 404 void __iomem *rbase;
... ... @@ -397,17 +413,8 @@
397 413  
398 414 gic_cpu_config(rbase, gic_redist_wait_for_rwp);
399 415  
400   - /* Enable system registers */
401   - gic_enable_sre();
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);
  416 + /* initialise system registers */
  417 + gic_cpu_sys_reg_init();
411 418 }
412 419  
413 420 #ifdef CONFIG_SMP
... ... @@ -543,6 +550,33 @@
543 550 #define gic_smp_init() do { } while(0)
544 551 #endif
545 552  
  553 +#ifdef CONFIG_CPU_PM
  554 +static 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 +
  567 +static struct notifier_block gic_cpu_pm_notifier_block = {
  568 + .notifier_call = gic_cpu_pm_notifier,
  569 +};
  570 +
  571 +static void gic_cpu_pm_init(void)
  572 +{
  573 + cpu_pm_register_notifier(&gic_cpu_pm_notifier_block);
  574 +}
  575 +
  576 +#else
  577 +static inline void gic_cpu_pm_init(void) { }
  578 +#endif /* CONFIG_CPU_PM */
  579 +
546 580 static struct irq_chip gic_chip = {
547 581 .name = "GICv3",
548 582 .irq_mask = gic_mask_irq,
... ... @@ -682,6 +716,7 @@
682 716 gic_smp_init();
683 717 gic_dist_init();
684 718 gic_cpu_init();
  719 + gic_cpu_pm_init();
685 720  
686 721 return 0;
687 722