static void ecc_e31200_status(struct ecc_e31200_softc *sc) { device_t dev = sc->ecc_device; uint16_t errsts; int bus, slot; bus = pci_get_bus(dev); slot = pci_get_slot(dev); errsts = pcib_read_config(dev, bus, slot, 0, PCI_E31200_ERRSTS, 2); if (errsts & PCI_E31200_ERRSTS_DMERR) ecc_printf(sc, "Uncorrectable multilple-bit ECC error\n"); else if (errsts & PCI_E31200_ERRSTS_DSERR) ecc_printf(sc, "Correctable single-bit ECC error\n"); if (errsts & (PCI_E31200_ERRSTS_DSERR | PCI_E31200_ERRSTS_DMERR)) { if (sc->ecc_addr != NULL) ecc_e31200_errlog(sc); /* Clear pending errors */ pcib_write_config(dev, bus, slot, 0, PCI_E31200_ERRSTS, errsts, 2); } }
static void ecc_e31200_status(struct ecc_e31200_softc *sc) { device_t dev = sc->ecc_device; uint16_t errsts; int bus, slot; bus = pci_get_bus(dev); slot = pci_get_slot(dev); errsts = pcib_read_config(dev, bus, slot, 0, 0xc8, 2); if (errsts & 0x2) ecc_printf(sc, "Uncorrectable ECC error\n"); else if (errsts & 0x1) ecc_printf(sc, "Correctable ECC error\n"); if (errsts & 0x3) { if (sc->ecc_addr != NULL) ecc_e31200_errlog(sc); /* Clear pending errors */ pcib_write_config(dev, bus, slot, 0, 0xc8, errsts, 2); } }
static void ecc_e31200_chaninfo(struct ecc_e31200_softc *sc, uint32_t dimm_ch, const char *desc) { int size_a, size_b, ecc; size_a = __SHIFTOUT(dimm_ch, MCH_E31200_DIMM_A_SIZE); if (size_a != 0) { ecc_printf(sc, "%s, DIMM A %dMB %s %s\n", desc, size_a * MCH_E31200_DIMM_SIZE_UNIT, (dimm_ch & MCH_E31200_DIMM_A_X16) ? "X16" : "X8", (dimm_ch & MCH_E31200_DIMM_A_DUAL_RANK) ? "DUAL" : "SINGLE"); } size_b = __SHIFTOUT(dimm_ch, MCH_E31200_DIMM_B_SIZE); if (size_b != 0) { ecc_printf(sc, "%s, DIMM B %dMB %s %s\n", desc, size_b * MCH_E31200_DIMM_SIZE_UNIT, (dimm_ch & MCH_E31200_DIMM_B_X16) ? "X16" : "X8", (dimm_ch & MCH_E31200_DIMM_B_DUAL_RANK) ? "DUAL" : "SINGLE"); } if (size_a == 0 && size_b == 0) return; ecc = __SHIFTOUT(dimm_ch, MCH_E31200_DIMM_ECC); if (ecc == MCH_E31200_DIMM_ECC_NONE) ecc_printf(sc, "%s, no ECC active\n", desc); else if (ecc == MCH_E31200_DIMM_ECC_IO) ecc_printf(sc, "%s, ECC active IO\n", desc); else if (ecc == MCH_E31200_DIMM_ECC_LOGIC) ecc_printf(sc, "%s, ECC active logic\n", desc); else ecc_printf(sc, "%s, ECC active IO/logic\n", desc); if (dimm_ch & (MCH_E31200_DIMM_ENHI | MCH_E31200_DIMM_RI)) { ecc_printf(sc, "%s", desc); if (dimm_ch & MCH_E31200_DIMM_RI) kprintf(", rank interleave"); if (dimm_ch & MCH_E31200_DIMM_ENHI) kprintf(", enhanced interleave"); kprintf("\n"); } }
static void ecc_e31200_errlog_ch(struct ecc_e31200_softc *sc, int err0_ofs, int err1_ofs, const char *desc) { uint32_t err0, err1; err0 = CSR_READ_4(sc, err0_ofs); if ((err0 & (MCH_E31200_ERRLOG0_CERRSTS | MCH_E31200_ERRLOG0_MERRSTS)) == 0) return; err1 = CSR_READ_4(sc, err1_ofs); ecc_printf(sc, "%s error @bank %d, rank %d, chunk %d, syndrome %d, " "row %d, col %d\n", desc, __SHIFTOUT(err0, MCH_E31200_ERRLOG0_ERRBANK), __SHIFTOUT(err0, MCH_E31200_ERRLOG0_ERRRANK), __SHIFTOUT(err0, MCH_E31200_ERRLOG0_ERRCHUNK), __SHIFTOUT(err0, MCH_E31200_ERRLOG0_ERRSYND), __SHIFTOUT(err1, MCH_E31200_ERRLOG1_ERRROW), __SHIFTOUT(err1, MCH_E31200_ERRLOG1_ERRCOL)); }
static int ecc_e31200_attach(device_t dev) { struct ecc_e31200_softc *sc = device_get_softc(dev); uint32_t capa, dmfc, mch_barlo, mch_barhi; uint64_t mch_bar; int bus, slot; dev = sc->ecc_device; /* XXX */ bus = pci_get_bus(dev); slot = pci_get_slot(dev); capa = pcib_read_config(dev, bus, slot, 0, PCI_E31200_CAPID0_A, 4); dmfc = __SHIFTOUT(capa, PCI_E31200_CAPID0_A_DMFC); if (dmfc == PCI_E31200_CAPID0_A_DMFC_1333) { ecc_printf(sc, "CAP DDR3 1333 "); } else if (dmfc == PCI_E31200_CAPID0_A_DMFC_1067) { ecc_printf(sc, "CAP DDR3 1067 "); } else if (dmfc == PCI_E31200_CAPID0_A_DMFC_ALL) { ecc_printf(sc, "no CAP "); } else { ecc_printf(sc, "unknown DMFC %#x\n", dmfc); return 0; } if (capa & PCI_E31200_CAPID0_A_ECCDIS) { kprintf("NON-ECC\n"); return 0; } else { kprintf("ECC\n"); } mch_barlo = pcib_read_config(dev, bus, slot, 0, PCI_E31200_MCHBAR_LO, 4); mch_barhi = pcib_read_config(dev, bus, slot, 0, PCI_E31200_MCHBAR_HI, 4); mch_bar = (uint64_t)mch_barlo | (((uint64_t)mch_barhi) << 32); if (bootverbose) ecc_printf(sc, "MCHBAR %jx\n", (uintmax_t)mch_bar); if (mch_bar & PCI_E31200_MCHBAR_LO_EN) { uint64_t map_addr = mch_bar & PCI_E31200_MCHBAR_ADDRMASK; uint32_t dimm_ch0, dimm_ch1; sc->ecc_addr = pmap_mapdev_uncacheable(map_addr, MCH_E31200_SIZE); if (bootverbose) { ecc_printf(sc, "LOG0_C0 %#x\n", CSR_READ_4(sc, MCH_E31200_ERRLOG0_C0)); ecc_printf(sc, "LOG0_C1 %#x\n", CSR_READ_4(sc, MCH_E31200_ERRLOG0_C1)); } dimm_ch0 = CSR_READ_4(sc, MCH_E31200_DIMM_CH0); dimm_ch1 = CSR_READ_4(sc, MCH_E31200_DIMM_CH1); if (bootverbose) { ecc_e31200_chaninfo(sc, dimm_ch0, "channel0"); ecc_e31200_chaninfo(sc, dimm_ch1, "channel1"); } if (((dimm_ch0 | dimm_ch1) & MCH_E31200_DIMM_ECC) == 0) { ecc_printf(sc, "No ECC active\n"); pmap_unmapdev((vm_offset_t)sc->ecc_addr, MCH_E31200_SIZE); return 0; } } ecc_e31200_status(sc); callout_init_mp(&sc->ecc_callout); callout_reset(&sc->ecc_callout, hz, ecc_e31200_callout, sc); return 0; }
static void ecc_x3400_status_ch(struct ecc_x3400_softc *sc, int ofs, int idx) { uint32_t cor, err0, err1; const char *desc0 = NULL, *desc1 = NULL; cor = MCT2_READ_4(ofs); if (cor == 0) return; if (sc->ecc_dimms > 2) { switch (idx) { case 0: desc0 = "channel0, DIMM0"; desc1 = "channel0, DIMM1"; break; case 1: desc0 = "channel0, DIMM2"; break; case 2: desc0 = "channel1, DIMM0"; desc1 = "channel1, DIMM1"; break; case 3: desc0 = "channel1, DIMM2"; break; default: panic("unsupported index %d", idx); } } else { switch (idx) { case 0: desc0 = "channel0, DIMM0 RANK 0/1"; desc1 = "channel0, DIMM0 RANK 2/3"; break; case 1: desc0 = "channel0, DIMM1 RANK 0/1"; desc1 = "channel0, DIMM1 RANK 2/3"; break; case 2: desc0 = "channel1, DIMM0 RANK 0/1"; desc1 = "channel1, DIMM0 RANK 2/3"; break; case 3: desc0 = "channel1, DIMM1 RANK 0/1"; desc1 = "channel1, DIMM1 RANK 2/3"; break; default: panic("unsupported index %d", idx); } } err0 = __SHIFTOUT(cor, PCI_X3400UC_MCT2_COR_DIMM0); if (cor & PCI_X3400UC_MCT2_COR_DIMM0_OV) ecc_printf(sc, "%s has too many errors\n", desc0); else if (err0) ecc_printf(sc, "%s has %d errors", desc0, err0); if (desc1 != NULL) { err1 = __SHIFTOUT(cor, PCI_X3400UC_MCT2_COR_DIMM1); if (cor & PCI_X3400UC_MCT2_COR_DIMM1_OV) ecc_printf(sc, "%s has too many errors\n", desc1); else if (err1) ecc_printf(sc, "%s has %d errors\n", desc1, err1); } MCT2_WRITE_4(ofs, 0); }
static void ecc_e31200_chaninfo(struct ecc_e31200_softc *sc, uint32_t dimm_ch, const char *desc) { int size_a, size_b, ecc; size_a = __SHIFTOUT(dimm_ch, MCH_E31200_DIMM_A_SIZE); if (size_a != 0) { ecc_printf(sc, "%s, DIMM A %dMB %s %s\n", desc, size_a * MCH_E31200_DIMM_SIZE_UNIT, (dimm_ch & MCH_E31200_DIMM_A_X16) ? "X16" : "X8", (dimm_ch & MCH_E31200_DIMM_A_DUAL_RANK) ? "DUAL" : "SINGLE"); } size_b = __SHIFTOUT(dimm_ch, MCH_E31200_DIMM_B_SIZE); if (size_b != 0) { ecc_printf(sc, "%s, DIMM B %dMB %s %s\n", desc, size_b * MCH_E31200_DIMM_SIZE_UNIT, (dimm_ch & MCH_E31200_DIMM_B_X16) ? "X16" : "X8", (dimm_ch & MCH_E31200_DIMM_B_DUAL_RANK) ? "DUAL" : "SINGLE"); } if (size_a == 0 && size_b == 0) return; ecc = __SHIFTOUT(dimm_ch, MCH_E31200_DIMM_ECC); if (ecc == MCH_E31200_DIMM_ECC_NONE) { ecc_printf(sc, "%s, no ECC active\n", desc); } else if (ecc == MCH_E31200_DIMM_ECC_ALL) { ecc_printf(sc, "%s, ECC active IO/logic\n", desc); } else { if (sc->ecc_ver == ECC_E31200_VER_1 || sc->ecc_ver == ECC_E31200_VER_2) { if (ecc == MCH_E31200_DIMM_ECC_IO) ecc_printf(sc, "%s, ECC active IO\n", desc); else ecc_printf(sc, "%s, ECC active logic\n", desc); } else { /* V3 */ ecc_printf(sc, "%s, invalid ECC active 0x%x\n", desc, ecc); } } if (sc->ecc_ver == ECC_E31200_VER_1 || sc->ecc_ver == ECC_E31200_VER_2) { /* This bit is V3 only */ dimm_ch &= ~MCH_E31200_DIMM_HORI; } if (dimm_ch & (MCH_E31200_DIMM_ENHI | MCH_E31200_DIMM_RI | MCH_E31200_DIMM_HORI)) { ecc_printf(sc, "%s", desc); if (dimm_ch & MCH_E31200_DIMM_RI) kprintf(", rank interleave"); if (dimm_ch & MCH_E31200_DIMM_ENHI) kprintf(", enhanced interleave"); if (dimm_ch & MCH_E31200_DIMM_HORI) kprintf(", high order rank interleave"); kprintf("\n"); } }
static int ecc_e31200_attach(device_t dev) { struct ecc_e31200_softc *sc = device_get_softc(dev); uint32_t capa, dmfc, mch_barlo, mch_barhi; uint64_t mch_bar; int bus, slot, dmfc_parsed = 1; dev = sc->ecc_device; /* XXX */ bus = pci_get_bus(dev); slot = pci_get_slot(dev); capa = pcib_read_config(dev, bus, slot, 0, PCI_E31200_CAPID0_A, 4); if (sc->ecc_ver == ECC_E31200_VER_1) { dmfc = __SHIFTOUT(capa, PCI_E31200_CAPID0_A_DMFC); } else { /* V2/V3 */ uint32_t capb; capb = pcib_read_config(dev, bus, slot, 0, PCI_E31200_CAPID0_B, 4); dmfc = __SHIFTOUT(capb, PCI_E31200_CAPID0_B_DMFC); } if (dmfc == PCI_E31200_CAPID0_DMFC_1067) { ecc_printf(sc, "CAP DDR3 1067 "); } else if (dmfc == PCI_E31200_CAPID0_DMFC_1333) { ecc_printf(sc, "CAP DDR3 1333 "); } else { if (sc->ecc_ver == ECC_E31200_VER_1) { if (dmfc == PCI_E31200_CAPID0_DMFC_V1_ALL) ecc_printf(sc, "no CAP "); else dmfc_parsed = 0; } else { /* V2/V3 */ if (dmfc == PCI_E31200_CAPID0_DMFC_1600) ecc_printf(sc, "CAP DDR3 1600 "); else if (dmfc == PCI_E31200_CAPID0_DMFC_1867) ecc_printf(sc, "CAP DDR3 1867 "); else if (dmfc == PCI_E31200_CAPID0_DMFC_2133) ecc_printf(sc, "CAP DDR3 2133 "); else if (dmfc == PCI_E31200_CAPID0_DMFC_2400) ecc_printf(sc, "CAP DDR3 2400 "); else if (dmfc == PCI_E31200_CAPID0_DMFC_2667) ecc_printf(sc, "CAP DDR3 2667 "); else if (dmfc == PCI_E31200_CAPID0_DMFC_2933) ecc_printf(sc, "CAP DDR3 2933 "); else dmfc_parsed = 0; } } if (!dmfc_parsed) { ecc_printf(sc, "unknown DMFC %#x\n", dmfc); return 0; } if (capa & PCI_E31200_CAPID0_A_ECCDIS) { kprintf("NON-ECC\n"); return 0; } else { kprintf("ECC\n"); } mch_barlo = pcib_read_config(dev, bus, slot, 0, PCI_E31200_MCHBAR_LO, 4); mch_barhi = pcib_read_config(dev, bus, slot, 0, PCI_E31200_MCHBAR_HI, 4); mch_bar = (uint64_t)mch_barlo | (((uint64_t)mch_barhi) << 32); if (bootverbose) ecc_printf(sc, "MCHBAR %jx\n", (uintmax_t)mch_bar); if (mch_bar & PCI_E31200_MCHBAR_LO_EN) { uint64_t map_addr = mch_bar & PCI_E31200_MCHBAR_ADDRMASK; uint32_t dimm_ch0, dimm_ch1; int ecc_active; sc->ecc_addr = pmap_mapdev_uncacheable(map_addr, MCH_E31200_SIZE); if (bootverbose) { ecc_printf(sc, "LOG0_C0 %#x\n", CSR_READ_4(sc, MCH_E31200_ERRLOG0_C0)); ecc_printf(sc, "LOG0_C1 %#x\n", CSR_READ_4(sc, MCH_E31200_ERRLOG0_C1)); } dimm_ch0 = CSR_READ_4(sc, MCH_E31200_DIMM_CH0); dimm_ch1 = CSR_READ_4(sc, MCH_E31200_DIMM_CH1); if (bootverbose) { ecc_e31200_chaninfo(sc, dimm_ch0, "channel0"); ecc_e31200_chaninfo(sc, dimm_ch1, "channel1"); } ecc_active = 1; if (sc->ecc_ver == ECC_E31200_VER_1 || sc->ecc_ver == ECC_E31200_VER_2) { if (((dimm_ch0 | dimm_ch1) & MCH_E31200_DIMM_ECC) == MCH_E31200_DIMM_ECC_NONE) { ecc_active = 0; ecc_printf(sc, "No ECC active\n"); } } else { /* V3 */ uint32_t ecc_mode0, ecc_mode1; ecc_mode0 = __SHIFTOUT(dimm_ch0, MCH_E31200_DIMM_ECC); ecc_mode1 = __SHIFTOUT(dimm_ch1, MCH_E31200_DIMM_ECC); /* * Only active ALL/NONE is supported */ if (ecc_mode0 != MCH_E31200_DIMM_ECC_NONE && ecc_mode0 != MCH_E31200_DIMM_ECC_ALL) { ecc_active = 0; ecc_printf(sc, "channel0, invalid ECC " "active 0x%x\n", ecc_mode0); } if (ecc_mode1 != MCH_E31200_DIMM_ECC_NONE && ecc_mode1 != MCH_E31200_DIMM_ECC_ALL) { ecc_active = 0; ecc_printf(sc, "channel1, invalid ECC " "active 0x%x\n", ecc_mode1); } if (ecc_mode0 == MCH_E31200_DIMM_ECC_NONE && ecc_mode1 == MCH_E31200_DIMM_ECC_NONE) { ecc_active = 0; ecc_printf(sc, "No ECC active\n"); } } if (!ecc_active) { pmap_unmapdev((vm_offset_t)sc->ecc_addr, MCH_E31200_SIZE); return 0; } } else { ecc_printf(sc, "MCHBAR is not enabled\n"); } ecc_e31200_status(sc); callout_init_mp(&sc->ecc_callout); callout_reset(&sc->ecc_callout, hz, ecc_e31200_callout, sc); return 0; }