aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh/intc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sh/intc.c')
-rw-r--r--drivers/sh/intc.c200
1 files changed, 148 insertions, 52 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 77d10acf1884..dcb4c833820b 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -98,6 +98,9 @@ static DEFINE_SPINLOCK(vector_lock);
98static unsigned int intc_prio_level[NR_IRQS]; /* for now */ 98static unsigned int intc_prio_level[NR_IRQS]; /* for now */
99static unsigned int default_prio_level = 2; /* 2 - 16 */ 99static unsigned int default_prio_level = 2; /* 2 - 16 */
100static unsigned long ack_handle[NR_IRQS]; 100static unsigned long ack_handle[NR_IRQS];
101#ifdef CONFIG_INTC_BALANCING
102static unsigned long dist_handle[NR_IRQS];
103#endif
101 104
102static inline struct intc_desc_int *get_intc_desc(unsigned int irq) 105static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
103{ 106{
@@ -105,6 +108,47 @@ static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
105 return container_of(chip, struct intc_desc_int, chip); 108 return container_of(chip, struct intc_desc_int, chip);
106} 109}
107 110
111static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
112 unsigned long address)
113{
114 struct intc_window *window;
115 int k;
116
117 /* scan through physical windows and convert address */
118 for (k = 0; k < d->nr_windows; k++) {
119 window = d->window + k;
120
121 if (address < window->phys)
122 continue;
123
124 if (address >= (window->phys + window->size))
125 continue;
126
127 address -= window->phys;
128 address += (unsigned long)window->virt;
129
130 return address;
131 }
132
133 /* no windows defined, register must be 1:1 mapped virt:phys */
134 return address;
135}
136
137static unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
138{
139 unsigned int k;
140
141 address = intc_phys_to_virt(d, address);
142
143 for (k = 0; k < d->nr_reg; k++) {
144 if (d->reg[k] == address)
145 return k;
146 }
147
148 BUG();
149 return 0;
150}
151
108static inline unsigned int set_field(unsigned int value, 152static inline unsigned int set_field(unsigned int value,
109 unsigned int field_value, 153 unsigned int field_value,
110 unsigned int handle) 154 unsigned int handle)
@@ -238,6 +282,85 @@ static void (*intc_disable_fns[])(unsigned long addr,
238 [MODE_PCLR_REG] = intc_mode_field, 282 [MODE_PCLR_REG] = intc_mode_field,
239}; 283};
240 284
285#ifdef CONFIG_INTC_BALANCING
286static inline void intc_balancing_enable(unsigned int irq)
287{
288 struct intc_desc_int *d = get_intc_desc(irq);
289 unsigned long handle = dist_handle[irq];
290 unsigned long addr;
291
292 if (irq_balancing_disabled(irq) || !handle)
293 return;
294
295 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
296 intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
297}
298
299static inline void intc_balancing_disable(unsigned int irq)
300{
301 struct intc_desc_int *d = get_intc_desc(irq);
302 unsigned long handle = dist_handle[irq];
303 unsigned long addr;
304
305 if (irq_balancing_disabled(irq) || !handle)
306 return;
307
308 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
309 intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
310}
311
312static unsigned int intc_dist_data(struct intc_desc *desc,
313 struct intc_desc_int *d,
314 intc_enum enum_id)
315{
316 struct intc_mask_reg *mr = desc->hw.mask_regs;
317 unsigned int i, j, fn, mode;
318 unsigned long reg_e, reg_d;
319
320 for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
321 mr = desc->hw.mask_regs + i;
322
323 /*
324 * Skip this entry if there's no auto-distribution
325 * register associated with it.
326 */
327 if (!mr->dist_reg)
328 continue;
329
330 for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
331 if (mr->enum_ids[j] != enum_id)
332 continue;
333
334 fn = REG_FN_MODIFY_BASE;
335 mode = MODE_ENABLE_REG;
336 reg_e = mr->dist_reg;
337 reg_d = mr->dist_reg;
338
339 fn += (mr->reg_width >> 3) - 1;
340 return _INTC_MK(fn, mode,
341 intc_get_reg(d, reg_e),
342 intc_get_reg(d, reg_d),
343 1,
344 (mr->reg_width - 1) - j);
345 }
346 }
347
348 /*
349 * It's possible we've gotten here with no distribution options
350 * available for the IRQ in question, so we just skip over those.
351 */
352 return 0;
353}
354#else
355static inline void intc_balancing_enable(unsigned int irq)
356{
357}
358
359static inline void intc_balancing_disable(unsigned int irq)
360{
361}
362#endif
363
241static inline void _intc_enable(unsigned int irq, unsigned long handle) 364static inline void _intc_enable(unsigned int irq, unsigned long handle)
242{ 365{
243 struct intc_desc_int *d = get_intc_desc(irq); 366 struct intc_desc_int *d = get_intc_desc(irq);
@@ -253,6 +376,8 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle)
253 intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ 376 intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
254 [_INTC_FN(handle)], irq); 377 [_INTC_FN(handle)], irq);
255 } 378 }
379
380 intc_balancing_enable(irq);
256} 381}
257 382
258static void intc_enable(unsigned int irq) 383static void intc_enable(unsigned int irq)
@@ -263,10 +388,12 @@ static void intc_enable(unsigned int irq)
263static void intc_disable(unsigned int irq) 388static void intc_disable(unsigned int irq)
264{ 389{
265 struct intc_desc_int *d = get_intc_desc(irq); 390 struct intc_desc_int *d = get_intc_desc(irq);
266 unsigned long handle = (unsigned long) get_irq_chip_data(irq); 391 unsigned long handle = (unsigned long)get_irq_chip_data(irq);
267 unsigned long addr; 392 unsigned long addr;
268 unsigned int cpu; 393 unsigned int cpu;
269 394
395 intc_balancing_disable(irq);
396
270 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { 397 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
271#ifdef CONFIG_SMP 398#ifdef CONFIG_SMP
272 if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) 399 if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
@@ -345,8 +472,7 @@ static void intc_mask_ack(unsigned int irq)
345 472
346 intc_disable(irq); 473 intc_disable(irq);
347 474
348 /* read register and write zero only to the assocaited bit */ 475 /* read register and write zero only to the associated bit */
349
350 if (handle) { 476 if (handle) {
351 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); 477 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
352 switch (_INTC_FN(handle)) { 478 switch (_INTC_FN(handle)) {
@@ -375,7 +501,8 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
375{ 501{
376 int i; 502 int i;
377 503
378 /* this doesn't scale well, but... 504 /*
505 * this doesn't scale well, but...
379 * 506 *
380 * this function should only be used for cerain uncommon 507 * this function should only be used for cerain uncommon
381 * operations such as intc_set_priority() and intc_set_sense() 508 * operations such as intc_set_priority() and intc_set_sense()
@@ -386,7 +513,6 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
386 * memory footprint down is to make sure the array is sorted 513 * memory footprint down is to make sure the array is sorted
387 * and then perform a bisect to lookup the irq. 514 * and then perform a bisect to lookup the irq.
388 */ 515 */
389
390 for (i = 0; i < nr_hp; i++) { 516 for (i = 0; i < nr_hp; i++) {
391 if ((hp + i)->irq != irq) 517 if ((hp + i)->irq != irq)
392 continue; 518 continue;
@@ -417,7 +543,6 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
417 * primary masking method is using intc_prio_level[irq] 543 * primary masking method is using intc_prio_level[irq]
418 * priority level will be set during next enable() 544 * priority level will be set during next enable()
419 */ 545 */
420
421 if (_INTC_FN(ihp->handle) != REG_FN_ERR) 546 if (_INTC_FN(ihp->handle) != REG_FN_ERR)
422 _intc_enable(irq, ihp->handle); 547 _intc_enable(irq, ihp->handle);
423 } 548 }
@@ -456,48 +581,6 @@ static int intc_set_sense(unsigned int irq, unsigned int type)
456 return 0; 581 return 0;
457} 582}
458 583
459static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
460 unsigned long address)
461{
462 struct intc_window *window;
463 int k;
464
465 /* scan through physical windows and convert address */
466 for (k = 0; k < d->nr_windows; k++) {
467 window = d->window + k;
468
469 if (address < window->phys)
470 continue;
471
472 if (address >= (window->phys + window->size))
473 continue;
474
475 address -= window->phys;
476 address += (unsigned long)window->virt;
477
478 return address;
479 }
480
481 /* no windows defined, register must be 1:1 mapped virt:phys */
482 return address;
483}
484
485static unsigned int __init intc_get_reg(struct intc_desc_int *d,
486 unsigned long address)
487{
488 unsigned int k;
489
490 address = intc_phys_to_virt(d, address);
491
492 for (k = 0; k < d->nr_reg; k++) {
493 if (d->reg[k] == address)
494 return k;
495 }
496
497 BUG();
498 return 0;
499}
500
501static intc_enum __init intc_grp_id(struct intc_desc *desc, 584static intc_enum __init intc_grp_id(struct intc_desc *desc,
502 intc_enum enum_id) 585 intc_enum enum_id)
503{ 586{
@@ -755,13 +838,14 @@ static void __init intc_register_irq(struct intc_desc *desc,
755 */ 838 */
756 set_bit(irq, intc_irq_map); 839 set_bit(irq, intc_irq_map);
757 840
758 /* Prefer single interrupt source bitmap over other combinations: 841 /*
842 * Prefer single interrupt source bitmap over other combinations:
843 *
759 * 1. bitmap, single interrupt source 844 * 1. bitmap, single interrupt source
760 * 2. priority, single interrupt source 845 * 2. priority, single interrupt source
761 * 3. bitmap, multiple interrupt sources (groups) 846 * 3. bitmap, multiple interrupt sources (groups)
762 * 4. priority, multiple interrupt sources (groups) 847 * 4. priority, multiple interrupt sources (groups)
763 */ 848 */
764
765 data[0] = intc_mask_data(desc, d, enum_id, 0); 849 data[0] = intc_mask_data(desc, d, enum_id, 0);
766 data[1] = intc_prio_data(desc, d, enum_id, 0); 850 data[1] = intc_prio_data(desc, d, enum_id, 0);
767 851
@@ -786,7 +870,8 @@ static void __init intc_register_irq(struct intc_desc *desc,
786 handle_level_irq, "level"); 870 handle_level_irq, "level");
787 set_irq_chip_data(irq, (void *)data[primary]); 871 set_irq_chip_data(irq, (void *)data[primary]);
788 872
789 /* set priority level 873 /*
874 * set priority level
790 * - this needs to be at least 2 for 5-bit priorities on 7780 875 * - this needs to be at least 2 for 5-bit priorities on 7780
791 */ 876 */
792 intc_prio_level[irq] = default_prio_level; 877 intc_prio_level[irq] = default_prio_level;
@@ -806,7 +891,6 @@ static void __init intc_register_irq(struct intc_desc *desc,
806 * only secondary priority should access registers, so 891 * only secondary priority should access registers, so
807 * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() 892 * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
808 */ 893 */
809
810 hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); 894 hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
811 hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); 895 hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
812 } 896 }
@@ -827,6 +911,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
827 if (desc->hw.ack_regs) 911 if (desc->hw.ack_regs)
828 ack_handle[irq] = intc_ack_data(desc, d, enum_id); 912 ack_handle[irq] = intc_ack_data(desc, d, enum_id);
829 913
914#ifdef CONFIG_INTC_BALANCING
915 if (desc->hw.mask_regs)
916 dist_handle[irq] = intc_dist_data(desc, d, enum_id);
917#endif
918
830#ifdef CONFIG_ARM 919#ifdef CONFIG_ARM
831 set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */ 920 set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
832#endif 921#endif
@@ -892,6 +981,10 @@ int __init register_intc_controller(struct intc_desc *desc)
892 } 981 }
893 982
894 d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; 983 d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
984#ifdef CONFIG_INTC_BALANCING
985 if (d->nr_reg)
986 d->nr_reg += hw->nr_mask_regs;
987#endif
895 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; 988 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
896 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; 989 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
897 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; 990 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
@@ -912,6 +1005,9 @@ int __init register_intc_controller(struct intc_desc *desc)
912 smp = IS_SMP(hw->mask_regs[i]); 1005 smp = IS_SMP(hw->mask_regs[i]);
913 k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); 1006 k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
914 k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); 1007 k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
1008#ifdef CONFIG_INTC_BALANCING
1009 k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
1010#endif
915 } 1011 }
916 } 1012 }
917 1013