aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-bcm7120-l2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip/irq-bcm7120-l2.c')
-rw-r--r--drivers/irqchip/irq-bcm7120-l2.c76
1 files changed, 53 insertions, 23 deletions
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index 3ba5cc780fcb..d3f976913a6f 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -26,10 +26,9 @@
26#include <linux/irqdomain.h> 26#include <linux/irqdomain.h>
27#include <linux/reboot.h> 27#include <linux/reboot.h>
28#include <linux/bitops.h> 28#include <linux/bitops.h>
29#include <linux/irqchip.h>
29#include <linux/irqchip/chained_irq.h> 30#include <linux/irqchip/chained_irq.h>
30 31
31#include "irqchip.h"
32
33/* Register offset in the L2 interrupt controller */ 32/* Register offset in the L2 interrupt controller */
34#define IRQEN 0x00 33#define IRQEN 0x00
35#define IRQSTAT 0x04 34#define IRQSTAT 0x04
@@ -38,6 +37,11 @@
38#define MAX_MAPPINGS (MAX_WORDS * 2) 37#define MAX_MAPPINGS (MAX_WORDS * 2)
39#define IRQS_PER_WORD 32 38#define IRQS_PER_WORD 32
40 39
40struct bcm7120_l1_intc_data {
41 struct bcm7120_l2_intc_data *b;
42 u32 irq_map_mask[MAX_WORDS];
43};
44
41struct bcm7120_l2_intc_data { 45struct bcm7120_l2_intc_data {
42 unsigned int n_words; 46 unsigned int n_words;
43 void __iomem *map_base[MAX_MAPPINGS]; 47 void __iomem *map_base[MAX_MAPPINGS];
@@ -47,14 +51,15 @@ struct bcm7120_l2_intc_data {
47 struct irq_domain *domain; 51 struct irq_domain *domain;
48 bool can_wake; 52 bool can_wake;
49 u32 irq_fwd_mask[MAX_WORDS]; 53 u32 irq_fwd_mask[MAX_WORDS];
50 u32 irq_map_mask[MAX_WORDS]; 54 struct bcm7120_l1_intc_data *l1_data;
51 int num_parent_irqs; 55 int num_parent_irqs;
52 const __be32 *map_mask_prop; 56 const __be32 *map_mask_prop;
53}; 57};
54 58
55static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) 59static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
56{ 60{
57 struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc); 61 struct bcm7120_l1_intc_data *data = irq_desc_get_handler_data(desc);
62 struct bcm7120_l2_intc_data *b = data->b;
58 struct irq_chip *chip = irq_desc_get_chip(desc); 63 struct irq_chip *chip = irq_desc_get_chip(desc);
59 unsigned int idx; 64 unsigned int idx;
60 65
@@ -69,7 +74,8 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
69 74
70 irq_gc_lock(gc); 75 irq_gc_lock(gc);
71 pending = irq_reg_readl(gc, b->stat_offset[idx]) & 76 pending = irq_reg_readl(gc, b->stat_offset[idx]) &
72 gc->mask_cache; 77 gc->mask_cache &
78 data->irq_map_mask[idx];
73 irq_gc_unlock(gc); 79 irq_gc_unlock(gc);
74 80
75 for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { 81 for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
@@ -81,11 +87,10 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
81 chained_irq_exit(chip, desc); 87 chained_irq_exit(chip, desc);
82} 88}
83 89
84static void bcm7120_l2_intc_suspend(struct irq_data *d) 90static void bcm7120_l2_intc_suspend(struct irq_chip_generic *gc)
85{ 91{
86 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
87 struct irq_chip_type *ct = irq_data_get_chip_type(d);
88 struct bcm7120_l2_intc_data *b = gc->private; 92 struct bcm7120_l2_intc_data *b = gc->private;
93 struct irq_chip_type *ct = gc->chip_types;
89 94
90 irq_gc_lock(gc); 95 irq_gc_lock(gc);
91 if (b->can_wake) 96 if (b->can_wake)
@@ -94,10 +99,9 @@ static void bcm7120_l2_intc_suspend(struct irq_data *d)
94 irq_gc_unlock(gc); 99 irq_gc_unlock(gc);
95} 100}
96 101
97static void bcm7120_l2_intc_resume(struct irq_data *d) 102static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc)
98{ 103{
99 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 104 struct irq_chip_type *ct = gc->chip_types;
100 struct irq_chip_type *ct = irq_data_get_chip_type(d);
101 105
102 /* Restore the saved mask */ 106 /* Restore the saved mask */
103 irq_gc_lock(gc); 107 irq_gc_lock(gc);
@@ -107,8 +111,9 @@ static void bcm7120_l2_intc_resume(struct irq_data *d)
107 111
108static int bcm7120_l2_intc_init_one(struct device_node *dn, 112static int bcm7120_l2_intc_init_one(struct device_node *dn,
109 struct bcm7120_l2_intc_data *data, 113 struct bcm7120_l2_intc_data *data,
110 int irq) 114 int irq, u32 *valid_mask)
111{ 115{
116 struct bcm7120_l1_intc_data *l1_data = &data->l1_data[irq];
112 int parent_irq; 117 int parent_irq;
113 unsigned int idx; 118 unsigned int idx;
114 119
@@ -120,20 +125,28 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
120 125
121 /* For multiple parent IRQs with multiple words, this looks like: 126 /* For multiple parent IRQs with multiple words, this looks like:
122 * <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...> 127 * <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...>
128 *
129 * We need to associate a given parent interrupt with its corresponding
130 * map_mask in order to mask the status register with it because we
131 * have the same handler being called for multiple parent interrupts.
132 *
133 * This is typically something needed on BCM7xxx (STB chips).
123 */ 134 */
124 for (idx = 0; idx < data->n_words; idx++) { 135 for (idx = 0; idx < data->n_words; idx++) {
125 if (data->map_mask_prop) { 136 if (data->map_mask_prop) {
126 data->irq_map_mask[idx] |= 137 l1_data->irq_map_mask[idx] |=
127 be32_to_cpup(data->map_mask_prop + 138 be32_to_cpup(data->map_mask_prop +
128 irq * data->n_words + idx); 139 irq * data->n_words + idx);
129 } else { 140 } else {
130 data->irq_map_mask[idx] = 0xffffffff; 141 l1_data->irq_map_mask[idx] = 0xffffffff;
131 } 142 }
143 valid_mask[idx] |= l1_data->irq_map_mask[idx];
132 } 144 }
133 145
134 irq_set_handler_data(parent_irq, data); 146 l1_data->b = data;
135 irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle);
136 147
148 irq_set_chained_handler_and_data(parent_irq,
149 bcm7120_l2_intc_irq_handle, l1_data);
137 return 0; 150 return 0;
138} 151}
139 152
@@ -214,6 +227,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
214 struct irq_chip_type *ct; 227 struct irq_chip_type *ct;
215 int ret = 0; 228 int ret = 0;
216 unsigned int idx, irq, flags; 229 unsigned int idx, irq, flags;
230 u32 valid_mask[MAX_WORDS] = { };
217 231
218 data = kzalloc(sizeof(*data), GFP_KERNEL); 232 data = kzalloc(sizeof(*data), GFP_KERNEL);
219 if (!data) 233 if (!data)
@@ -226,9 +240,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
226 goto out_unmap; 240 goto out_unmap;
227 } 241 }
228 242
243 data->l1_data = kcalloc(data->num_parent_irqs, sizeof(*data->l1_data),
244 GFP_KERNEL);
245 if (!data->l1_data) {
246 ret = -ENOMEM;
247 goto out_free_l1_data;
248 }
249
229 ret = iomap_regs_fn(dn, data); 250 ret = iomap_regs_fn(dn, data);
230 if (ret < 0) 251 if (ret < 0)
231 goto out_unmap; 252 goto out_free_l1_data;
232 253
233 for (idx = 0; idx < data->n_words; idx++) { 254 for (idx = 0; idx < data->n_words; idx++) {
234 __raw_writel(data->irq_fwd_mask[idx], 255 __raw_writel(data->irq_fwd_mask[idx],
@@ -237,16 +258,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
237 } 258 }
238 259
239 for (irq = 0; irq < data->num_parent_irqs; irq++) { 260 for (irq = 0; irq < data->num_parent_irqs; irq++) {
240 ret = bcm7120_l2_intc_init_one(dn, data, irq); 261 ret = bcm7120_l2_intc_init_one(dn, data, irq, valid_mask);
241 if (ret) 262 if (ret)
242 goto out_unmap; 263 goto out_free_l1_data;
243 } 264 }
244 265
245 data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words, 266 data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words,
246 &irq_generic_chip_ops, NULL); 267 &irq_generic_chip_ops, NULL);
247 if (!data->domain) { 268 if (!data->domain) {
248 ret = -ENOMEM; 269 ret = -ENOMEM;
249 goto out_unmap; 270 goto out_free_l1_data;
250 } 271 }
251 272
252 /* MIPS chips strapped for BE will automagically configure the 273 /* MIPS chips strapped for BE will automagically configure the
@@ -270,7 +291,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
270 irq = idx * IRQS_PER_WORD; 291 irq = idx * IRQS_PER_WORD;
271 gc = irq_get_domain_generic_chip(data->domain, irq); 292 gc = irq_get_domain_generic_chip(data->domain, irq);
272 293
273 gc->unused = 0xffffffff & ~data->irq_map_mask[idx]; 294 gc->unused = 0xffffffff & ~valid_mask[idx];
274 gc->private = data; 295 gc->private = data;
275 ct = gc->chip_types; 296 ct = gc->chip_types;
276 297
@@ -280,8 +301,15 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
280 ct->chip.irq_mask = irq_gc_mask_clr_bit; 301 ct->chip.irq_mask = irq_gc_mask_clr_bit;
281 ct->chip.irq_unmask = irq_gc_mask_set_bit; 302 ct->chip.irq_unmask = irq_gc_mask_set_bit;
282 ct->chip.irq_ack = irq_gc_noop; 303 ct->chip.irq_ack = irq_gc_noop;
283 ct->chip.irq_suspend = bcm7120_l2_intc_suspend; 304 gc->suspend = bcm7120_l2_intc_suspend;
284 ct->chip.irq_resume = bcm7120_l2_intc_resume; 305 gc->resume = bcm7120_l2_intc_resume;
306
307 /*
308 * Initialize mask-cache, in case we need it for
309 * saving/restoring fwd mask even w/o any child interrupts
310 * installed
311 */
312 gc->mask_cache = irq_reg_readl(gc, ct->regs.mask);
285 313
286 if (data->can_wake) { 314 if (data->can_wake) {
287 /* This IRQ chip can wake the system, set all 315 /* This IRQ chip can wake the system, set all
@@ -300,6 +328,8 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn,
300 328
301out_free_domain: 329out_free_domain:
302 irq_domain_remove(data->domain); 330 irq_domain_remove(data->domain);
331out_free_l1_data:
332 kfree(data->l1_data);
303out_unmap: 333out_unmap:
304 for (idx = 0; idx < MAX_MAPPINGS; idx++) { 334 for (idx = 0; idx < MAX_MAPPINGS; idx++) {
305 if (data->map_base[idx]) 335 if (data->map_base[idx])