diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 201 |
1 files changed, 122 insertions, 79 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 8c7e8528e7c4..4e9ccb1015de 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -154,7 +154,7 @@ static inline unsigned int mpic_processor_id(struct mpic *mpic) | |||
154 | { | 154 | { |
155 | unsigned int cpu = 0; | 155 | unsigned int cpu = 0; |
156 | 156 | ||
157 | if (mpic->flags & MPIC_PRIMARY) | 157 | if (!(mpic->flags & MPIC_SECONDARY)) |
158 | cpu = hard_smp_processor_id(); | 158 | cpu = hard_smp_processor_id(); |
159 | 159 | ||
160 | return cpu; | 160 | return cpu; |
@@ -315,29 +315,25 @@ static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, | |||
315 | } | 315 | } |
316 | 316 | ||
317 | #ifdef CONFIG_PPC_DCR | 317 | #ifdef CONFIG_PPC_DCR |
318 | static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node, | 318 | static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, |
319 | struct mpic_reg_bank *rb, | ||
320 | unsigned int offset, unsigned int size) | 319 | unsigned int offset, unsigned int size) |
321 | { | 320 | { |
322 | const u32 *dbasep; | 321 | phys_addr_t phys_addr = dcr_resource_start(mpic->node, 0); |
323 | 322 | rb->dhost = dcr_map(mpic->node, phys_addr + offset, size); | |
324 | dbasep = of_get_property(node, "dcr-reg", NULL); | ||
325 | |||
326 | rb->dhost = dcr_map(node, *dbasep + offset, size); | ||
327 | BUG_ON(!DCR_MAP_OK(rb->dhost)); | 323 | BUG_ON(!DCR_MAP_OK(rb->dhost)); |
328 | } | 324 | } |
329 | 325 | ||
330 | static inline void mpic_map(struct mpic *mpic, struct device_node *node, | 326 | static inline void mpic_map(struct mpic *mpic, |
331 | phys_addr_t phys_addr, struct mpic_reg_bank *rb, | 327 | phys_addr_t phys_addr, struct mpic_reg_bank *rb, |
332 | unsigned int offset, unsigned int size) | 328 | unsigned int offset, unsigned int size) |
333 | { | 329 | { |
334 | if (mpic->flags & MPIC_USES_DCR) | 330 | if (mpic->flags & MPIC_USES_DCR) |
335 | _mpic_map_dcr(mpic, node, rb, offset, size); | 331 | _mpic_map_dcr(mpic, rb, offset, size); |
336 | else | 332 | else |
337 | _mpic_map_mmio(mpic, phys_addr, rb, offset, size); | 333 | _mpic_map_mmio(mpic, phys_addr, rb, offset, size); |
338 | } | 334 | } |
339 | #else /* CONFIG_PPC_DCR */ | 335 | #else /* CONFIG_PPC_DCR */ |
340 | #define mpic_map(m,n,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) | 336 | #define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) |
341 | #endif /* !CONFIG_PPC_DCR */ | 337 | #endif /* !CONFIG_PPC_DCR */ |
342 | 338 | ||
343 | 339 | ||
@@ -901,7 +897,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) | |||
901 | if (vold != vnew) | 897 | if (vold != vnew) |
902 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); | 898 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); |
903 | 899 | ||
904 | return IRQ_SET_MASK_OK_NOCOPY;; | 900 | return IRQ_SET_MASK_OK_NOCOPY; |
905 | } | 901 | } |
906 | 902 | ||
907 | void mpic_set_vector(unsigned int virq, unsigned int vector) | 903 | void mpic_set_vector(unsigned int virq, unsigned int vector) |
@@ -990,7 +986,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
990 | 986 | ||
991 | #ifdef CONFIG_SMP | 987 | #ifdef CONFIG_SMP |
992 | else if (hw >= mpic->ipi_vecs[0]) { | 988 | else if (hw >= mpic->ipi_vecs[0]) { |
993 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | 989 | WARN_ON(mpic->flags & MPIC_SECONDARY); |
994 | 990 | ||
995 | DBG("mpic: mapping as IPI\n"); | 991 | DBG("mpic: mapping as IPI\n"); |
996 | irq_set_chip_data(virq, mpic); | 992 | irq_set_chip_data(virq, mpic); |
@@ -1001,7 +997,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
1001 | #endif /* CONFIG_SMP */ | 997 | #endif /* CONFIG_SMP */ |
1002 | 998 | ||
1003 | if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { | 999 | if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { |
1004 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | 1000 | WARN_ON(mpic->flags & MPIC_SECONDARY); |
1005 | 1001 | ||
1006 | DBG("mpic: mapping as timer\n"); | 1002 | DBG("mpic: mapping as timer\n"); |
1007 | irq_set_chip_data(virq, mpic); | 1003 | irq_set_chip_data(virq, mpic); |
@@ -1115,17 +1111,28 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | |||
1115 | return 0; | 1111 | return 0; |
1116 | } | 1112 | } |
1117 | 1113 | ||
1114 | /* IRQ handler for a secondary MPIC cascaded from another IRQ controller */ | ||
1115 | static void mpic_cascade(unsigned int irq, struct irq_desc *desc) | ||
1116 | { | ||
1117 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
1118 | struct mpic *mpic = irq_desc_get_handler_data(desc); | ||
1119 | unsigned int virq; | ||
1120 | |||
1121 | BUG_ON(!(mpic->flags & MPIC_SECONDARY)); | ||
1122 | |||
1123 | virq = mpic_get_one_irq(mpic); | ||
1124 | if (virq != NO_IRQ) | ||
1125 | generic_handle_irq(virq); | ||
1126 | |||
1127 | chip->irq_eoi(&desc->irq_data); | ||
1128 | } | ||
1129 | |||
1118 | static struct irq_host_ops mpic_host_ops = { | 1130 | static struct irq_host_ops mpic_host_ops = { |
1119 | .match = mpic_host_match, | 1131 | .match = mpic_host_match, |
1120 | .map = mpic_host_map, | 1132 | .map = mpic_host_map, |
1121 | .xlate = mpic_host_xlate, | 1133 | .xlate = mpic_host_xlate, |
1122 | }; | 1134 | }; |
1123 | 1135 | ||
1124 | static int mpic_reset_prohibited(struct device_node *node) | ||
1125 | { | ||
1126 | return node && of_get_property(node, "pic-no-reset", NULL); | ||
1127 | } | ||
1128 | |||
1129 | /* | 1136 | /* |
1130 | * Exported functions | 1137 | * Exported functions |
1131 | */ | 1138 | */ |
@@ -1137,27 +1144,60 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1137 | unsigned int irq_count, | 1144 | unsigned int irq_count, |
1138 | const char *name) | 1145 | const char *name) |
1139 | { | 1146 | { |
1140 | struct mpic *mpic; | 1147 | int i, psize, intvec_top; |
1141 | u32 greg_feature; | 1148 | struct mpic *mpic; |
1142 | const char *vers; | 1149 | u32 greg_feature; |
1143 | int i; | 1150 | const char *vers; |
1144 | int intvec_top; | 1151 | const u32 *psrc; |
1145 | u64 paddr = phys_addr; | 1152 | |
1153 | /* Default MPIC search parameters */ | ||
1154 | static const struct of_device_id __initconst mpic_device_id[] = { | ||
1155 | { .type = "open-pic", }, | ||
1156 | { .compatible = "open-pic", }, | ||
1157 | {}, | ||
1158 | }; | ||
1159 | |||
1160 | /* | ||
1161 | * If we were not passed a device-tree node, then perform the default | ||
1162 | * search for standardized a standardized OpenPIC. | ||
1163 | */ | ||
1164 | if (node) { | ||
1165 | node = of_node_get(node); | ||
1166 | } else { | ||
1167 | node = of_find_matching_node(NULL, mpic_device_id); | ||
1168 | if (!node) | ||
1169 | return NULL; | ||
1170 | } | ||
1171 | |||
1172 | /* Pick the physical address from the device tree if unspecified */ | ||
1173 | if (!phys_addr) { | ||
1174 | /* Check if it is DCR-based */ | ||
1175 | if (of_get_property(node, "dcr-reg", NULL)) { | ||
1176 | flags |= MPIC_USES_DCR; | ||
1177 | } else { | ||
1178 | struct resource r; | ||
1179 | if (of_address_to_resource(node, 0, &r)) | ||
1180 | goto err_of_node_put; | ||
1181 | phys_addr = r.start; | ||
1182 | } | ||
1183 | } | ||
1146 | 1184 | ||
1147 | mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); | 1185 | mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); |
1148 | if (mpic == NULL) | 1186 | if (mpic == NULL) |
1149 | return NULL; | 1187 | goto err_of_node_put; |
1150 | 1188 | ||
1151 | mpic->name = name; | 1189 | mpic->name = name; |
1190 | mpic->node = node; | ||
1191 | mpic->paddr = phys_addr; | ||
1152 | 1192 | ||
1153 | mpic->hc_irq = mpic_irq_chip; | 1193 | mpic->hc_irq = mpic_irq_chip; |
1154 | mpic->hc_irq.name = name; | 1194 | mpic->hc_irq.name = name; |
1155 | if (flags & MPIC_PRIMARY) | 1195 | if (!(flags & MPIC_SECONDARY)) |
1156 | mpic->hc_irq.irq_set_affinity = mpic_set_affinity; | 1196 | mpic->hc_irq.irq_set_affinity = mpic_set_affinity; |
1157 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 1197 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
1158 | mpic->hc_ht_irq = mpic_irq_ht_chip; | 1198 | mpic->hc_ht_irq = mpic_irq_ht_chip; |
1159 | mpic->hc_ht_irq.name = name; | 1199 | mpic->hc_ht_irq.name = name; |
1160 | if (flags & MPIC_PRIMARY) | 1200 | if (!(flags & MPIC_SECONDARY)) |
1161 | mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; | 1201 | mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; |
1162 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ | 1202 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ |
1163 | 1203 | ||
@@ -1194,28 +1234,22 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1194 | mpic->spurious_vec = intvec_top; | 1234 | mpic->spurious_vec = intvec_top; |
1195 | 1235 | ||
1196 | /* Check for "big-endian" in device-tree */ | 1236 | /* Check for "big-endian" in device-tree */ |
1197 | if (node && of_get_property(node, "big-endian", NULL) != NULL) | 1237 | if (of_get_property(mpic->node, "big-endian", NULL) != NULL) |
1198 | mpic->flags |= MPIC_BIG_ENDIAN; | 1238 | mpic->flags |= MPIC_BIG_ENDIAN; |
1199 | if (node && of_device_is_compatible(node, "fsl,mpic")) | 1239 | if (of_device_is_compatible(mpic->node, "fsl,mpic")) |
1200 | mpic->flags |= MPIC_FSL; | 1240 | mpic->flags |= MPIC_FSL; |
1201 | 1241 | ||
1202 | /* Look for protected sources */ | 1242 | /* Look for protected sources */ |
1203 | if (node) { | 1243 | psrc = of_get_property(mpic->node, "protected-sources", &psize); |
1204 | int psize; | 1244 | if (psrc) { |
1205 | unsigned int bits, mapsize; | 1245 | /* Allocate a bitmap with one bit per interrupt */ |
1206 | const u32 *psrc = | 1246 | unsigned int mapsize = BITS_TO_LONGS(intvec_top + 1); |
1207 | of_get_property(node, "protected-sources", &psize); | 1247 | mpic->protected = kzalloc(mapsize*sizeof(long), GFP_KERNEL); |
1208 | if (psrc) { | 1248 | BUG_ON(mpic->protected == NULL); |
1209 | psize /= 4; | 1249 | for (i = 0; i < psize/sizeof(u32); i++) { |
1210 | bits = intvec_top + 1; | 1250 | if (psrc[i] > intvec_top) |
1211 | mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long); | 1251 | continue; |
1212 | mpic->protected = kzalloc(mapsize, GFP_KERNEL); | 1252 | __set_bit(psrc[i], mpic->protected); |
1213 | BUG_ON(mpic->protected == NULL); | ||
1214 | for (i = 0; i < psize; i++) { | ||
1215 | if (psrc[i] > intvec_top) | ||
1216 | continue; | ||
1217 | __set_bit(psrc[i], mpic->protected); | ||
1218 | } | ||
1219 | } | 1253 | } |
1220 | } | 1254 | } |
1221 | 1255 | ||
@@ -1224,42 +1258,32 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1224 | #endif | 1258 | #endif |
1225 | 1259 | ||
1226 | /* default register type */ | 1260 | /* default register type */ |
1227 | mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? | 1261 | if (flags & MPIC_BIG_ENDIAN) |
1228 | mpic_access_mmio_be : mpic_access_mmio_le; | 1262 | mpic->reg_type = mpic_access_mmio_be; |
1229 | 1263 | else | |
1230 | /* If no physical address is passed in, a device-node is mandatory */ | 1264 | mpic->reg_type = mpic_access_mmio_le; |
1231 | BUG_ON(paddr == 0 && node == NULL); | ||
1232 | 1265 | ||
1233 | /* If no physical address passed in, check if it's dcr based */ | 1266 | /* |
1234 | if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL) { | 1267 | * An MPIC with a "dcr-reg" property must be accessed that way, but |
1268 | * only if the kernel includes DCR support. | ||
1269 | */ | ||
1235 | #ifdef CONFIG_PPC_DCR | 1270 | #ifdef CONFIG_PPC_DCR |
1236 | mpic->flags |= MPIC_USES_DCR; | 1271 | if (flags & MPIC_USES_DCR) |
1237 | mpic->reg_type = mpic_access_dcr; | 1272 | mpic->reg_type = mpic_access_dcr; |
1238 | #else | 1273 | #else |
1239 | BUG(); | 1274 | BUG_ON(flags & MPIC_USES_DCR); |
1240 | #endif /* CONFIG_PPC_DCR */ | 1275 | #endif |
1241 | } | ||
1242 | |||
1243 | /* If the MPIC is not DCR based, and no physical address was passed | ||
1244 | * in, try to obtain one | ||
1245 | */ | ||
1246 | if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { | ||
1247 | const u32 *reg = of_get_property(node, "reg", NULL); | ||
1248 | BUG_ON(reg == NULL); | ||
1249 | paddr = of_translate_address(node, reg); | ||
1250 | BUG_ON(paddr == OF_BAD_ADDR); | ||
1251 | } | ||
1252 | 1276 | ||
1253 | /* Map the global registers */ | 1277 | /* Map the global registers */ |
1254 | mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); | 1278 | mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); |
1255 | mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); | 1279 | mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); |
1256 | 1280 | ||
1257 | /* Reset */ | 1281 | /* Reset */ |
1258 | 1282 | ||
1259 | /* When using a device-node, reset requests are only honored if the MPIC | 1283 | /* When using a device-node, reset requests are only honored if the MPIC |
1260 | * is allowed to reset. | 1284 | * is allowed to reset. |
1261 | */ | 1285 | */ |
1262 | if (mpic_reset_prohibited(node)) | 1286 | if (of_get_property(mpic->node, "pic-no-reset", NULL)) |
1263 | mpic->flags |= MPIC_NO_RESET; | 1287 | mpic->flags |= MPIC_NO_RESET; |
1264 | 1288 | ||
1265 | if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { | 1289 | if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { |
@@ -1307,7 +1331,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1307 | for_each_possible_cpu(i) { | 1331 | for_each_possible_cpu(i) { |
1308 | unsigned int cpu = get_hard_smp_processor_id(i); | 1332 | unsigned int cpu = get_hard_smp_processor_id(i); |
1309 | 1333 | ||
1310 | mpic_map(mpic, node, paddr, &mpic->cpuregs[cpu], | 1334 | mpic_map(mpic, mpic->paddr, &mpic->cpuregs[cpu], |
1311 | MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), | 1335 | MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), |
1312 | 0x1000); | 1336 | 0x1000); |
1313 | } | 1337 | } |
@@ -1315,16 +1339,21 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1315 | /* Initialize main ISU if none provided */ | 1339 | /* Initialize main ISU if none provided */ |
1316 | if (mpic->isu_size == 0) { | 1340 | if (mpic->isu_size == 0) { |
1317 | mpic->isu_size = mpic->num_sources; | 1341 | mpic->isu_size = mpic->num_sources; |
1318 | mpic_map(mpic, node, paddr, &mpic->isus[0], | 1342 | mpic_map(mpic, mpic->paddr, &mpic->isus[0], |
1319 | MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); | 1343 | MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); |
1320 | } | 1344 | } |
1321 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); | 1345 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); |
1322 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; | 1346 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; |
1323 | 1347 | ||
1324 | mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, | 1348 | mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR, |
1325 | isu_size ? isu_size : mpic->num_sources, | 1349 | isu_size ? isu_size : mpic->num_sources, |
1326 | &mpic_host_ops, | 1350 | &mpic_host_ops, |
1327 | flags & MPIC_LARGE_VECTORS ? 2048 : 256); | 1351 | flags & MPIC_LARGE_VECTORS ? 2048 : 256); |
1352 | |||
1353 | /* | ||
1354 | * FIXME: The code leaks the MPIC object and mappings here; this | ||
1355 | * is very unlikely to fail but it ought to be fixed anyways. | ||
1356 | */ | ||
1328 | if (mpic->irqhost == NULL) | 1357 | if (mpic->irqhost == NULL) |
1329 | return NULL; | 1358 | return NULL; |
1330 | 1359 | ||
@@ -1347,19 +1376,23 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1347 | } | 1376 | } |
1348 | printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," | 1377 | printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," |
1349 | " max %d CPUs\n", | 1378 | " max %d CPUs\n", |
1350 | name, vers, (unsigned long long)paddr, num_possible_cpus()); | 1379 | name, vers, (unsigned long long)mpic->paddr, num_possible_cpus()); |
1351 | printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", | 1380 | printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", |
1352 | mpic->isu_size, mpic->isu_shift, mpic->isu_mask); | 1381 | mpic->isu_size, mpic->isu_shift, mpic->isu_mask); |
1353 | 1382 | ||
1354 | mpic->next = mpics; | 1383 | mpic->next = mpics; |
1355 | mpics = mpic; | 1384 | mpics = mpic; |
1356 | 1385 | ||
1357 | if (flags & MPIC_PRIMARY) { | 1386 | if (!(flags & MPIC_SECONDARY)) { |
1358 | mpic_primary = mpic; | 1387 | mpic_primary = mpic; |
1359 | irq_set_default_host(mpic->irqhost); | 1388 | irq_set_default_host(mpic->irqhost); |
1360 | } | 1389 | } |
1361 | 1390 | ||
1362 | return mpic; | 1391 | return mpic; |
1392 | |||
1393 | err_of_node_put: | ||
1394 | of_node_put(node); | ||
1395 | return NULL; | ||
1363 | } | 1396 | } |
1364 | 1397 | ||
1365 | void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | 1398 | void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, |
@@ -1369,7 +1402,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | |||
1369 | 1402 | ||
1370 | BUG_ON(isu_num >= MPIC_MAX_ISU); | 1403 | BUG_ON(isu_num >= MPIC_MAX_ISU); |
1371 | 1404 | ||
1372 | mpic_map(mpic, mpic->irqhost->of_node, | 1405 | mpic_map(mpic, |
1373 | paddr, &mpic->isus[isu_num], 0, | 1406 | paddr, &mpic->isus[isu_num], 0, |
1374 | MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); | 1407 | MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); |
1375 | 1408 | ||
@@ -1385,8 +1418,7 @@ void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) | |||
1385 | 1418 | ||
1386 | void __init mpic_init(struct mpic *mpic) | 1419 | void __init mpic_init(struct mpic *mpic) |
1387 | { | 1420 | { |
1388 | int i; | 1421 | int i, cpu; |
1389 | int cpu; | ||
1390 | 1422 | ||
1391 | BUG_ON(mpic->num_sources == 0); | 1423 | BUG_ON(mpic->num_sources == 0); |
1392 | 1424 | ||
@@ -1424,7 +1456,7 @@ void __init mpic_init(struct mpic *mpic) | |||
1424 | 1456 | ||
1425 | /* Do the HT PIC fixups on U3 broken mpic */ | 1457 | /* Do the HT PIC fixups on U3 broken mpic */ |
1426 | DBG("MPIC flags: %x\n", mpic->flags); | 1458 | DBG("MPIC flags: %x\n", mpic->flags); |
1427 | if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) { | 1459 | if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { |
1428 | mpic_scan_ht_pics(mpic); | 1460 | mpic_scan_ht_pics(mpic); |
1429 | mpic_u3msi_init(mpic); | 1461 | mpic_u3msi_init(mpic); |
1430 | } | 1462 | } |
@@ -1471,6 +1503,17 @@ void __init mpic_init(struct mpic *mpic) | |||
1471 | GFP_KERNEL); | 1503 | GFP_KERNEL); |
1472 | BUG_ON(mpic->save_data == NULL); | 1504 | BUG_ON(mpic->save_data == NULL); |
1473 | #endif | 1505 | #endif |
1506 | |||
1507 | /* Check if this MPIC is chained from a parent interrupt controller */ | ||
1508 | if (mpic->flags & MPIC_SECONDARY) { | ||
1509 | int virq = irq_of_parse_and_map(mpic->node, 0); | ||
1510 | if (virq != NO_IRQ) { | ||
1511 | printk(KERN_INFO "%s: hooking up to IRQ %d\n", | ||
1512 | mpic->node->full_name, virq); | ||
1513 | irq_set_handler_data(virq, mpic); | ||
1514 | irq_set_chained_handler(virq, &mpic_cascade); | ||
1515 | } | ||
1516 | } | ||
1474 | } | 1517 | } |
1475 | 1518 | ||
1476 | void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) | 1519 | void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) |