diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 102 |
1 files changed, 85 insertions, 17 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index bfc6211e5422..9c6e535daad2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * with various broken implementations of this HW. | 6 | * with various broken implementations of this HW. |
7 | * | 7 | * |
8 | * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. | 8 | * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. |
9 | * Copyright 2010-2011 Freescale Semiconductor, Inc. | 9 | * Copyright 2010-2012 Freescale Semiconductor, Inc. |
10 | * | 10 | * |
11 | * This file is subject to the terms and conditions of the GNU General Public | 11 | * This file is subject to the terms and conditions of the GNU General Public |
12 | * License. See the file COPYING in the main directory of this archive | 12 | * License. See the file COPYING in the main directory of this archive |
@@ -221,24 +221,24 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu | |||
221 | _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); | 221 | _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); |
222 | } | 222 | } |
223 | 223 | ||
224 | static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) | 224 | static inline unsigned int mpic_tm_offset(struct mpic *mpic, unsigned int tm) |
225 | { | 225 | { |
226 | unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + | 226 | return (tm >> 2) * MPIC_TIMER_GROUP_STRIDE + |
227 | ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); | 227 | (tm & 3) * MPIC_INFO(TIMER_STRIDE); |
228 | } | ||
228 | 229 | ||
229 | if (tm >= 4) | 230 | static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) |
230 | offset += 0x1000 / 4; | 231 | { |
232 | unsigned int offset = mpic_tm_offset(mpic, tm) + | ||
233 | MPIC_INFO(TIMER_VECTOR_PRI); | ||
231 | 234 | ||
232 | return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); | 235 | return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); |
233 | } | 236 | } |
234 | 237 | ||
235 | static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) | 238 | static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) |
236 | { | 239 | { |
237 | unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + | 240 | unsigned int offset = mpic_tm_offset(mpic, tm) + |
238 | ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); | 241 | MPIC_INFO(TIMER_VECTOR_PRI); |
239 | |||
240 | if (tm >= 4) | ||
241 | offset += 0x1000 / 4; | ||
242 | 242 | ||
243 | _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); | 243 | _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); |
244 | } | 244 | } |
@@ -1026,6 +1026,9 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq, | |||
1026 | return 0; | 1026 | return 0; |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | if (mpic_map_error_int(mpic, virq, hw)) | ||
1030 | return 0; | ||
1031 | |||
1029 | if (hw >= mpic->num_sources) | 1032 | if (hw >= mpic->num_sources) |
1030 | return -EINVAL; | 1033 | return -EINVAL; |
1031 | 1034 | ||
@@ -1085,7 +1088,16 @@ static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct, | |||
1085 | */ | 1088 | */ |
1086 | switch (intspec[2]) { | 1089 | switch (intspec[2]) { |
1087 | case 0: | 1090 | case 0: |
1088 | case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ | 1091 | break; |
1092 | case 1: | ||
1093 | if (!(mpic->flags & MPIC_FSL_HAS_EIMR)) | ||
1094 | break; | ||
1095 | |||
1096 | if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs)) | ||
1097 | return -EINVAL; | ||
1098 | |||
1099 | *out_hwirq = mpic->err_int_vecs[intspec[3]]; | ||
1100 | |||
1089 | break; | 1101 | break; |
1090 | case 2: | 1102 | case 2: |
1091 | if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) | 1103 | if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) |
@@ -1301,6 +1313,42 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1301 | mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); | 1313 | mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); |
1302 | mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); | 1314 | mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); |
1303 | 1315 | ||
1316 | if (mpic->flags & MPIC_FSL) { | ||
1317 | u32 brr1, version; | ||
1318 | int ret; | ||
1319 | |||
1320 | /* | ||
1321 | * Yes, Freescale really did put global registers in the | ||
1322 | * magic per-cpu area -- and they don't even show up in the | ||
1323 | * non-magic per-cpu copies that this driver normally uses. | ||
1324 | */ | ||
1325 | mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs, | ||
1326 | MPIC_CPU_THISBASE, 0x1000); | ||
1327 | |||
1328 | brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs, | ||
1329 | MPIC_FSL_BRR1); | ||
1330 | version = brr1 & MPIC_FSL_BRR1_VER; | ||
1331 | |||
1332 | /* Error interrupt mask register (EIMR) is required for | ||
1333 | * handling individual device error interrupts. EIMR | ||
1334 | * was added in MPIC version 4.1. | ||
1335 | * | ||
1336 | * Over here we reserve vector number space for error | ||
1337 | * interrupt vectors. This space is stolen from the | ||
1338 | * global vector number space, as in case of ipis | ||
1339 | * and timer interrupts. | ||
1340 | * | ||
1341 | * Available vector space = intvec_top - 12, where 12 | ||
1342 | * is the number of vectors which have been consumed by | ||
1343 | * ipis and timer interrupts. | ||
1344 | */ | ||
1345 | if (version >= 0x401) { | ||
1346 | ret = mpic_setup_error_int(mpic, intvec_top - 12); | ||
1347 | if (ret) | ||
1348 | return NULL; | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1304 | /* Reset */ | 1352 | /* Reset */ |
1305 | 1353 | ||
1306 | /* When using a device-node, reset requests are only honored if the MPIC | 1354 | /* When using a device-node, reset requests are only honored if the MPIC |
@@ -1440,6 +1488,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | |||
1440 | void __init mpic_init(struct mpic *mpic) | 1488 | void __init mpic_init(struct mpic *mpic) |
1441 | { | 1489 | { |
1442 | int i, cpu; | 1490 | int i, cpu; |
1491 | int num_timers = 4; | ||
1443 | 1492 | ||
1444 | BUG_ON(mpic->num_sources == 0); | 1493 | BUG_ON(mpic->num_sources == 0); |
1445 | 1494 | ||
@@ -1448,15 +1497,34 @@ void __init mpic_init(struct mpic *mpic) | |||
1448 | /* Set current processor priority to max */ | 1497 | /* Set current processor priority to max */ |
1449 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); | 1498 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); |
1450 | 1499 | ||
1500 | if (mpic->flags & MPIC_FSL) { | ||
1501 | u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs, | ||
1502 | MPIC_FSL_BRR1); | ||
1503 | u32 version = brr1 & MPIC_FSL_BRR1_VER; | ||
1504 | |||
1505 | /* | ||
1506 | * Timer group B is present at the latest in MPIC 3.1 (e.g. | ||
1507 | * mpc8536). It is not present in MPIC 2.0 (e.g. mpc8544). | ||
1508 | * I don't know about the status of intermediate versions (or | ||
1509 | * whether they even exist). | ||
1510 | */ | ||
1511 | if (version >= 0x0301) | ||
1512 | num_timers = 8; | ||
1513 | } | ||
1514 | |||
1515 | /* FSL mpic error interrupt intialization */ | ||
1516 | if (mpic->flags & MPIC_FSL_HAS_EIMR) | ||
1517 | mpic_err_int_init(mpic, MPIC_FSL_ERR_INT); | ||
1518 | |||
1451 | /* Initialize timers to our reserved vectors and mask them for now */ | 1519 | /* Initialize timers to our reserved vectors and mask them for now */ |
1452 | for (i = 0; i < 4; i++) { | 1520 | for (i = 0; i < num_timers; i++) { |
1521 | unsigned int offset = mpic_tm_offset(mpic, i); | ||
1522 | |||
1453 | mpic_write(mpic->tmregs, | 1523 | mpic_write(mpic->tmregs, |
1454 | i * MPIC_INFO(TIMER_STRIDE) + | 1524 | offset + MPIC_INFO(TIMER_DESTINATION), |
1455 | MPIC_INFO(TIMER_DESTINATION), | ||
1456 | 1 << hard_smp_processor_id()); | 1525 | 1 << hard_smp_processor_id()); |
1457 | mpic_write(mpic->tmregs, | 1526 | mpic_write(mpic->tmregs, |
1458 | i * MPIC_INFO(TIMER_STRIDE) + | 1527 | offset + MPIC_INFO(TIMER_VECTOR_PRI), |
1459 | MPIC_INFO(TIMER_VECTOR_PRI), | ||
1460 | MPIC_VECPRI_MASK | | 1528 | MPIC_VECPRI_MASK | |
1461 | (9 << MPIC_VECPRI_PRIORITY_SHIFT) | | 1529 | (9 << MPIC_VECPRI_PRIORITY_SHIFT) | |
1462 | (mpic->timer_vecs[0] + i)); | 1530 | (mpic->timer_vecs[0] + i)); |