aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/kernel/irq.c2
-rw-r--r--drivers/sh/intc.c404
-rw-r--r--include/linux/sh_intc.h12
3 files changed, 351 insertions, 67 deletions
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 257de1f0692b..c8e1409f20a2 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -283,6 +283,8 @@ void __init init_IRQ(void)
283 if (sh_mv.mv_init_irq) 283 if (sh_mv.mv_init_irq)
284 sh_mv.mv_init_irq(); 284 sh_mv.mv_init_irq();
285 285
286 intc_finalize();
287
286 irq_ctx_init(smp_processor_id()); 288 irq_ctx_init(smp_processor_id());
287} 289}
288 290
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index a27dcb4254c7..c81fe23db7f7 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -35,6 +35,7 @@
35#include <linux/seq_file.h> 35#include <linux/seq_file.h>
36#include <linux/radix-tree.h> 36#include <linux/radix-tree.h>
37#include <linux/mutex.h> 37#include <linux/mutex.h>
38#include <linux/rcupdate.h>
38#include <asm/sizes.h> 39#include <asm/sizes.h>
39 40
40#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ 41#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
@@ -64,11 +65,19 @@ struct intc_map_entry {
64 struct intc_desc_int *desc; 65 struct intc_desc_int *desc;
65}; 66};
66 67
68struct intc_subgroup_entry {
69 unsigned int pirq;
70 intc_enum enum_id;
71 unsigned long handle;
72};
73
67struct intc_desc_int { 74struct intc_desc_int {
68 struct list_head list; 75 struct list_head list;
69 struct sys_device sysdev; 76 struct sys_device sysdev;
70 struct radix_tree_root tree; 77 struct radix_tree_root tree;
71 pm_message_t state; 78 pm_message_t state;
79 spinlock_t lock;
80 unsigned int index;
72 unsigned long *reg; 81 unsigned long *reg;
73#ifdef CONFIG_SMP 82#ifdef CONFIG_SMP
74 unsigned long *smp; 83 unsigned long *smp;
@@ -84,6 +93,7 @@ struct intc_desc_int {
84}; 93};
85 94
86static LIST_HEAD(intc_list); 95static LIST_HEAD(intc_list);
96static unsigned int nr_intc_controllers;
87 97
88/* 98/*
89 * The intc_irq_map provides a global map of bound IRQ vectors for a 99 * The intc_irq_map provides a global map of bound IRQ vectors for a
@@ -99,7 +109,7 @@ static LIST_HEAD(intc_list);
99static DECLARE_BITMAP(intc_irq_map, NR_IRQS); 109static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
100static struct intc_map_entry intc_irq_xlate[NR_IRQS]; 110static struct intc_map_entry intc_irq_xlate[NR_IRQS];
101static DEFINE_SPINLOCK(vector_lock); 111static DEFINE_SPINLOCK(vector_lock);
102static DEFINE_MUTEX(irq_xlate_mutex); 112static DEFINE_SPINLOCK(xlate_lock);
103 113
104#ifdef CONFIG_SMP 114#ifdef CONFIG_SMP
105#define IS_SMP(x) x.smp 115#define IS_SMP(x) x.smp
@@ -118,12 +128,39 @@ static unsigned long ack_handle[NR_IRQS];
118static unsigned long dist_handle[NR_IRQS]; 128static unsigned long dist_handle[NR_IRQS];
119#endif 129#endif
120 130
131struct intc_virq_list {
132 unsigned int irq;
133 struct intc_virq_list *next;
134};
135
136#define for_each_virq(entry, head) \
137 for (entry = head; entry; entry = entry->next)
138
121static inline struct intc_desc_int *get_intc_desc(unsigned int irq) 139static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
122{ 140{
123 struct irq_chip *chip = get_irq_chip(irq); 141 struct irq_chip *chip = get_irq_chip(irq);
142
124 return container_of(chip, struct intc_desc_int, chip); 143 return container_of(chip, struct intc_desc_int, chip);
125} 144}
126 145
146static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
147{
148 generic_handle_irq((unsigned int)get_irq_data(irq));
149}
150
151static inline void activate_irq(int irq)
152{
153#ifdef CONFIG_ARM
154 /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
155 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
156 */
157 set_irq_flags(irq, IRQF_VALID);
158#else
159 /* same effect on other architectures */
160 set_irq_noprobe(irq);
161#endif
162}
163
127static unsigned long intc_phys_to_virt(struct intc_desc_int *d, 164static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
128 unsigned long address) 165 unsigned long address)
129{ 166{
@@ -177,56 +214,103 @@ static inline unsigned int set_field(unsigned int value,
177 return value; 214 return value;
178} 215}
179 216
180static void write_8(unsigned long addr, unsigned long h, unsigned long data) 217static inline unsigned long get_field(unsigned int value, unsigned int handle)
218{
219 unsigned int width = _INTC_WIDTH(handle);
220 unsigned int shift = _INTC_SHIFT(handle);
221 unsigned int mask = ((1 << width) - 1) << shift;
222
223 return (value & mask) >> shift;
224}
225
226static unsigned long test_8(unsigned long addr, unsigned long h,
227 unsigned long ignore)
228{
229 return get_field(__raw_readb(addr), h);
230}
231
232static unsigned long test_16(unsigned long addr, unsigned long h,
233 unsigned long ignore)
234{
235 return get_field(__raw_readw(addr), h);
236}
237
238static unsigned long test_32(unsigned long addr, unsigned long h,
239 unsigned long ignore)
240{
241 return get_field(__raw_readl(addr), h);
242}
243
244static unsigned long write_8(unsigned long addr, unsigned long h,
245 unsigned long data)
181{ 246{
182 __raw_writeb(set_field(0, data, h), addr); 247 __raw_writeb(set_field(0, data, h), addr);
183 (void)__raw_readb(addr); /* Defeat write posting */ 248 (void)__raw_readb(addr); /* Defeat write posting */
249 return 0;
184} 250}
185 251
186static void write_16(unsigned long addr, unsigned long h, unsigned long data) 252static unsigned long write_16(unsigned long addr, unsigned long h,
253 unsigned long data)
187{ 254{
188 __raw_writew(set_field(0, data, h), addr); 255 __raw_writew(set_field(0, data, h), addr);
189 (void)__raw_readw(addr); /* Defeat write posting */ 256 (void)__raw_readw(addr); /* Defeat write posting */
257 return 0;
190} 258}
191 259
192static void write_32(unsigned long addr, unsigned long h, unsigned long data) 260static unsigned long write_32(unsigned long addr, unsigned long h,
261 unsigned long data)
193{ 262{
194 __raw_writel(set_field(0, data, h), addr); 263 __raw_writel(set_field(0, data, h), addr);
195 (void)__raw_readl(addr); /* Defeat write posting */ 264 (void)__raw_readl(addr); /* Defeat write posting */
265 return 0;
196} 266}
197 267
198static void modify_8(unsigned long addr, unsigned long h, unsigned long data) 268static unsigned long modify_8(unsigned long addr, unsigned long h,
269 unsigned long data)
199{ 270{
200 unsigned long flags; 271 unsigned long flags;
201 local_irq_save(flags); 272 local_irq_save(flags);
202 __raw_writeb(set_field(__raw_readb(addr), data, h), addr); 273 __raw_writeb(set_field(__raw_readb(addr), data, h), addr);
203 (void)__raw_readb(addr); /* Defeat write posting */ 274 (void)__raw_readb(addr); /* Defeat write posting */
204 local_irq_restore(flags); 275 local_irq_restore(flags);
276 return 0;
205} 277}
206 278
207static void modify_16(unsigned long addr, unsigned long h, unsigned long data) 279static unsigned long modify_16(unsigned long addr, unsigned long h,
280 unsigned long data)
208{ 281{
209 unsigned long flags; 282 unsigned long flags;
210 local_irq_save(flags); 283 local_irq_save(flags);
211 __raw_writew(set_field(__raw_readw(addr), data, h), addr); 284 __raw_writew(set_field(__raw_readw(addr), data, h), addr);
212 (void)__raw_readw(addr); /* Defeat write posting */ 285 (void)__raw_readw(addr); /* Defeat write posting */
213 local_irq_restore(flags); 286 local_irq_restore(flags);
287 return 0;
214} 288}
215 289
216static void modify_32(unsigned long addr, unsigned long h, unsigned long data) 290static unsigned long modify_32(unsigned long addr, unsigned long h,
291 unsigned long data)
217{ 292{
218 unsigned long flags; 293 unsigned long flags;
219 local_irq_save(flags); 294 local_irq_save(flags);
220 __raw_writel(set_field(__raw_readl(addr), data, h), addr); 295 __raw_writel(set_field(__raw_readl(addr), data, h), addr);
221 (void)__raw_readl(addr); /* Defeat write posting */ 296 (void)__raw_readl(addr); /* Defeat write posting */
222 local_irq_restore(flags); 297 local_irq_restore(flags);
298 return 0;
223} 299}
224 300
225enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 }; 301enum {
302 REG_FN_ERR = 0,
303 REG_FN_TEST_BASE = 1,
304 REG_FN_WRITE_BASE = 5,
305 REG_FN_MODIFY_BASE = 9
306};
226 307
227static void (*intc_reg_fns[])(unsigned long addr, 308static unsigned long (*intc_reg_fns[])(unsigned long addr,
228 unsigned long h, 309 unsigned long h,
229 unsigned long data) = { 310 unsigned long data) = {
311 [REG_FN_TEST_BASE + 0] = test_8,
312 [REG_FN_TEST_BASE + 1] = test_16,
313 [REG_FN_TEST_BASE + 3] = test_32,
230 [REG_FN_WRITE_BASE + 0] = write_8, 314 [REG_FN_WRITE_BASE + 0] = write_8,
231 [REG_FN_WRITE_BASE + 1] = write_16, 315 [REG_FN_WRITE_BASE + 1] = write_16,
232 [REG_FN_WRITE_BASE + 3] = write_32, 316 [REG_FN_WRITE_BASE + 3] = write_32,
@@ -242,42 +326,42 @@ enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
242 MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */ 326 MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
243}; 327};
244 328
245static void intc_mode_field(unsigned long addr, 329static unsigned long intc_mode_field(unsigned long addr,
246 unsigned long handle, 330 unsigned long handle,
247 void (*fn)(unsigned long, 331 unsigned long (*fn)(unsigned long,
248 unsigned long, 332 unsigned long,
249 unsigned long), 333 unsigned long),
250 unsigned int irq) 334 unsigned int irq)
251{ 335{
252 fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1)); 336 return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
253} 337}
254 338
255static void intc_mode_zero(unsigned long addr, 339static unsigned long intc_mode_zero(unsigned long addr,
256 unsigned long handle, 340 unsigned long handle,
257 void (*fn)(unsigned long, 341 unsigned long (*fn)(unsigned long,
258 unsigned long, 342 unsigned long,
259 unsigned long), 343 unsigned long),
260 unsigned int irq) 344 unsigned int irq)
261{ 345{
262 fn(addr, handle, 0); 346 return fn(addr, handle, 0);
263} 347}
264 348
265static void intc_mode_prio(unsigned long addr, 349static unsigned long intc_mode_prio(unsigned long addr,
266 unsigned long handle, 350 unsigned long handle,
267 void (*fn)(unsigned long, 351 unsigned long (*fn)(unsigned long,
268 unsigned long, 352 unsigned long,
269 unsigned long), 353 unsigned long),
270 unsigned int irq) 354 unsigned int irq)
271{ 355{
272 fn(addr, handle, intc_prio_level[irq]); 356 return fn(addr, handle, intc_prio_level[irq]);
273} 357}
274 358
275static void (*intc_enable_fns[])(unsigned long addr, 359static unsigned long (*intc_enable_fns[])(unsigned long addr,
276 unsigned long handle, 360 unsigned long handle,
277 void (*fn)(unsigned long, 361 unsigned long (*fn)(unsigned long,
278 unsigned long, 362 unsigned long,
279 unsigned long), 363 unsigned long),
280 unsigned int irq) = { 364 unsigned int irq) = {
281 [MODE_ENABLE_REG] = intc_mode_field, 365 [MODE_ENABLE_REG] = intc_mode_field,
282 [MODE_MASK_REG] = intc_mode_zero, 366 [MODE_MASK_REG] = intc_mode_zero,
283 [MODE_DUAL_REG] = intc_mode_field, 367 [MODE_DUAL_REG] = intc_mode_field,
@@ -285,9 +369,9 @@ static void (*intc_enable_fns[])(unsigned long addr,
285 [MODE_PCLR_REG] = intc_mode_prio, 369 [MODE_PCLR_REG] = intc_mode_prio,
286}; 370};
287 371
288static void (*intc_disable_fns[])(unsigned long addr, 372static unsigned long (*intc_disable_fns[])(unsigned long addr,
289 unsigned long handle, 373 unsigned long handle,
290 void (*fn)(unsigned long, 374 unsigned long (*fn)(unsigned long,
291 unsigned long, 375 unsigned long,
292 unsigned long), 376 unsigned long),
293 unsigned int irq) = { 377 unsigned int irq) = {
@@ -421,12 +505,13 @@ static void intc_disable(unsigned int irq)
421 } 505 }
422} 506}
423 507
424static void (*intc_enable_noprio_fns[])(unsigned long addr, 508static unsigned long
425 unsigned long handle, 509(*intc_enable_noprio_fns[])(unsigned long addr,
426 void (*fn)(unsigned long, 510 unsigned long handle,
427 unsigned long, 511 unsigned long (*fn)(unsigned long,
428 unsigned long), 512 unsigned long,
429 unsigned int irq) = { 513 unsigned long),
514 unsigned int irq) = {
430 [MODE_ENABLE_REG] = intc_mode_field, 515 [MODE_ENABLE_REG] = intc_mode_field,
431 [MODE_MASK_REG] = intc_mode_zero, 516 [MODE_MASK_REG] = intc_mode_zero,
432 [MODE_DUAL_REG] = intc_mode_field, 517 [MODE_DUAL_REG] = intc_mode_field,
@@ -439,8 +524,9 @@ static void intc_enable_disable(struct intc_desc_int *d,
439{ 524{
440 unsigned long addr; 525 unsigned long addr;
441 unsigned int cpu; 526 unsigned int cpu;
442 void (*fn)(unsigned long, unsigned long, 527 unsigned long (*fn)(unsigned long, unsigned long,
443 void (*)(unsigned long, unsigned long, unsigned long), 528 unsigned long (*)(unsigned long, unsigned long,
529 unsigned long),
444 unsigned int); 530 unsigned int);
445 531
446 if (do_enable) { 532 if (do_enable) {
@@ -861,6 +947,186 @@ unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id)
861} 947}
862EXPORT_SYMBOL_GPL(intc_irq_lookup); 948EXPORT_SYMBOL_GPL(intc_irq_lookup);
863 949
950static int add_virq_to_pirq(unsigned int irq, unsigned int virq)
951{
952 struct intc_virq_list **last, *entry;
953 struct irq_desc *desc = irq_to_desc(irq);
954
955 /* scan for duplicates */
956 last = (struct intc_virq_list **)&desc->handler_data;
957 for_each_virq(entry, desc->handler_data) {
958 if (entry->irq == virq)
959 return 0;
960 last = &entry->next;
961 }
962
963 entry = kzalloc(sizeof(struct intc_virq_list), GFP_ATOMIC);
964 if (!entry) {
965 pr_err("can't allocate VIRQ mapping for %d\n", virq);
966 return -ENOMEM;
967 }
968
969 entry->irq = virq;
970
971 *last = entry;
972
973 return 0;
974}
975
976static void intc_virq_handler(unsigned int irq, struct irq_desc *desc)
977{
978 struct intc_virq_list *entry, *vlist = get_irq_data(irq);
979 struct intc_desc_int *d = get_intc_desc(irq);
980
981 desc->chip->mask_ack(irq);
982
983 for_each_virq(entry, vlist) {
984 unsigned long addr, handle;
985
986 handle = (unsigned long)get_irq_data(entry->irq);
987 addr = INTC_REG(d, _INTC_ADDR_E(handle), 0);
988
989 if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0))
990 generic_handle_irq(entry->irq);
991 }
992
993 desc->chip->unmask(irq);
994}
995
996static unsigned long __init intc_subgroup_data(struct intc_subgroup *subgroup,
997 struct intc_desc_int *d,
998 unsigned int index)
999{
1000 unsigned int fn = REG_FN_TEST_BASE + (subgroup->reg_width >> 3) - 1;
1001
1002 return _INTC_MK(fn, MODE_ENABLE_REG, intc_get_reg(d, subgroup->reg),
1003 0, 1, (subgroup->reg_width - 1) - index);
1004}
1005
1006#define INTC_TAG_VIRQ_NEEDS_ALLOC 0
1007
1008static void __init intc_subgroup_init_one(struct intc_desc *desc,
1009 struct intc_desc_int *d,
1010 struct intc_subgroup *subgroup)
1011{
1012 struct intc_map_entry *mapped;
1013 unsigned int pirq;
1014 unsigned long flags;
1015 int i;
1016
1017 mapped = radix_tree_lookup(&d->tree, subgroup->parent_id);
1018 if (!mapped) {
1019 WARN_ON(1);
1020 return;
1021 }
1022
1023 pirq = mapped - intc_irq_xlate;
1024
1025 spin_lock_irqsave(&d->lock, flags);
1026
1027 for (i = 0; i < ARRAY_SIZE(subgroup->enum_ids); i++) {
1028 struct intc_subgroup_entry *entry;
1029 int err;
1030
1031 if (!subgroup->enum_ids[i])
1032 continue;
1033
1034 entry = kmalloc(sizeof(*entry), GFP_NOWAIT);
1035 if (!entry)
1036 break;
1037
1038 entry->pirq = pirq;
1039 entry->enum_id = subgroup->enum_ids[i];
1040 entry->handle = intc_subgroup_data(subgroup, d, i);
1041
1042 err = radix_tree_insert(&d->tree, entry->enum_id, entry);
1043 if (unlikely(err < 0))
1044 break;
1045
1046 radix_tree_tag_set(&d->tree, entry->enum_id,
1047 INTC_TAG_VIRQ_NEEDS_ALLOC);
1048 }
1049
1050 spin_unlock_irqrestore(&d->lock, flags);
1051}
1052
1053static void __init intc_subgroup_init(struct intc_desc *desc,
1054 struct intc_desc_int *d)
1055{
1056 int i;
1057
1058 if (!desc->hw.subgroups)
1059 return;
1060
1061 for (i = 0; i < desc->hw.nr_subgroups; i++)
1062 intc_subgroup_init_one(desc, d, desc->hw.subgroups + i);
1063}
1064
1065static void __init intc_subgroup_map(struct intc_desc_int *d)
1066{
1067 struct intc_subgroup_entry *entries[32];
1068 unsigned long flags;
1069 unsigned int nr_found;
1070 int i;
1071
1072 spin_lock_irqsave(&d->lock, flags);
1073
1074restart:
1075 nr_found = radix_tree_gang_lookup_tag_slot(&d->tree,
1076 (void ***)entries, 0, ARRAY_SIZE(entries),
1077 INTC_TAG_VIRQ_NEEDS_ALLOC);
1078
1079 for (i = 0; i < nr_found; i++) {
1080 struct intc_subgroup_entry *entry;
1081 int irq;
1082
1083 entry = radix_tree_deref_slot((void **)entries[i]);
1084 if (unlikely(!entry))
1085 continue;
1086 if (unlikely(entry == RADIX_TREE_RETRY))
1087 goto restart;
1088
1089 irq = create_irq();
1090 if (unlikely(irq < 0)) {
1091 pr_err("no more free IRQs, bailing..\n");
1092 break;
1093 }
1094
1095 pr_info("Setting up a chained VIRQ from %d -> %d\n",
1096 irq, entry->pirq);
1097
1098 spin_lock(&xlate_lock);
1099 intc_irq_xlate[irq].desc = d;
1100 intc_irq_xlate[irq].enum_id = entry->enum_id;
1101 spin_unlock(&xlate_lock);
1102
1103 set_irq_chip_and_handler_name(irq, get_irq_chip(entry->pirq),
1104 handle_simple_irq, "virq");
1105 set_irq_chip_data(irq, get_irq_chip_data(entry->pirq));
1106
1107 set_irq_data(irq, (void *)entry->handle);
1108
1109 set_irq_chained_handler(entry->pirq, intc_virq_handler);
1110 add_virq_to_pirq(entry->pirq, irq);
1111
1112 radix_tree_tag_clear(&d->tree, entry->enum_id,
1113 INTC_TAG_VIRQ_NEEDS_ALLOC);
1114 radix_tree_replace_slot((void **)entries[i],
1115 &intc_irq_xlate[irq]);
1116 }
1117
1118 spin_unlock_irqrestore(&d->lock, flags);
1119}
1120
1121void __init intc_finalize(void)
1122{
1123 struct intc_desc_int *d;
1124
1125 list_for_each_entry(d, &intc_list, list)
1126 if (radix_tree_tagged(&d->tree, INTC_TAG_VIRQ_NEEDS_ALLOC))
1127 intc_subgroup_map(d);
1128}
1129
864static void __init intc_register_irq(struct intc_desc *desc, 1130static void __init intc_register_irq(struct intc_desc *desc,
865 struct intc_desc_int *d, 1131 struct intc_desc_int *d,
866 intc_enum enum_id, 1132 intc_enum enum_id,
@@ -868,6 +1134,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
868{ 1134{
869 struct intc_handle_int *hp; 1135 struct intc_handle_int *hp;
870 unsigned int data[2], primary; 1136 unsigned int data[2], primary;
1137 unsigned long flags;
871 1138
872 /* 1139 /*
873 * Register the IRQ position with the global IRQ map, then insert 1140 * Register the IRQ position with the global IRQ map, then insert
@@ -875,9 +1142,9 @@ static void __init intc_register_irq(struct intc_desc *desc,
875 */ 1142 */
876 set_bit(irq, intc_irq_map); 1143 set_bit(irq, intc_irq_map);
877 1144
878 mutex_lock(&irq_xlate_mutex); 1145 spin_lock_irqsave(&xlate_lock, flags);
879 radix_tree_insert(&d->tree, enum_id, &intc_irq_xlate[irq]); 1146 radix_tree_insert(&d->tree, enum_id, &intc_irq_xlate[irq]);
880 mutex_unlock(&irq_xlate_mutex); 1147 spin_unlock_irqrestore(&xlate_lock, flags);
881 1148
882 /* 1149 /*
883 * Prefer single interrupt source bitmap over other combinations: 1150 * Prefer single interrupt source bitmap over other combinations:
@@ -957,9 +1224,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
957 dist_handle[irq] = intc_dist_data(desc, d, enum_id); 1224 dist_handle[irq] = intc_dist_data(desc, d, enum_id);
958#endif 1225#endif
959 1226
960#ifdef CONFIG_ARM 1227 activate_irq(irq);
961 set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
962#endif
963} 1228}
964 1229
965static unsigned int __init save_reg(struct intc_desc_int *d, 1230static unsigned int __init save_reg(struct intc_desc_int *d,
@@ -980,11 +1245,6 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
980 return 0; 1245 return 0;
981} 1246}
982 1247
983static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
984{
985 generic_handle_irq((unsigned int)get_irq_data(irq));
986}
987
988int __init register_intc_controller(struct intc_desc *desc) 1248int __init register_intc_controller(struct intc_desc *desc)
989{ 1249{
990 unsigned int i, k, smp; 1250 unsigned int i, k, smp;
@@ -1000,7 +1260,11 @@ int __init register_intc_controller(struct intc_desc *desc)
1000 goto err0; 1260 goto err0;
1001 1261
1002 INIT_LIST_HEAD(&d->list); 1262 INIT_LIST_HEAD(&d->list);
1003 list_add(&d->list, &intc_list); 1263 list_add_tail(&d->list, &intc_list);
1264
1265 spin_lock_init(&d->lock);
1266
1267 d->index = nr_intc_controllers;
1004 1268
1005 if (desc->num_resources) { 1269 if (desc->num_resources) {
1006 d->nr_windows = desc->num_resources; 1270 d->nr_windows = desc->num_resources;
@@ -1029,6 +1293,7 @@ int __init register_intc_controller(struct intc_desc *desc)
1029 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; 1293 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
1030 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; 1294 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
1031 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; 1295 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
1296 d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0;
1032 1297
1033 d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); 1298 d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
1034 if (!d->reg) 1299 if (!d->reg)
@@ -1075,6 +1340,11 @@ int __init register_intc_controller(struct intc_desc *desc)
1075 k += save_reg(d, k, hw->sense_regs[i].reg, 0); 1340 k += save_reg(d, k, hw->sense_regs[i].reg, 0);
1076 } 1341 }
1077 1342
1343 if (hw->subgroups)
1344 for (i = 0; i < hw->nr_subgroups; i++)
1345 if (hw->subgroups[i].reg)
1346 k+= save_reg(d, k, hw->subgroups[i].reg, 0);
1347
1078 d->chip.name = desc->name; 1348 d->chip.name = desc->name;
1079 d->chip.mask = intc_disable; 1349 d->chip.mask = intc_disable;
1080 d->chip.unmask = intc_enable; 1350 d->chip.unmask = intc_enable;
@@ -1109,6 +1379,7 @@ int __init register_intc_controller(struct intc_desc *desc)
1109 for (i = 0; i < hw->nr_vectors; i++) { 1379 for (i = 0; i < hw->nr_vectors; i++) {
1110 struct intc_vect *vect = hw->vectors + i; 1380 struct intc_vect *vect = hw->vectors + i;
1111 unsigned int irq = evt2irq(vect->vect); 1381 unsigned int irq = evt2irq(vect->vect);
1382 unsigned long flags;
1112 struct irq_desc *irq_desc; 1383 struct irq_desc *irq_desc;
1113 1384
1114 if (!vect->enum_id) 1385 if (!vect->enum_id)
@@ -1120,8 +1391,10 @@ int __init register_intc_controller(struct intc_desc *desc)
1120 continue; 1391 continue;
1121 } 1392 }
1122 1393
1394 spin_lock_irqsave(&xlate_lock, flags);
1123 intc_irq_xlate[irq].enum_id = vect->enum_id; 1395 intc_irq_xlate[irq].enum_id = vect->enum_id;
1124 intc_irq_xlate[irq].desc = d; 1396 intc_irq_xlate[irq].desc = d;
1397 spin_unlock_irqrestore(&xlate_lock, flags);
1125 1398
1126 intc_register_irq(desc, d, vect->enum_id, irq); 1399 intc_register_irq(desc, d, vect->enum_id, irq);
1127 1400
@@ -1152,10 +1425,14 @@ int __init register_intc_controller(struct intc_desc *desc)
1152 } 1425 }
1153 } 1426 }
1154 1427
1428 intc_subgroup_init(desc, d);
1429
1155 /* enable bits matching force_enable after registering irqs */ 1430 /* enable bits matching force_enable after registering irqs */
1156 if (desc->force_enable) 1431 if (desc->force_enable)
1157 intc_enable_disable_enum(desc, d, desc->force_enable, 1); 1432 intc_enable_disable_enum(desc, d, desc->force_enable, 1);
1158 1433
1434 nr_intc_controllers++;
1435
1159 return 0; 1436 return 0;
1160err5: 1437err5:
1161 kfree(d->prio); 1438 kfree(d->prio);
@@ -1353,7 +1630,6 @@ static int __init register_intc_sysdevs(void)
1353{ 1630{
1354 struct intc_desc_int *d; 1631 struct intc_desc_int *d;
1355 int error; 1632 int error;
1356 int id = 0;
1357 1633
1358 error = sysdev_class_register(&intc_sysdev_class); 1634 error = sysdev_class_register(&intc_sysdev_class);
1359#ifdef CONFIG_INTC_USERIMASK 1635#ifdef CONFIG_INTC_USERIMASK
@@ -1363,7 +1639,7 @@ static int __init register_intc_sysdevs(void)
1363#endif 1639#endif
1364 if (!error) { 1640 if (!error) {
1365 list_for_each_entry(d, &intc_list, list) { 1641 list_for_each_entry(d, &intc_list, list) {
1366 d->sysdev.id = id; 1642 d->sysdev.id = d->index;
1367 d->sysdev.cls = &intc_sysdev_class; 1643 d->sysdev.cls = &intc_sysdev_class;
1368 error = sysdev_register(&d->sysdev); 1644 error = sysdev_register(&d->sysdev);
1369 if (error == 0) 1645 if (error == 0)
@@ -1371,8 +1647,6 @@ static int __init register_intc_sysdevs(void)
1371 &attr_name); 1647 &attr_name);
1372 if (error) 1648 if (error)
1373 break; 1649 break;
1374
1375 id++;
1376 } 1650 }
1377 } 1651 }
1378 1652
@@ -1422,9 +1696,7 @@ out_unlock:
1422 1696
1423 if (irq > 0) { 1697 if (irq > 0) {
1424 dynamic_irq_init(irq); 1698 dynamic_irq_init(irq);
1425#ifdef CONFIG_ARM 1699 activate_irq(irq);
1426 set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
1427#endif
1428 } 1700 }
1429 1701
1430 return irq; 1702 return irq;
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index d40fd77fa75c..04134a6c7b52 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -20,6 +20,12 @@ struct intc_group {
20 20
21#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } } 21#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } }
22 22
23struct intc_subgroup {
24 unsigned long reg, reg_width;
25 intc_enum parent_id;
26 intc_enum enum_ids[32];
27};
28
23struct intc_mask_reg { 29struct intc_mask_reg {
24 unsigned long set_reg, clr_reg, reg_width; 30 unsigned long set_reg, clr_reg, reg_width;
25 intc_enum enum_ids[32]; 31 intc_enum enum_ids[32];
@@ -69,9 +75,12 @@ struct intc_hw_desc {
69 unsigned int nr_sense_regs; 75 unsigned int nr_sense_regs;
70 struct intc_mask_reg *ack_regs; 76 struct intc_mask_reg *ack_regs;
71 unsigned int nr_ack_regs; 77 unsigned int nr_ack_regs;
78 struct intc_subgroup *subgroups;
79 unsigned int nr_subgroups;
72}; 80};
73 81
74#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a) 82#define _INTC_ARRAY(a) a, a == NULL ? 0 : sizeof(a)/sizeof(*a)
83
75#define INTC_HW_DESC(vectors, groups, mask_regs, \ 84#define INTC_HW_DESC(vectors, groups, mask_regs, \
76 prio_regs, sense_regs, ack_regs) \ 85 prio_regs, sense_regs, ack_regs) \
77{ \ 86{ \
@@ -109,6 +118,7 @@ int __init register_intc_controller(struct intc_desc *desc);
109void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs); 118void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
110int intc_set_priority(unsigned int irq, unsigned int prio); 119int intc_set_priority(unsigned int irq, unsigned int prio);
111unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id); 120unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id);
121void intc_finalize(void);
112 122
113#ifdef CONFIG_INTC_USERIMASK 123#ifdef CONFIG_INTC_USERIMASK
114int register_intc_userimask(unsigned long addr); 124int register_intc_userimask(unsigned long addr);