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
This commit is contained in:
@@ -157,6 +157,8 @@ struct fsl_lbc_regs {
|
|||||||
#define LBCR_EPAR_SHIFT 16
|
#define LBCR_EPAR_SHIFT 16
|
||||||
#define LBCR_BMT 0x0000FF00
|
#define LBCR_BMT 0x0000FF00
|
||||||
#define LBCR_BMT_SHIFT 8
|
#define LBCR_BMT_SHIFT 8
|
||||||
|
#define LBCR_BMTPS 0x0000000F
|
||||||
|
#define LBCR_BMTPS_SHIFT 0
|
||||||
#define LBCR_INIT 0x00040000
|
#define LBCR_INIT 0x00040000
|
||||||
__be32 lcrr; /**< Clock Ratio Register */
|
__be32 lcrr; /**< Clock Ratio Register */
|
||||||
#define LCRR_DBYP 0x80000000
|
#define LCRR_DBYP 0x80000000
|
||||||
|
@@ -14,5 +14,10 @@
|
|||||||
#define ASM_PPC_RIO_H
|
#define ASM_PPC_RIO_H
|
||||||
|
|
||||||
extern void platform_rio_init(void);
|
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 */
|
#endif /* ASM_PPC_RIO_H */
|
||||||
|
@@ -55,6 +55,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <asm/kexec.h>
|
#include <asm/kexec.h>
|
||||||
#include <asm/ppc-opcode.h>
|
#include <asm/ppc-opcode.h>
|
||||||
|
#include <asm/rio.h>
|
||||||
|
|
||||||
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
|
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
|
||||||
int (*__debugger)(struct pt_regs *regs) __read_mostly;
|
int (*__debugger)(struct pt_regs *regs) __read_mostly;
|
||||||
@@ -424,6 +425,12 @@ int machine_check_e500mc(struct pt_regs *regs)
|
|||||||
unsigned long reason = mcsr;
|
unsigned long reason = mcsr;
|
||||||
int recoverable = 1;
|
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("Machine check in kernel mode.\n");
|
||||||
printk("Caused by (from MCSR=%lx): ", reason);
|
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);
|
reason & MCSR_MEA ? "Effective" : "Physical", addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
silent_out:
|
||||||
mtspr(SPRN_MCSR, mcsr);
|
mtspr(SPRN_MCSR, mcsr);
|
||||||
return mfspr(SPRN_MCSR) == 0 && recoverable;
|
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);
|
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("Machine check in kernel mode.\n");
|
||||||
printk("Caused by (from MCSR=%lx): ", reason);
|
printk("Caused by (from MCSR=%lx): ", reason);
|
||||||
|
|
||||||
|
@@ -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);
|
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;
|
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 */
|
/* Enable interrupts for any detected events */
|
||||||
out_be32(&lbc->lteir, LTEIR_ENABLE);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +309,7 @@ static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
|
|||||||
|
|
||||||
fsl_lbc_ctrl_dev->dev = &dev->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)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
* - Added Port-Write message handling
|
* - Added Port-Write message handling
|
||||||
* - Added Machine Check exception 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>
|
* Zhang Wei <wei.zhang@freescale.com>
|
||||||
*
|
*
|
||||||
* Copyright 2005 MontaVista Software, Inc.
|
* Copyright 2005 MontaVista Software, Inc.
|
||||||
@@ -47,15 +47,33 @@
|
|||||||
#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq)
|
#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq)
|
||||||
#define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq)
|
#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_ATMU_REGS_OFFSET 0x10c00
|
||||||
#define RIO_P_MSG_REGS_OFFSET 0x11000
|
#define RIO_P_MSG_REGS_OFFSET 0x11000
|
||||||
#define RIO_S_MSG_REGS_OFFSET 0x13000
|
#define RIO_S_MSG_REGS_OFFSET 0x13000
|
||||||
#define RIO_GCCSR 0x13c
|
#define RIO_GCCSR 0x13c
|
||||||
#define RIO_ESCSR 0x158
|
#define RIO_ESCSR 0x158
|
||||||
|
#define RIO_PORT2_ESCSR 0x178
|
||||||
#define RIO_CCSR 0x15c
|
#define RIO_CCSR 0x15c
|
||||||
#define RIO_LTLEDCSR 0x0608
|
#define RIO_LTLEDCSR 0x0608
|
||||||
#define RIO_LTLEDCSR_IER 0x80000000
|
#define RIO_LTLEDCSR_IER 0x80000000
|
||||||
#define RIO_LTLEDCSR_PRT 0x01000000
|
#define RIO_LTLEDCSR_PRT 0x01000000
|
||||||
#define RIO_LTLEECSR 0x060c
|
#define RIO_LTLEECSR 0x060c
|
||||||
#define RIO_EPWISR 0x10010
|
#define RIO_EPWISR 0x10010
|
||||||
#define RIO_ISR_AACR 0x10120
|
#define RIO_ISR_AACR 0x10120
|
||||||
@@ -88,7 +106,10 @@
|
|||||||
#define RIO_IPWSR_PWD 0x00000008
|
#define RIO_IPWSR_PWD 0x00000008
|
||||||
#define RIO_IPWSR_PWB 0x00000004
|
#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_EPWISR_PW 0x00000001
|
||||||
|
|
||||||
#define RIO_MSG_DESC_SIZE 32
|
#define RIO_MSG_DESC_SIZE 32
|
||||||
@@ -260,9 +281,7 @@ struct rio_priv {
|
|||||||
static void __iomem *rio_regs_win;
|
static void __iomem *rio_regs_win;
|
||||||
|
|
||||||
#ifdef CONFIG_E500
|
#ifdef CONFIG_E500
|
||||||
static int (*saved_mcheck_exception)(struct pt_regs *regs);
|
int fsl_rio_mcheck_exception(struct pt_regs *regs)
|
||||||
|
|
||||||
static int fsl_rio_mcheck_exception(struct pt_regs *regs)
|
|
||||||
{
|
{
|
||||||
const struct exception_table_entry *entry = NULL;
|
const struct exception_table_entry *entry = NULL;
|
||||||
unsigned long reason = mfspr(SPRN_MCSR);
|
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 0;
|
||||||
return saved_mcheck_exception(regs);
|
|
||||||
else
|
|
||||||
return cur_cpu_spec->machine_check(regs);
|
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1064,6 +1081,40 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
|
|||||||
return rc;
|
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
|
* fsl_rio_port_write_handler - MPC85xx port write interrupt handler
|
||||||
* @irq: Linux interrupt number
|
* @irq: Linux interrupt number
|
||||||
@@ -1144,10 +1195,22 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pw_done:
|
pw_done:
|
||||||
if (epwisr & RIO_EPWISR_PINT) {
|
if (epwisr & RIO_EPWISR_PINT1) {
|
||||||
tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
|
tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
|
||||||
pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
|
pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
|
||||||
out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
|
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);
|
||||||
|
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;
|
return IRQ_HANDLED;
|
||||||
@@ -1258,12 +1321,14 @@ static int fsl_rio_port_write_init(struct rio_mport *mport)
|
|||||||
|
|
||||||
|
|
||||||
/* Hook up port-write handler */
|
/* Hook up port-write handler */
|
||||||
rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
|
rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler,
|
||||||
"port-write", (void *)mport);
|
IRQF_SHARED, "port-write", (void *)mport);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
|
pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
|
||||||
goto err_out;
|
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);
|
INIT_WORK(&priv->pw_work, fsl_pw_dpc);
|
||||||
spin_lock_init(&priv->pw_fifo_lock);
|
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_doorbell_init(port);
|
||||||
fsl_rio_port_write_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;
|
return 0;
|
||||||
err:
|
err:
|
||||||
iounmap(priv->regs_win);
|
iounmap(priv->regs_win);
|
||||||
|
Reference in New Issue
Block a user