diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-27 13:17:30 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-27 13:17:30 -0400 |
commit | 45acab01ca6389371ec39e16844768a60f5f1380 (patch) | |
tree | c2997deab16bdc254f927edfa849d2a4dfb36092 /arch/powerpc | |
parent | c0880dcded3ffe77700184e9d96c110ce0094c11 (diff) | |
parent | 9693ebd4815eefa2b7c8fcc699061a0c8da0c1e7 (diff) |
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
powerpc/fsl_rio: Error interrupt handler for sRIO on MPC85xx
powerpc/fsl_rio: move machine_check handler
powerpc/fsl_lbc: Add workaround for ELBC-A001 erratum
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/fsl_lbc.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/rio.h | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 13 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_lbc.c | 9 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_rio.c | 100 |
5 files changed, 107 insertions, 22 deletions
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h index 5c1bf3466749..8a0b5ece8f76 100644 --- a/arch/powerpc/include/asm/fsl_lbc.h +++ b/arch/powerpc/include/asm/fsl_lbc.h | |||
@@ -157,6 +157,8 @@ struct fsl_lbc_regs { | |||
157 | #define LBCR_EPAR_SHIFT 16 | 157 | #define LBCR_EPAR_SHIFT 16 |
158 | #define LBCR_BMT 0x0000FF00 | 158 | #define LBCR_BMT 0x0000FF00 |
159 | #define LBCR_BMT_SHIFT 8 | 159 | #define LBCR_BMT_SHIFT 8 |
160 | #define LBCR_BMTPS 0x0000000F | ||
161 | #define LBCR_BMTPS_SHIFT 0 | ||
160 | #define LBCR_INIT 0x00040000 | 162 | #define LBCR_INIT 0x00040000 |
161 | __be32 lcrr; /**< Clock Ratio Register */ | 163 | __be32 lcrr; /**< Clock Ratio Register */ |
162 | #define LCRR_DBYP 0x80000000 | 164 | #define LCRR_DBYP 0x80000000 |
diff --git a/arch/powerpc/include/asm/rio.h b/arch/powerpc/include/asm/rio.h index 0018bf80cb25..d902abd33995 100644 --- a/arch/powerpc/include/asm/rio.h +++ b/arch/powerpc/include/asm/rio.h | |||
@@ -14,5 +14,10 @@ | |||
14 | #define ASM_PPC_RIO_H | 14 | #define ASM_PPC_RIO_H |
15 | 15 | ||
16 | extern void platform_rio_init(void); | 16 | extern void platform_rio_init(void); |
17 | #ifdef CONFIG_RAPIDIO | ||
18 | extern int fsl_rio_mcheck_exception(struct pt_regs *); | ||
19 | #else | ||
20 | static inline int fsl_rio_mcheck_exception(struct pt_regs *regs) {return 0; } | ||
21 | #endif | ||
17 | 22 | ||
18 | #endif /* ASM_PPC_RIO_H */ | 23 | #endif /* ASM_PPC_RIO_H */ |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index b13306b0d925..0ff4ab98d50c 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #endif | 55 | #endif |
56 | #include <asm/kexec.h> | 56 | #include <asm/kexec.h> |
57 | #include <asm/ppc-opcode.h> | 57 | #include <asm/ppc-opcode.h> |
58 | #include <asm/rio.h> | ||
58 | 59 | ||
59 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 60 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
60 | int (*__debugger)(struct pt_regs *regs) __read_mostly; | 61 | int (*__debugger)(struct pt_regs *regs) __read_mostly; |
@@ -424,6 +425,12 @@ int machine_check_e500mc(struct pt_regs *regs) | |||
424 | unsigned long reason = mcsr; | 425 | unsigned long reason = mcsr; |
425 | int recoverable = 1; | 426 | int recoverable = 1; |
426 | 427 | ||
428 | if (reason & MCSR_BUS_RBERR) { | ||
429 | recoverable = fsl_rio_mcheck_exception(regs); | ||
430 | if (recoverable == 1) | ||
431 | goto silent_out; | ||
432 | } | ||
433 | |||
427 | printk("Machine check in kernel mode.\n"); | 434 | printk("Machine check in kernel mode.\n"); |
428 | printk("Caused by (from MCSR=%lx): ", reason); | 435 | printk("Caused by (from MCSR=%lx): ", reason); |
429 | 436 | ||
@@ -499,6 +506,7 @@ int machine_check_e500mc(struct pt_regs *regs) | |||
499 | reason & MCSR_MEA ? "Effective" : "Physical", addr); | 506 | reason & MCSR_MEA ? "Effective" : "Physical", addr); |
500 | } | 507 | } |
501 | 508 | ||
509 | silent_out: | ||
502 | mtspr(SPRN_MCSR, mcsr); | 510 | mtspr(SPRN_MCSR, mcsr); |
503 | return mfspr(SPRN_MCSR) == 0 && recoverable; | 511 | return mfspr(SPRN_MCSR) == 0 && recoverable; |
504 | } | 512 | } |
@@ -507,6 +515,11 @@ int machine_check_e500(struct pt_regs *regs) | |||
507 | { | 515 | { |
508 | unsigned long reason = get_mc_reason(regs); | 516 | unsigned long reason = get_mc_reason(regs); |
509 | 517 | ||
518 | if (reason & MCSR_BUS_RBERR) { | ||
519 | if (fsl_rio_mcheck_exception(regs)) | ||
520 | return 1; | ||
521 | } | ||
522 | |||
510 | printk("Machine check in kernel mode.\n"); | 523 | printk("Machine check in kernel mode.\n"); |
511 | printk("Caused by (from MCSR=%lx): ", reason); | 524 | printk("Caused by (from MCSR=%lx): ", reason); |
512 | 525 | ||
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index 4fcb5a4e60dd..0608b1657da4 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c | |||
@@ -184,7 +184,8 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) | |||
184 | } | 184 | } |
185 | EXPORT_SYMBOL(fsl_upm_run_pattern); | 185 | EXPORT_SYMBOL(fsl_upm_run_pattern); |
186 | 186 | ||
187 | static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl) | 187 | static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl, |
188 | struct device_node *node) | ||
188 | { | 189 | { |
189 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 190 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
190 | 191 | ||
@@ -198,6 +199,10 @@ static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl) | |||
198 | /* Enable interrupts for any detected events */ | 199 | /* Enable interrupts for any detected events */ |
199 | out_be32(&lbc->lteir, LTEIR_ENABLE); | 200 | out_be32(&lbc->lteir, LTEIR_ENABLE); |
200 | 201 | ||
202 | /* Set the monitor timeout value to the maximum for erratum A001 */ | ||
203 | if (of_device_is_compatible(node, "fsl,elbc")) | ||
204 | clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS); | ||
205 | |||
201 | return 0; | 206 | return 0; |
202 | } | 207 | } |
203 | 208 | ||
@@ -304,7 +309,7 @@ static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev) | |||
304 | 309 | ||
305 | fsl_lbc_ctrl_dev->dev = &dev->dev; | 310 | fsl_lbc_ctrl_dev->dev = &dev->dev; |
306 | 311 | ||
307 | ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev); | 312 | ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node); |
308 | if (ret < 0) | 313 | if (ret < 0) |
309 | goto err; | 314 | goto err; |
310 | 315 | ||
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 49798532b477..5b206a2fe17c 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c | |||
@@ -10,7 +10,7 @@ | |||
10 | * - Added Port-Write message handling | 10 | * - Added Port-Write message handling |
11 | * - Added Machine Check exception handling | 11 | * - Added Machine Check exception handling |
12 | * | 12 | * |
13 | * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc. | 13 | * Copyright (C) 2007, 2008, 2010 Freescale Semiconductor, Inc. |
14 | * Zhang Wei <wei.zhang@freescale.com> | 14 | * Zhang Wei <wei.zhang@freescale.com> |
15 | * | 15 | * |
16 | * Copyright 2005 MontaVista Software, Inc. | 16 | * Copyright 2005 MontaVista Software, Inc. |
@@ -47,15 +47,33 @@ | |||
47 | #define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq) | 47 | #define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq) |
48 | #define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq) | 48 | #define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq) |
49 | 49 | ||
50 | #define IPWSR_CLEAR 0x98 | ||
51 | #define OMSR_CLEAR 0x1cb3 | ||
52 | #define IMSR_CLEAR 0x491 | ||
53 | #define IDSR_CLEAR 0x91 | ||
54 | #define ODSR_CLEAR 0x1c00 | ||
55 | #define LTLEECSR_ENABLE_ALL 0xFFC000FC | ||
56 | #define ESCSR_CLEAR 0x07120204 | ||
57 | |||
58 | #define RIO_PORT1_EDCSR 0x0640 | ||
59 | #define RIO_PORT2_EDCSR 0x0680 | ||
60 | #define RIO_PORT1_IECSR 0x10130 | ||
61 | #define RIO_PORT2_IECSR 0x101B0 | ||
62 | #define RIO_IM0SR 0x13064 | ||
63 | #define RIO_IM1SR 0x13164 | ||
64 | #define RIO_OM0SR 0x13004 | ||
65 | #define RIO_OM1SR 0x13104 | ||
66 | |||
50 | #define RIO_ATMU_REGS_OFFSET 0x10c00 | 67 | #define RIO_ATMU_REGS_OFFSET 0x10c00 |
51 | #define RIO_P_MSG_REGS_OFFSET 0x11000 | 68 | #define RIO_P_MSG_REGS_OFFSET 0x11000 |
52 | #define RIO_S_MSG_REGS_OFFSET 0x13000 | 69 | #define RIO_S_MSG_REGS_OFFSET 0x13000 |
53 | #define RIO_GCCSR 0x13c | 70 | #define RIO_GCCSR 0x13c |
54 | #define RIO_ESCSR 0x158 | 71 | #define RIO_ESCSR 0x158 |
72 | #define RIO_PORT2_ESCSR 0x178 | ||
55 | #define RIO_CCSR 0x15c | 73 | #define RIO_CCSR 0x15c |
56 | #define RIO_LTLEDCSR 0x0608 | 74 | #define RIO_LTLEDCSR 0x0608 |
57 | #define RIO_LTLEDCSR_IER 0x80000000 | 75 | #define RIO_LTLEDCSR_IER 0x80000000 |
58 | #define RIO_LTLEDCSR_PRT 0x01000000 | 76 | #define RIO_LTLEDCSR_PRT 0x01000000 |
59 | #define RIO_LTLEECSR 0x060c | 77 | #define RIO_LTLEECSR 0x060c |
60 | #define RIO_EPWISR 0x10010 | 78 | #define RIO_EPWISR 0x10010 |
61 | #define RIO_ISR_AACR 0x10120 | 79 | #define RIO_ISR_AACR 0x10120 |
@@ -88,7 +106,10 @@ | |||
88 | #define RIO_IPWSR_PWD 0x00000008 | 106 | #define RIO_IPWSR_PWD 0x00000008 |
89 | #define RIO_IPWSR_PWB 0x00000004 | 107 | #define RIO_IPWSR_PWB 0x00000004 |
90 | 108 | ||
91 | #define RIO_EPWISR_PINT 0x80000000 | 109 | /* EPWISR Error match value */ |
110 | #define RIO_EPWISR_PINT1 0x80000000 | ||
111 | #define RIO_EPWISR_PINT2 0x40000000 | ||
112 | #define RIO_EPWISR_MU 0x00000002 | ||
92 | #define RIO_EPWISR_PW 0x00000001 | 113 | #define RIO_EPWISR_PW 0x00000001 |
93 | 114 | ||
94 | #define RIO_MSG_DESC_SIZE 32 | 115 | #define RIO_MSG_DESC_SIZE 32 |
@@ -260,9 +281,7 @@ struct rio_priv { | |||
260 | static void __iomem *rio_regs_win; | 281 | static void __iomem *rio_regs_win; |
261 | 282 | ||
262 | #ifdef CONFIG_E500 | 283 | #ifdef CONFIG_E500 |
263 | static int (*saved_mcheck_exception)(struct pt_regs *regs); | 284 | int fsl_rio_mcheck_exception(struct pt_regs *regs) |
264 | |||
265 | static int fsl_rio_mcheck_exception(struct pt_regs *regs) | ||
266 | { | 285 | { |
267 | const struct exception_table_entry *entry = NULL; | 286 | const struct exception_table_entry *entry = NULL; |
268 | unsigned long reason = mfspr(SPRN_MCSR); | 287 | unsigned long reason = mfspr(SPRN_MCSR); |
@@ -284,11 +303,9 @@ static int fsl_rio_mcheck_exception(struct pt_regs *regs) | |||
284 | } | 303 | } |
285 | } | 304 | } |
286 | 305 | ||
287 | if (saved_mcheck_exception) | 306 | return 0; |
288 | return saved_mcheck_exception(regs); | ||
289 | else | ||
290 | return cur_cpu_spec->machine_check(regs); | ||
291 | } | 307 | } |
308 | EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception); | ||
292 | #endif | 309 | #endif |
293 | 310 | ||
294 | /** | 311 | /** |
@@ -1064,6 +1081,40 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport) | |||
1064 | return rc; | 1081 | return rc; |
1065 | } | 1082 | } |
1066 | 1083 | ||
1084 | static void port_error_handler(struct rio_mport *port, int offset) | ||
1085 | { | ||
1086 | /*XXX: Error recovery is not implemented, we just clear errors */ | ||
1087 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); | ||
1088 | |||
1089 | if (offset == 0) { | ||
1090 | out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); | ||
1091 | out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0); | ||
1092 | out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); | ||
1093 | } else { | ||
1094 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); | ||
1095 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0); | ||
1096 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | static void msg_unit_error_handler(struct rio_mport *port) | ||
1101 | { | ||
1102 | struct rio_priv *priv = port->priv; | ||
1103 | |||
1104 | /*XXX: Error recovery is not implemented, we just clear errors */ | ||
1105 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); | ||
1106 | |||
1107 | out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR); | ||
1108 | out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR); | ||
1109 | out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR); | ||
1110 | out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR); | ||
1111 | |||
1112 | out_be32(&priv->msg_regs->odsr, ODSR_CLEAR); | ||
1113 | out_be32(&priv->msg_regs->dsr, IDSR_CLEAR); | ||
1114 | |||
1115 | out_be32(&priv->msg_regs->pwsr, IPWSR_CLEAR); | ||
1116 | } | ||
1117 | |||
1067 | /** | 1118 | /** |
1068 | * fsl_rio_port_write_handler - MPC85xx port write interrupt handler | 1119 | * fsl_rio_port_write_handler - MPC85xx port write interrupt handler |
1069 | * @irq: Linux interrupt number | 1120 | * @irq: Linux interrupt number |
@@ -1144,10 +1195,22 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) | |||
1144 | } | 1195 | } |
1145 | 1196 | ||
1146 | pw_done: | 1197 | pw_done: |
1147 | if (epwisr & RIO_EPWISR_PINT) { | 1198 | if (epwisr & RIO_EPWISR_PINT1) { |
1199 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | ||
1200 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | ||
1201 | port_error_handler(port, 0); | ||
1202 | } | ||
1203 | |||
1204 | if (epwisr & RIO_EPWISR_PINT2) { | ||
1148 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | 1205 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); |
1149 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | 1206 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); |
1150 | out_be32(priv->regs_win + RIO_LTLEDCSR, 0); | 1207 | port_error_handler(port, 1); |
1208 | } | ||
1209 | |||
1210 | if (epwisr & RIO_EPWISR_MU) { | ||
1211 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | ||
1212 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | ||
1213 | msg_unit_error_handler(port); | ||
1151 | } | 1214 | } |
1152 | 1215 | ||
1153 | return IRQ_HANDLED; | 1216 | return IRQ_HANDLED; |
@@ -1258,12 +1321,14 @@ static int fsl_rio_port_write_init(struct rio_mport *mport) | |||
1258 | 1321 | ||
1259 | 1322 | ||
1260 | /* Hook up port-write handler */ | 1323 | /* Hook up port-write handler */ |
1261 | rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0, | 1324 | rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, |
1262 | "port-write", (void *)mport); | 1325 | IRQF_SHARED, "port-write", (void *)mport); |
1263 | if (rc < 0) { | 1326 | if (rc < 0) { |
1264 | pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); | 1327 | pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); |
1265 | goto err_out; | 1328 | goto err_out; |
1266 | } | 1329 | } |
1330 | /* Enable Error Interrupt */ | ||
1331 | out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL); | ||
1267 | 1332 | ||
1268 | INIT_WORK(&priv->pw_work, fsl_pw_dpc); | 1333 | INIT_WORK(&priv->pw_work, fsl_pw_dpc); |
1269 | spin_lock_init(&priv->pw_fifo_lock); | 1334 | spin_lock_init(&priv->pw_fifo_lock); |
@@ -1538,11 +1603,6 @@ int fsl_rio_setup(struct platform_device *dev) | |||
1538 | fsl_rio_doorbell_init(port); | 1603 | fsl_rio_doorbell_init(port); |
1539 | fsl_rio_port_write_init(port); | 1604 | fsl_rio_port_write_init(port); |
1540 | 1605 | ||
1541 | #ifdef CONFIG_E500 | ||
1542 | saved_mcheck_exception = ppc_md.machine_check_exception; | ||
1543 | ppc_md.machine_check_exception = fsl_rio_mcheck_exception; | ||
1544 | #endif | ||
1545 | |||
1546 | return 0; | 1606 | return 0; |
1547 | err: | 1607 | err: |
1548 | iounmap(priv->regs_win); | 1608 | iounmap(priv->regs_win); |