diff options
-rw-r--r-- | arch/powerpc/sysdev/fsl_rio.c | 85 |
1 files changed, 77 insertions, 8 deletions
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 34440e1bac18..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 |
@@ -1060,6 +1081,40 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport) | |||
1060 | return rc; | 1081 | return rc; |
1061 | } | 1082 | } |
1062 | 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 | |||
1063 | /** | 1118 | /** |
1064 | * fsl_rio_port_write_handler - MPC85xx port write interrupt handler | 1119 | * fsl_rio_port_write_handler - MPC85xx port write interrupt handler |
1065 | * @irq: Linux interrupt number | 1120 | * @irq: Linux interrupt number |
@@ -1140,10 +1195,22 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) | |||
1140 | } | 1195 | } |
1141 | 1196 | ||
1142 | pw_done: | 1197 | pw_done: |
1143 | 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) { | ||
1205 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | ||
1206 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | ||
1207 | port_error_handler(port, 1); | ||
1208 | } | ||
1209 | |||
1210 | if (epwisr & RIO_EPWISR_MU) { | ||
1144 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | 1211 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); |
1145 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | 1212 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); |
1146 | out_be32(priv->regs_win + RIO_LTLEDCSR, 0); | 1213 | msg_unit_error_handler(port); |
1147 | } | 1214 | } |
1148 | 1215 | ||
1149 | return IRQ_HANDLED; | 1216 | return IRQ_HANDLED; |
@@ -1254,12 +1321,14 @@ static int fsl_rio_port_write_init(struct rio_mport *mport) | |||
1254 | 1321 | ||
1255 | 1322 | ||
1256 | /* Hook up port-write handler */ | 1323 | /* Hook up port-write handler */ |
1257 | 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, |
1258 | "port-write", (void *)mport); | 1325 | IRQF_SHARED, "port-write", (void *)mport); |
1259 | if (rc < 0) { | 1326 | if (rc < 0) { |
1260 | pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); | 1327 | pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); |
1261 | goto err_out; | 1328 | goto err_out; |
1262 | } | 1329 | } |
1330 | /* Enable Error Interrupt */ | ||
1331 | out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL); | ||
1263 | 1332 | ||
1264 | INIT_WORK(&priv->pw_work, fsl_pw_dpc); | 1333 | INIT_WORK(&priv->pw_work, fsl_pw_dpc); |
1265 | spin_lock_init(&priv->pw_fifo_lock); | 1334 | spin_lock_init(&priv->pw_fifo_lock); |