summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/mpc85xx
diff options
context:
space:
mode:
authorjhibbits <jhibbits@FreeBSD.org>2016-01-03 15:24:57 +0000
committerjhibbits <jhibbits@FreeBSD.org>2016-01-03 15:24:57 +0000
commitf77e82d7d2528fbb0af076dc2dd86c2052a9cecc (patch)
tree460d9b4ebb5abab868dc7fb88af763f468a9d43b /sys/powerpc/mpc85xx
parent9e2574043ba4d96f5811c4dd2b164ecf18a55bc6 (diff)
downloadFreeBSD-src-f77e82d7d2528fbb0af076dc2dd86c2052a9cecc.zip
FreeBSD-src-f77e82d7d2528fbb0af076dc2dd86c2052a9cecc.tar.gz
Add error interrupt handler for Freescale PCI errors
This eliminates a 'interrupt storm' warning spam with the P5020. Obtained from: Semihalf
Diffstat (limited to 'sys/powerpc/mpc85xx')
-rw-r--r--sys/powerpc/mpc85xx/pci_mpc85xx.c113
1 files changed, 112 insertions, 1 deletions
diff --git a/sys/powerpc/mpc85xx/pci_mpc85xx.c b/sys/powerpc/mpc85xx/pci_mpc85xx.c
index 3c34c87..95e5a74 100644
--- a/sys/powerpc/mpc85xx/pci_mpc85xx.c
+++ b/sys/powerpc/mpc85xx/pci_mpc85xx.c
@@ -94,6 +94,29 @@ __FBSDID("$FreeBSD$");
#define REG_PEX_ERR_DR 0x0e00
#define REG_PEX_ERR_EN 0x0e08
+#define REG_PEX_ERR_DR 0x0e00
+#define REG_PEX_ERR_DR_ME 0x80000000
+#define REG_PEX_ERR_DR_PCT 0x800000
+#define REG_PEX_ERR_DR_PAT 0x400000
+#define REG_PEX_ERR_DR_PCAC 0x200000
+#define REG_PEX_ERR_DR_PNM 0x100000
+#define REG_PEX_ERR_DR_CDNSC 0x80000
+#define REG_PEX_ERR_DR_CRSNC 0x40000
+#define REG_PEX_ERR_DR_ICCA 0x20000
+#define REG_PEX_ERR_DR_IACA 0x10000
+#define REG_PEX_ERR_DR_CRST 0x8000
+#define REG_PEX_ERR_DR_MIS 0x4000
+#define REG_PEX_ERR_DR_IOIS 0x2000
+#define REG_PEX_ERR_DR_CIS 0x1000
+#define REG_PEX_ERR_DR_CIEP 0x800
+#define REG_PEX_ERR_DR_IOIEP 0x400
+#define REG_PEX_ERR_DR_OAC 0x200
+#define REG_PEX_ERR_DR_IOIA 0x100
+#define REG_PEX_ERR_DR_IMBA 0x80
+#define REG_PEX_ERR_DR_IIOBA 0x40
+#define REG_PEX_ERR_DR_LDDE 0x20
+#define REG_PEX_ERR_EN 0x0e08
+
#define PCIR_LTSSM 0x404
#define LTSSM_STAT_L0 0x16
@@ -113,6 +136,9 @@ struct fsl_pcib_softc {
bus_space_tag_t sc_bst;
int sc_rid;
+ struct resource *sc_irq_res;
+ void *sc_ih;
+
int sc_busnr;
int sc_pcie;
uint8_t sc_pcie_capreg; /* PCI-E Capability Reg Set */
@@ -122,6 +148,34 @@ struct fsl_pcib_softc {
int sc_devfn_via_ide;
};
+struct fsl_pcib_err_dr {
+ const char *msg;
+ uint32_t err_dr_mask;
+};
+
+static const struct fsl_pcib_err_dr pci_err[] = {
+ {"ME", REG_PEX_ERR_DR_ME},
+ {"PCT", REG_PEX_ERR_DR_PCT},
+ {"PAT", REG_PEX_ERR_DR_PAT},
+ {"PCAC", REG_PEX_ERR_DR_PCAC},
+ {"PNM", REG_PEX_ERR_DR_PNM},
+ {"CDNSC", REG_PEX_ERR_DR_CDNSC},
+ {"CRSNC", REG_PEX_ERR_DR_CRSNC},
+ {"ICCA", REG_PEX_ERR_DR_ICCA},
+ {"IACA", REG_PEX_ERR_DR_IACA},
+ {"CRST", REG_PEX_ERR_DR_CRST},
+ {"MIS", REG_PEX_ERR_DR_MIS},
+ {"IOIS", REG_PEX_ERR_DR_IOIS},
+ {"CIS", REG_PEX_ERR_DR_CIS},
+ {"CIEP", REG_PEX_ERR_DR_CIEP},
+ {"IOIEP", REG_PEX_ERR_DR_IOIEP},
+ {"OAC", REG_PEX_ERR_DR_OAC},
+ {"IOIA", REG_PEX_ERR_DR_IOIA},
+ {"IMBA", REG_PEX_ERR_DR_IMBA},
+ {"IIOBA", REG_PEX_ERR_DR_IIOBA},
+ {"LDDE", REG_PEX_ERR_DR_LDDE}
+};
+
/* Local forward declerations. */
static uint32_t fsl_pcib_cfgread(struct fsl_pcib_softc *, u_int, u_int, u_int,
u_int, int);
@@ -173,6 +227,35 @@ DEFINE_CLASS_1(pcib, fsl_pcib_driver, fsl_pcib_methods,
DRIVER_MODULE(pcib, ofwbus, fsl_pcib_driver, fsl_pcib_devclass, 0, 0);
static int
+fsl_pcib_err_intr(void *v)
+{
+ struct fsl_pcib_softc *sc;
+ device_t dev;
+ uint32_t err_reg, clear_reg;
+ uint8_t i;
+
+ dev = (device_t)v;
+ sc = device_get_softc(dev);
+
+ clear_reg = 0;
+ err_reg = bus_space_read_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR);
+
+ /* Check which one error occurred */
+ for (i = 0; i < sizeof(pci_err)/sizeof(struct fsl_pcib_err_dr); i++) {
+ if (err_reg & pci_err[i].err_dr_mask) {
+ device_printf(dev, "PCI %d: report %s error\n",
+ device_get_unit(dev), pci_err[i].msg);
+ clear_reg |= pci_err[i].err_dr_mask;
+ }
+ }
+
+ /* Clear pending errors */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR, clear_reg);
+
+ return (0);
+}
+
+static int
fsl_pcib_probe(device_t dev)
{
@@ -198,7 +281,7 @@ fsl_pcib_attach(device_t dev)
struct fsl_pcib_softc *sc;
phandle_t node;
uint32_t cfgreg;
- int maxslot, error;
+ int error, maxslot, rid;
uint8_t ltssm, capptr;
sc = device_get_softc(dev);
@@ -279,6 +362,34 @@ fsl_pcib_attach(device_t dev)
}
}
+ /* Allocate irq */
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->sc_irq_res == NULL) {
+ error = fsl_pcib_detach(dev);
+ if (error != 0) {
+ device_printf(dev,
+ "Detach of the driver failed with error %d\n",
+ error);
+ }
+ return (ENXIO);
+ }
+
+ /* Setup interrupt handler */
+ error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, (driver_intr_t *)fsl_pcib_err_intr, dev, &sc->sc_ih);
+ if (error != 0) {
+ device_printf(dev, "Could not setup irq, %d\n", error);
+ sc->sc_ih = NULL;
+ error = fsl_pcib_detach(dev);
+ if (error != 0) {
+ device_printf(dev,
+ "Detach of the driver failed with error %d\n",
+ error);
+ }
+ return (ENXIO);
+ }
+
fsl_pcib_err_init(dev);
return (ofw_pci_attach(dev));
OpenPOWER on IntegriCloud