Skip to content

Commit 3708d52

Browse files
sudeep-hollaJason Cooper
authored andcommitted
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>
1 parent a2c2251 commit 3708d52

File tree

1 file changed

+46
-11
lines changed

1 file changed

+46
-11
lines changed

drivers/irqchip/irq-gic-v3.c

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
#include <linux/cpu.h>
19+
#include <linux/cpu_pm.h>
1920
#include <linux/delay.h>
2021
#include <linux/interrupt.h>
2122
#include <linux/of.h>
@@ -383,6 +384,21 @@ static int gic_populate_rdist(void)
383384
return -ENODEV;
384385
}
385386

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+
386402
static void gic_cpu_init(void)
387403
{
388404
void __iomem *rbase;
@@ -397,17 +413,8 @@ static void gic_cpu_init(void)
397413

398414
gic_cpu_config(rbase, gic_redist_wait_for_rwp);
399415

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();
411418
}
412419

413420
#ifdef CONFIG_SMP
@@ -543,6 +550,33 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
543550
#define gic_smp_init() do { } while(0)
544551
#endif
545552

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+
546580
static struct irq_chip gic_chip = {
547581
.name = "GICv3",
548582
.irq_mask = gic_mask_irq,
@@ -682,6 +716,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
682716
gic_smp_init();
683717
gic_dist_init();
684718
gic_cpu_init();
719+
gic_cpu_pm_init();
685720

686721
return 0;
687722

0 commit comments

Comments
 (0)