diff options
author | Jason Cooper <jason@lakedaemon.net> | 2014-10-02 09:04:58 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-10-02 09:04:58 -0400 |
commit | fae119b6d427a087be0c6a85431c1b8ee9ffea96 (patch) | |
tree | a91d42306e6aca87407df53dfce0d4a9e4eb8e0e /drivers/irqchip/irq-gic-v3.c | |
parent | f7472655fbe70f422c08f78d107ca24a791d7b14 (diff) | |
parent | 3708d52fc6bb34ae16399fe998d515dd7d188ab0 (diff) |
Merge branch 'irqchip/gic' into irqchip/core
Diffstat (limited to 'drivers/irqchip/irq-gic-v3.c')
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 87 |
1 files changed, 66 insertions, 21 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 9e3144975696..7247a3cc7ba1 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> |
@@ -155,7 +156,7 @@ static void gic_enable_sre(void) | |||
155 | pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); | 156 | pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); |
156 | } | 157 | } |
157 | 158 | ||
158 | static void gic_enable_redist(void) | 159 | static void gic_enable_redist(bool enable) |
159 | { | 160 | { |
160 | void __iomem *rbase; | 161 | void __iomem *rbase; |
161 | u32 count = 1000000; /* 1s! */ | 162 | u32 count = 1000000; /* 1s! */ |
@@ -163,20 +164,30 @@ static void gic_enable_redist(void) | |||
163 | 164 | ||
164 | rbase = gic_data_rdist_rd_base(); | 165 | rbase = gic_data_rdist_rd_base(); |
165 | 166 | ||
166 | /* Wake up this CPU redistributor */ | ||
167 | val = readl_relaxed(rbase + GICR_WAKER); | 167 | val = readl_relaxed(rbase + GICR_WAKER); |
168 | val &= ~GICR_WAKER_ProcessorSleep; | 168 | if (enable) |
169 | /* Wake up this CPU redistributor */ | ||
170 | val &= ~GICR_WAKER_ProcessorSleep; | ||
171 | else | ||
172 | val |= GICR_WAKER_ProcessorSleep; | ||
169 | writel_relaxed(val, rbase + GICR_WAKER); | 173 | writel_relaxed(val, rbase + GICR_WAKER); |
170 | 174 | ||
171 | while (readl_relaxed(rbase + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) { | 175 | if (!enable) { /* Check that GICR_WAKER is writeable */ |
172 | count--; | 176 | val = readl_relaxed(rbase + GICR_WAKER); |
173 | if (!count) { | 177 | if (!(val & GICR_WAKER_ProcessorSleep)) |
174 | pr_err_ratelimited("redist didn't wake up...\n"); | 178 | return; /* No PM support in this redistributor */ |
175 | return; | 179 | } |
176 | } | 180 | |
181 | while (count--) { | ||
182 | val = readl_relaxed(rbase + GICR_WAKER); | ||
183 | if (enable ^ (val & GICR_WAKER_ChildrenAsleep)) | ||
184 | break; | ||
177 | cpu_relax(); | 185 | cpu_relax(); |
178 | udelay(1); | 186 | udelay(1); |
179 | }; | 187 | }; |
188 | if (!count) | ||
189 | pr_err_ratelimited("redistributor failed to %s...\n", | ||
190 | enable ? "wakeup" : "sleep"); | ||
180 | } | 191 | } |
181 | 192 | ||
182 | /* | 193 | /* |
@@ -372,6 +383,21 @@ static int gic_populate_rdist(void) | |||
372 | return -ENODEV; | 383 | return -ENODEV; |
373 | } | 384 | } |
374 | 385 | ||
386 | static void gic_cpu_sys_reg_init(void) | ||
387 | { | ||
388 | /* Enable system registers */ | ||
389 | gic_enable_sre(); | ||
390 | |||
391 | /* Set priority mask register */ | ||
392 | gic_write_pmr(DEFAULT_PMR_VALUE); | ||
393 | |||
394 | /* EOI deactivates interrupt too (mode 0) */ | ||
395 | gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); | ||
396 | |||
397 | /* ... and let's hit the road... */ | ||
398 | gic_write_grpen1(1); | ||
399 | } | ||
400 | |||
375 | static void gic_cpu_init(void) | 401 | static void gic_cpu_init(void) |
376 | { | 402 | { |
377 | void __iomem *rbase; | 403 | void __iomem *rbase; |
@@ -380,23 +406,14 @@ static void gic_cpu_init(void) | |||
380 | if (gic_populate_rdist()) | 406 | if (gic_populate_rdist()) |
381 | return; | 407 | return; |
382 | 408 | ||
383 | gic_enable_redist(); | 409 | gic_enable_redist(true); |
384 | 410 | ||
385 | rbase = gic_data_rdist_sgi_base(); | 411 | rbase = gic_data_rdist_sgi_base(); |
386 | 412 | ||
387 | gic_cpu_config(rbase, gic_redist_wait_for_rwp); | 413 | gic_cpu_config(rbase, gic_redist_wait_for_rwp); |
388 | 414 | ||
389 | /* Enable system registers */ | 415 | /* initialise system registers */ |
390 | gic_enable_sre(); | 416 | gic_cpu_sys_reg_init(); |
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 | } | 417 | } |
401 | 418 | ||
402 | #ifdef CONFIG_SMP | 419 | #ifdef CONFIG_SMP |
@@ -532,6 +549,33 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, | |||
532 | #define gic_smp_init() do { } while(0) | 549 | #define gic_smp_init() do { } while(0) |
533 | #endif | 550 | #endif |
534 | 551 | ||
552 | #ifdef CONFIG_CPU_PM | ||
553 | static int gic_cpu_pm_notifier(struct notifier_block *self, | ||
554 | unsigned long cmd, void *v) | ||
555 | { | ||
556 | if (cmd == CPU_PM_EXIT) { | ||
557 | gic_enable_redist(true); | ||
558 | gic_cpu_sys_reg_init(); | ||
559 | } else if (cmd == CPU_PM_ENTER) { | ||
560 | gic_write_grpen1(0); | ||
561 | gic_enable_redist(false); | ||
562 | } | ||
563 | return NOTIFY_OK; | ||
564 | } | ||
565 | |||
566 | static struct notifier_block gic_cpu_pm_notifier_block = { | ||
567 | .notifier_call = gic_cpu_pm_notifier, | ||
568 | }; | ||
569 | |||
570 | static void gic_cpu_pm_init(void) | ||
571 | { | ||
572 | cpu_pm_register_notifier(&gic_cpu_pm_notifier_block); | ||
573 | } | ||
574 | |||
575 | #else | ||
576 | static inline void gic_cpu_pm_init(void) { } | ||
577 | #endif /* CONFIG_CPU_PM */ | ||
578 | |||
535 | static struct irq_chip gic_chip = { | 579 | static struct irq_chip gic_chip = { |
536 | .name = "GICv3", | 580 | .name = "GICv3", |
537 | .irq_mask = gic_mask_irq, | 581 | .irq_mask = gic_mask_irq, |
@@ -671,6 +715,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare | |||
671 | gic_smp_init(); | 715 | gic_smp_init(); |
672 | gic_dist_init(); | 716 | gic_dist_init(); |
673 | gic_cpu_init(); | 717 | gic_cpu_init(); |
718 | gic_cpu_pm_init(); | ||
674 | 719 | ||
675 | return 0; | 720 | return 0; |
676 | 721 | ||