Skip to content

Commit

Permalink
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
Linus Torvalds committed May 27, 2011
2 parents c0880dc + 9693ebd commit 45acab0
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 22 deletions.
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/fsl_lbc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions arch/powerpc/include/asm/rio.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@
#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 */
13 changes: 13 additions & 0 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand All @@ -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);

Expand Down
9 changes: 7 additions & 2 deletions arch/powerpc/sysdev/fsl_lbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

Expand Down
100 changes: 80 additions & 20 deletions arch/powerpc/sysdev/fsl_rio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -47,15 +47,33 @@
#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
Expand Down Expand Up @@ -88,7 +106,10 @@
#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
Expand Down Expand Up @@ -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);
Expand All @@ -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

/**
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 45acab0

Please sign in to comment.