Merge remote branch 'kumar/merge' into merge
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 26 May 2011 23:58:22 +0000 (09:58 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 26 May 2011 23:58:22 +0000 (09:58 +1000)
arch/powerpc/include/asm/fsl_lbc.h
arch/powerpc/include/asm/rio.h
arch/powerpc/kernel/traps.c
arch/powerpc/sysdev/fsl_lbc.c
arch/powerpc/sysdev/fsl_rio.c

index 5c1bf34..8a0b5ec 100644 (file)
@@ -157,6 +157,8 @@ struct fsl_lbc_regs {
 #define LBCR_EPAR_SHIFT    16
 #define LBCR_BMT   0x0000FF00
 #define LBCR_BMT_SHIFT      8
+#define LBCR_BMTPS 0x0000000F
+#define LBCR_BMTPS_SHIFT    0
 #define LBCR_INIT  0x00040000
        __be32 lcrr;            /**< Clock Ratio Register */
 #define LCRR_DBYP    0x80000000
index 0018bf8..d902abd 100644 (file)
 #define ASM_PPC_RIO_H
 
 extern void platform_rio_init(void);
+#ifdef CONFIG_RAPIDIO
+extern int fsl_rio_mcheck_exception(struct pt_regs *);
+#else
+static inline int fsl_rio_mcheck_exception(struct pt_regs *regs) {return 0; }
+#endif
 
 #endif                         /* ASM_PPC_RIO_H */
index b13306b..0ff4ab9 100644 (file)
@@ -55,6 +55,7 @@
 #endif
 #include <asm/kexec.h>
 #include <asm/ppc-opcode.h>
+#include <asm/rio.h>
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -424,6 +425,12 @@ int machine_check_e500mc(struct pt_regs *regs)
        unsigned long reason = mcsr;
        int recoverable = 1;
 
+       if (reason & MCSR_BUS_RBERR) {
+               recoverable = fsl_rio_mcheck_exception(regs);
+               if (recoverable == 1)
+                       goto silent_out;
+       }
+
        printk("Machine check in kernel mode.\n");
        printk("Caused by (from MCSR=%lx): ", reason);
 
@@ -499,6 +506,7 @@ int machine_check_e500mc(struct pt_regs *regs)
                       reason & MCSR_MEA ? "Effective" : "Physical", addr);
        }
 
+silent_out:
        mtspr(SPRN_MCSR, mcsr);
        return mfspr(SPRN_MCSR) == 0 && recoverable;
 }
@@ -507,6 +515,11 @@ int machine_check_e500(struct pt_regs *regs)
 {
        unsigned long reason = get_mc_reason(regs);
 
+       if (reason & MCSR_BUS_RBERR) {
+               if (fsl_rio_mcheck_exception(regs))
+                       return 1;
+       }
+
        printk("Machine check in kernel mode.\n");
        printk("Caused by (from MCSR=%lx): ", reason);
 
index 4fcb5a4..0608b16 100644 (file)
@@ -184,7 +184,8 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
 }
 EXPORT_SYMBOL(fsl_upm_run_pattern);
 
-static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
+static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl,
+                                      struct device_node *node)
 {
        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
 
@@ -198,6 +199,10 @@ static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
        /* Enable interrupts for any detected events */
        out_be32(&lbc->lteir, LTEIR_ENABLE);
 
+       /* Set the monitor timeout value to the maximum for erratum A001 */
+       if (of_device_is_compatible(node, "fsl,elbc"))
+               clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS);
+
        return 0;
 }
 
@@ -304,7 +309,7 @@ static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
 
        fsl_lbc_ctrl_dev->dev = &dev->dev;
 
-       ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
+       ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node);
        if (ret < 0)
                goto err;
 
index 4979853..5b206a2 100644 (file)
@@ -10,7 +10,7 @@
  * - Added Port-Write message handling
  * - Added Machine Check exception handling
  *
- * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007, 2008, 2010 Freescale Semiconductor, Inc.
  * Zhang Wei <wei.zhang@freescale.com>
  *
  * Copyright 2005 MontaVista Software, Inc.
 #define IRQ_RIO_RX(m)          (((struct rio_priv *)(m->priv))->rxirq)
 #define IRQ_RIO_PW(m)          (((struct rio_priv *)(m->priv))->pwirq)
 
+#define IPWSR_CLEAR            0x98
+#define OMSR_CLEAR             0x1cb3
+#define IMSR_CLEAR             0x491
+#define IDSR_CLEAR             0x91
+#define ODSR_CLEAR             0x1c00
+#define LTLEECSR_ENABLE_ALL    0xFFC000FC
+#define ESCSR_CLEAR            0x07120204
+
+#define RIO_PORT1_EDCSR                0x0640
+#define RIO_PORT2_EDCSR                0x0680
+#define RIO_PORT1_IECSR                0x10130
+#define RIO_PORT2_IECSR                0x101B0
+#define RIO_IM0SR              0x13064
+#define RIO_IM1SR              0x13164
+#define RIO_OM0SR              0x13004
+#define RIO_OM1SR              0x13104
+
 #define RIO_ATMU_REGS_OFFSET   0x10c00
 #define RIO_P_MSG_REGS_OFFSET  0x11000
 #define RIO_S_MSG_REGS_OFFSET  0x13000
 #define RIO_GCCSR              0x13c
 #define RIO_ESCSR              0x158
+#define RIO_PORT2_ESCSR                0x178
 #define RIO_CCSR               0x15c
 #define RIO_LTLEDCSR           0x0608
-#define  RIO_LTLEDCSR_IER      0x80000000
-#define  RIO_LTLEDCSR_PRT      0x01000000
+#define RIO_LTLEDCSR_IER       0x80000000
+#define RIO_LTLEDCSR_PRT       0x01000000
 #define RIO_LTLEECSR           0x060c
 #define RIO_EPWISR             0x10010
 #define RIO_ISR_AACR           0x10120
 #define RIO_IPWSR_PWD          0x00000008
 #define RIO_IPWSR_PWB          0x00000004
 
-#define RIO_EPWISR_PINT                0x80000000
+/* EPWISR Error match value */
+#define RIO_EPWISR_PINT1       0x80000000
+#define RIO_EPWISR_PINT2       0x40000000
+#define RIO_EPWISR_MU          0x00000002
 #define RIO_EPWISR_PW          0x00000001
 
 #define RIO_MSG_DESC_SIZE      32
@@ -260,9 +281,7 @@ struct rio_priv {
 static void __iomem *rio_regs_win;
 
 #ifdef CONFIG_E500
-static int (*saved_mcheck_exception)(struct pt_regs *regs);
-
-static int fsl_rio_mcheck_exception(struct pt_regs *regs)
+int fsl_rio_mcheck_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *entry = NULL;
        unsigned long reason = mfspr(SPRN_MCSR);
@@ -284,11 +303,9 @@ static int fsl_rio_mcheck_exception(struct pt_regs *regs)
                }
        }
 
-       if (saved_mcheck_exception)
-               return saved_mcheck_exception(regs);
-       else
-               return cur_cpu_spec->machine_check(regs);
+       return 0;
 }
+EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception);
 #endif
 
 /**
@@ -1064,6 +1081,40 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
        return rc;
 }
 
+static void port_error_handler(struct rio_mport *port, int offset)
+{
+       /*XXX: Error recovery is not implemented, we just clear errors */
+       out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
+
+       if (offset == 0) {
+               out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);
+       } else {
+               out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0);
+               out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
+       }
+}
+
+static void msg_unit_error_handler(struct rio_mport *port)
+{
+       struct rio_priv *priv = port->priv;
+
+       /*XXX: Error recovery is not implemented, we just clear errors */
+       out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
+
+       out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR);
+       out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR);
+       out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR);
+       out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR);
+
+       out_be32(&priv->msg_regs->odsr, ODSR_CLEAR);
+       out_be32(&priv->msg_regs->dsr, IDSR_CLEAR);
+
+       out_be32(&priv->msg_regs->pwsr, IPWSR_CLEAR);
+}
+
 /**
  * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
  * @irq: Linux interrupt number
@@ -1144,10 +1195,22 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
        }
 
 pw_done:
-       if (epwisr & RIO_EPWISR_PINT) {
+       if (epwisr & RIO_EPWISR_PINT1) {
+               tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+               pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+               port_error_handler(port, 0);
+       }
+
+       if (epwisr & RIO_EPWISR_PINT2) {
                tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
                pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
-               out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+               port_error_handler(port, 1);
+       }
+
+       if (epwisr & RIO_EPWISR_MU) {
+               tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+               pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+               msg_unit_error_handler(port);
        }
 
        return IRQ_HANDLED;
@@ -1258,12 +1321,14 @@ static int fsl_rio_port_write_init(struct rio_mport *mport)
 
 
        /* Hook up port-write handler */
-       rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
-                        "port-write", (void *)mport);
+       rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler,
+                       IRQF_SHARED, "port-write", (void *)mport);
        if (rc < 0) {
                pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
                goto err_out;
        }
+       /* Enable Error Interrupt */
+       out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
 
        INIT_WORK(&priv->pw_work, fsl_pw_dpc);
        spin_lock_init(&priv->pw_fifo_lock);
@@ -1538,11 +1603,6 @@ int fsl_rio_setup(struct platform_device *dev)
        fsl_rio_doorbell_init(port);
        fsl_rio_port_write_init(port);
 
-#ifdef CONFIG_E500
-       saved_mcheck_exception = ppc_md.machine_check_exception;
-       ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
-#endif
-
        return 0;
 err:
        iounmap(priv->regs_win);