diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/sysdev/fsl_rio.c | 74 |
1 files changed, 70 insertions, 4 deletions
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 73d5f3e142ab..4646cc7aa93a 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/kfifo.h> | 32 | #include <linux/kfifo.h> |
33 | 33 | ||
34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
35 | #include <asm/machdep.h> | ||
36 | #include <asm/uaccess.h> | ||
35 | 37 | ||
36 | #undef DEBUG_PW /* Port-Write debugging */ | 38 | #undef DEBUG_PW /* Port-Write debugging */ |
37 | 39 | ||
@@ -47,6 +49,8 @@ | |||
47 | #define RIO_ESCSR 0x158 | 49 | #define RIO_ESCSR 0x158 |
48 | #define RIO_CCSR 0x15c | 50 | #define RIO_CCSR 0x15c |
49 | #define RIO_LTLEDCSR 0x0608 | 51 | #define RIO_LTLEDCSR 0x0608 |
52 | #define RIO_LTLEDCSR_IER 0x80000000 | ||
53 | #define RIO_LTLEDCSR_PRT 0x01000000 | ||
50 | #define RIO_LTLEECSR 0x060c | 54 | #define RIO_LTLEECSR 0x060c |
51 | #define RIO_EPWISR 0x10010 | 55 | #define RIO_EPWISR 0x10010 |
52 | #define RIO_ISR_AACR 0x10120 | 56 | #define RIO_ISR_AACR 0x10120 |
@@ -214,6 +218,54 @@ struct rio_priv { | |||
214 | spinlock_t pw_fifo_lock; | 218 | spinlock_t pw_fifo_lock; |
215 | }; | 219 | }; |
216 | 220 | ||
221 | #define __fsl_read_rio_config(x, addr, err, op) \ | ||
222 | __asm__ __volatile__( \ | ||
223 | "1: "op" %1,0(%2)\n" \ | ||
224 | " eieio\n" \ | ||
225 | "2:\n" \ | ||
226 | ".section .fixup,\"ax\"\n" \ | ||
227 | "3: li %1,-1\n" \ | ||
228 | " li %0,%3\n" \ | ||
229 | " b 2b\n" \ | ||
230 | ".section __ex_table,\"a\"\n" \ | ||
231 | " .align 2\n" \ | ||
232 | " .long 1b,3b\n" \ | ||
233 | ".text" \ | ||
234 | : "=r" (err), "=r" (x) \ | ||
235 | : "b" (addr), "i" (-EFAULT), "0" (err)) | ||
236 | |||
237 | static void __iomem *rio_regs_win; | ||
238 | |||
239 | static int (*saved_mcheck_exception)(struct pt_regs *regs); | ||
240 | |||
241 | static int fsl_rio_mcheck_exception(struct pt_regs *regs) | ||
242 | { | ||
243 | const struct exception_table_entry *entry = NULL; | ||
244 | unsigned long reason = (mfspr(SPRN_MCSR) & MCSR_MASK); | ||
245 | |||
246 | if (reason & MCSR_BUS_RBERR) { | ||
247 | reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); | ||
248 | if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { | ||
249 | /* Check if we are prepared to handle this fault */ | ||
250 | entry = search_exception_tables(regs->nip); | ||
251 | if (entry) { | ||
252 | pr_debug("RIO: %s - MC Exception handled\n", | ||
253 | __func__); | ||
254 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), | ||
255 | 0); | ||
256 | regs->msr |= MSR_RI; | ||
257 | regs->nip = entry->fixup; | ||
258 | return 1; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if (saved_mcheck_exception) | ||
264 | return saved_mcheck_exception(regs); | ||
265 | else | ||
266 | return cur_cpu_spec->machine_check(regs); | ||
267 | } | ||
268 | |||
217 | /** | 269 | /** |
218 | * fsl_rio_doorbell_send - Send a MPC85xx doorbell message | 270 | * fsl_rio_doorbell_send - Send a MPC85xx doorbell message |
219 | * @mport: RapidIO master port info | 271 | * @mport: RapidIO master port info |
@@ -314,6 +366,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, | |||
314 | { | 366 | { |
315 | struct rio_priv *priv = mport->priv; | 367 | struct rio_priv *priv = mport->priv; |
316 | u8 *data; | 368 | u8 *data; |
369 | u32 rval, err = 0; | ||
317 | 370 | ||
318 | pr_debug | 371 | pr_debug |
319 | ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n", | 372 | ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n", |
@@ -324,17 +377,24 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, | |||
324 | data = (u8 *) priv->maint_win + offset; | 377 | data = (u8 *) priv->maint_win + offset; |
325 | switch (len) { | 378 | switch (len) { |
326 | case 1: | 379 | case 1: |
327 | *val = in_8((u8 *) data); | 380 | __fsl_read_rio_config(rval, data, err, "lbz"); |
328 | break; | 381 | break; |
329 | case 2: | 382 | case 2: |
330 | *val = in_be16((u16 *) data); | 383 | __fsl_read_rio_config(rval, data, err, "lhz"); |
331 | break; | 384 | break; |
332 | default: | 385 | default: |
333 | *val = in_be32((u32 *) data); | 386 | __fsl_read_rio_config(rval, data, err, "lwz"); |
334 | break; | 387 | break; |
335 | } | 388 | } |
336 | 389 | ||
337 | return 0; | 390 | if (err) { |
391 | pr_debug("RIO: cfg_read error %d for %x:%x:%x\n", | ||
392 | err, destid, hopcount, offset); | ||
393 | } | ||
394 | |||
395 | *val = rval; | ||
396 | |||
397 | return err; | ||
338 | } | 398 | } |
339 | 399 | ||
340 | /** | 400 | /** |
@@ -1365,6 +1425,7 @@ int fsl_rio_setup(struct of_device *dev) | |||
1365 | rio_register_mport(port); | 1425 | rio_register_mport(port); |
1366 | 1426 | ||
1367 | priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); | 1427 | priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); |
1428 | rio_regs_win = priv->regs_win; | ||
1368 | 1429 | ||
1369 | /* Probe the master port phy type */ | 1430 | /* Probe the master port phy type */ |
1370 | ccsr = in_be32(priv->regs_win + RIO_CCSR); | 1431 | ccsr = in_be32(priv->regs_win + RIO_CCSR); |
@@ -1433,6 +1494,11 @@ int fsl_rio_setup(struct of_device *dev) | |||
1433 | fsl_rio_doorbell_init(port); | 1494 | fsl_rio_doorbell_init(port); |
1434 | fsl_rio_port_write_init(port); | 1495 | fsl_rio_port_write_init(port); |
1435 | 1496 | ||
1497 | saved_mcheck_exception = ppc_md.machine_check_exception; | ||
1498 | ppc_md.machine_check_exception = fsl_rio_mcheck_exception; | ||
1499 | /* Ensure that RFXE is set */ | ||
1500 | mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000)); | ||
1501 | |||
1436 | return 0; | 1502 | return 0; |
1437 | err: | 1503 | err: |
1438 | iounmap(priv->regs_win); | 1504 | iounmap(priv->regs_win); |