ecc/e3: Split it into two drivers, coremctl(4) and ecc(4)
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 11 Feb 2015 09:06:17 +0000 (17:06 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 12 Feb 2015 08:50:08 +0000 (16:50 +0800)
coremctl(4), which maps the MCHBAR, is now the parent of ecc(4) for
Intel E3 cpus.  This paves way to add Intel Core/E3 support to
memtemp(4).

Tested-by: dillon@ on i3/Haswell and E3/v3
13 files changed:
sys/conf/files
sys/conf/kmod.mk
sys/config/LINT64
sys/config/X86_64_GENERIC
sys/dev/misc/Makefile
sys/dev/misc/coremctl/Makefile [new file with mode: 0644]
sys/dev/misc/coremctl/coremctl.c [new file with mode: 0644]
sys/dev/misc/coremctl/coremctl_if.m [new file with mode: 0644]
sys/dev/misc/coremctl/coremctl_reg.h [new file with mode: 0644]
sys/dev/misc/ecc/Makefile
sys/dev/misc/ecc/ecc_e3.c [new file with mode: 0644]
sys/dev/misc/ecc/ecc_e31200.c [deleted file]
sys/dev/misc/ecc/ecc_e31200_reg.h [deleted file]

index b1e38e9..253ce06 100644 (file)
@@ -1753,8 +1753,10 @@ bus/isa/isa_common.c             optional isa
 bus/isa/isahint.c              optional isa
 bus/isa/pnpeat.c               optional isa
 dev/misc/amdsbwd/amdsbwd.c     optional amdsbwd
+dev/misc/coremctl/coremctl.c   optional coremctl
+dev/misc/coremctl/coremctl_if.m        optional coremctl
 dev/misc/ecc/ecc_amd8000.c     optional ecc
-dev/misc/ecc/ecc_e31200.c      optional ecc
+dev/misc/ecc/ecc_e3.c          optional ecc
 dev/misc/ecc/ecc_e5.c          optional ecc
 # not ready yet
 #dev/misc/ecc/ecc_x3400.c      optional ecc
index a862dfe..04fa171 100644 (file)
@@ -316,7 +316,8 @@ MFILES?= kern/bus_if.m kern/device_if.m bus/iicbus/iicbb_if.m \
     libiconv/iconv_converter_if.m dev/agp/agp_if.m opencrypto/cryptodev_if.m \
     bus/mmc/mmcbus_if.m bus/mmc/mmcbr_if.m \
     dev/virtual/virtio/virtio/virtio_bus_if.m \
-    dev/virtual/virtio/virtio/virtio_if.m
+    dev/virtual/virtio/virtio/virtio_if.m \
+    dev/misc/coremctl/coremctl_if.m
 
 .for _srcsrc in ${MFILES}
 .for _ext in c h
index 4cf1e11..c91bcca 100644 (file)
@@ -1273,6 +1273,7 @@ options           SND_OLDSTEREO
 # Miscellaneous hardware:
 #
 # bktr: Brooktree bt848/848a/849a/878/879 video capture and TV Tuner board
+# coremctl: Intel Core/E3 memory controller (required by ecc(4))
 # ecc: ECC memory controller
 # ipmi: Intelligent Platform Management Interface
 # joy: joystick
@@ -1288,6 +1289,7 @@ options           SND_OLDSTEREO
 #  The Rev 2 host cards use a 32K chunk, on a 32K boundary.
 #  The cards can use an IRQ of 11, 12 or 15.
 
+device         coremctl
 device         ecc
 device         joy0    at isa? port IO_GAME
 device         nrp
index 1b1359f..c3cda37 100644 (file)
@@ -185,6 +185,9 @@ device              wbsio1  at isa? port 0x4e
 device         lm#3    at wbsio?
 # Intel Core and newer CPUs on-die digital thermal sensor support
 device         coretemp
+device         coremctl        # support Intel Core and E3 memory controller
+device         ecc             # support AMD8000, Intel E3 and Intel E5 ECC
+                               # requires coremctl.
 
 # PCCARD (PCMCIA) support
 device         pccard
index 66b5a6d..c041cc2 100644 (file)
@@ -1,4 +1,4 @@
 SUBDIR= amdsbwd cmx cpuctl dcons ecc ichwd ipmi joy kbdmux lpbb \
-       nmdm pcfclock putter snp syscons tbridge
+       nmdm pcfclock putter snp syscons tbridge coremctl
 
 .include <bsd.subdir.mk>
diff --git a/sys/dev/misc/coremctl/Makefile b/sys/dev/misc/coremctl/Makefile
new file mode 100644 (file)
index 0000000..c250409
--- /dev/null
@@ -0,0 +1,5 @@
+KMOD = coremctl
+SRCS = coremctl.c coremctl_if.c
+SRCS += device_if.h bus_if.h pci_if.h pcib_if.h coremctl_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/dev/misc/coremctl/coremctl.c b/sys/dev/misc/coremctl/coremctl.c
new file mode 100644 (file)
index 0000000..db28e1e
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2015 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Sepherosa Ziehau <sepherosa@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bitops.h>
+
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcibus.h>
+#include <bus/pci/pci_cfgreg.h>
+
+#include <vm/pmap.h>
+
+#include "coremctl_if.h"
+#include "pcib_if.h"
+
+#include <dev/misc/coremctl/coremctl_reg.h>
+
+#define COREMCTL_VER_1 1       /* Sandy Bridge */
+#define COREMCTL_VER_2 2       /* Ivy Bridge */
+#define COREMCTL_VER_3 3       /* Haswell */
+
+struct coremctl_type {
+       uint16_t        did;
+       const char      *desc;
+       int             ver;            /* COREMCTL_VER_ */
+};
+
+struct coremctl_softc {
+       device_t        sc_dev;
+       int             sc_ver; /* COREMCTL_VER_ */
+       device_t        sc_ecc;
+       volatile uint8_t *sc_mch;
+};
+
+#define CSR_READ_4(sc, ofs)    (*(volatile uint32_t *)((sc)->sc_mch + (ofs)))
+
+static void    coremctl_identify(driver_t *, device_t);
+static int     coremctl_probe(device_t);
+static int     coremctl_attach(device_t);
+static int     coremctl_detach(device_t);
+static int     coremctl_mch_readreg(device_t, int, uint32_t *);
+static int     coremctl_pci_read_ivar(device_t, device_t, int, uintptr_t *);
+static uint32_t        coremctl_pci_read_config(device_t, device_t, int, int);
+static void    coremctl_pci_write_config(device_t, device_t, int, uint32_t,
+                   int);
+
+static void    coremctl_chaninfo(struct coremctl_softc *, uint32_t,
+                   const char *);
+
+static const struct coremctl_type coremctl_types[] = {
+       { PCI_E3V1_MEMCTL_DID, "Intel E3 memory controller",
+         COREMCTL_VER_1 },
+
+       { PCI_E3V2_MEMCTL_DID, "Intel E3 v2 memory controller",
+         COREMCTL_VER_2 },
+
+       { PCI_E3V3_MEMCTL_DID, "Intel E3 v3 memory controller",
+         COREMCTL_VER_3 },
+
+       { PCI_COREV3_MEMCTL_DID, "Intel i3/i5/i7 Haswell memory controller",
+         COREMCTL_VER_3 },
+
+       { 0, NULL, 0 } /* required last entry */
+};
+
+static device_method_t coremctl_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_identify,      coremctl_identify),
+       DEVMETHOD(device_probe,         coremctl_probe),
+       DEVMETHOD(device_attach,        coremctl_attach),
+       DEVMETHOD(device_detach,        coremctl_detach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_read_ivar,        coremctl_pci_read_ivar),
+
+       /* PCI interface */
+       DEVMETHOD(pci_read_config,      coremctl_pci_read_config),
+       DEVMETHOD(pci_write_config,     coremctl_pci_write_config),
+
+       /* Core memory controller interface */
+       DEVMETHOD(coremctl_mch_read,    coremctl_mch_readreg),
+
+       DEVMETHOD_END
+};
+
+static driver_t coremctl_driver = {
+       "coremctl",
+       coremctl_methods,
+       sizeof(struct coremctl_softc)
+};
+static devclass_t coremctl_devclass;
+
+DRIVER_MODULE(coremctl, hostb, coremctl_driver, coremctl_devclass, NULL, NULL);
+MODULE_VERSION(coremctl, 1);
+MODULE_DEPEND(coremctl, pci, 1, 1, 1);
+
+static void
+coremctl_identify(driver_t *driver, device_t parent)
+{
+       const struct coremctl_type *t;
+       uint16_t did;
+
+       /* Already identified */
+       if (device_find_child(parent, "coremctl", -1) != NULL)
+               return;
+
+       if (pci_get_vendor(parent) != PCI_CORE_MEMCTL_VID)
+               return;
+
+       did = pci_get_device(parent);
+       for (t = coremctl_types; t->desc != NULL; ++t) {
+               if (t->did == did) {
+                       if (device_add_child(parent, "coremctl", -1) == NULL)
+                               device_printf(parent, "add coremctl failed\n");
+                       return;
+               }
+       }
+}
+
+static int
+coremctl_probe(device_t dev)
+{
+       const struct coremctl_type *t;
+       uint16_t did;
+
+       if (pci_get_vendor(dev) != PCI_CORE_MEMCTL_VID)
+               return ENXIO;
+
+       did = pci_get_device(dev);
+       for (t = coremctl_types; t->desc != NULL; ++t) {
+               if (t->did == did) {
+                       struct coremctl_softc *sc = device_get_softc(dev);
+
+                       device_set_desc(dev, t->desc);
+                       sc->sc_ver = t->ver;
+                       return 0;
+               }
+       }
+       return ENXIO;
+}
+
+static int
+coremctl_attach(device_t dev)
+{
+       struct coremctl_softc *sc = device_get_softc(dev);
+       uint32_t capa, dmfc, mch_barlo, mch_barhi;
+       uint64_t mch_bar;
+       int dmfc_parsed = 1;
+
+       sc->sc_dev = dev;
+
+       capa = pci_read_config(dev, PCI_CORE_CAPID0_A, 4);
+
+       if (sc->sc_ver == COREMCTL_VER_1) {
+               dmfc = __SHIFTOUT(capa, PCI_CORE_CAPID0_A_DMFC);
+       } else { /* v2/v3 */
+               uint32_t capb;
+
+               capb = pci_read_config(dev, PCI_CORE_CAPID0_B, 4);
+               dmfc = __SHIFTOUT(capb, PCI_CORE_CAPID0_B_DMFC);
+       }
+
+       if (dmfc == PCI_CORE_CAPID0_DMFC_1067) {
+               device_printf(dev, "CAP DDR3 1067 ");
+       } else if (dmfc == PCI_CORE_CAPID0_DMFC_1333) {
+               device_printf(dev, "CAP DDR3 1333 ");
+       } else {
+               if (sc->sc_ver == COREMCTL_VER_1) {
+                       if (dmfc == PCI_CORE_CAPID0_DMFC_V1_ALL)
+                               device_printf(dev, "no CAP ");
+                       else
+                               dmfc_parsed = 0;
+               } else { /* v2/v3 */
+                       if (dmfc == PCI_CORE_CAPID0_DMFC_1600)
+                               device_printf(dev, "CAP DDR3 1600 ");
+                       else if (dmfc == PCI_CORE_CAPID0_DMFC_1867)
+                               device_printf(dev, "CAP DDR3 1867 ");
+                       else if (dmfc == PCI_CORE_CAPID0_DMFC_2133)
+                               device_printf(dev, "CAP DDR3 2133 ");
+                       else if (dmfc == PCI_CORE_CAPID0_DMFC_2400)
+                               device_printf(dev, "CAP DDR3 2400 ");
+                       else if (dmfc == PCI_CORE_CAPID0_DMFC_2667)
+                               device_printf(dev, "CAP DDR3 2667 ");
+                       else if (dmfc == PCI_CORE_CAPID0_DMFC_2933)
+                               device_printf(dev, "CAP DDR3 2933 ");
+                       else
+                               dmfc_parsed = 0;
+               }
+       }
+       if (!dmfc_parsed) {
+               device_printf(dev, "unknown DMFC %#x\n", dmfc);
+               return 0;
+       }
+
+       if (capa & PCI_CORE_CAPID0_A_ECCDIS) {
+               kprintf("NON-ECC\n");
+       } else {
+               kprintf("ECC\n");
+               sc->sc_ecc = device_add_child(dev, "ecc", -1);
+               if (sc->sc_ecc == NULL)
+                       device_printf(dev, "add ecc failed\n");
+       }
+
+       mch_barlo = pci_read_config(dev, PCI_CORE_MCHBAR_LO, 4);
+       mch_barhi = pci_read_config(dev, PCI_CORE_MCHBAR_HI, 4);
+
+       mch_bar = (uint64_t)mch_barlo | (((uint64_t)mch_barhi) << 32);
+       if (bootverbose)
+               device_printf(dev, "MCHBAR 0x%jx\n", (uintmax_t)mch_bar);
+
+       if (mch_bar & PCI_CORE_MCHBAR_LO_EN) {
+               uint64_t map_addr = mch_bar & PCI_CORE_MCHBAR_ADDRMASK;
+
+               sc->sc_mch = pmap_mapdev_uncacheable(map_addr, MCH_CORE_SIZE);
+
+               if (bootverbose) {
+                       uint32_t dimm_ch0, dimm_ch1;
+
+                       dimm_ch0 = CSR_READ_4(sc, MCH_CORE_DIMM_CH0);
+                       dimm_ch1 = CSR_READ_4(sc, MCH_CORE_DIMM_CH1);
+
+                       coremctl_chaninfo(sc, dimm_ch0, "channel0");
+                       coremctl_chaninfo(sc, dimm_ch1, "channel1");
+               }
+       } else {
+               device_printf(dev, "MCHBAR is not enabled\n");
+       }
+
+       bus_generic_attach(dev);
+
+       return 0;
+}
+
+static void
+coremctl_chaninfo(struct coremctl_softc *sc, uint32_t dimm_ch,
+    const char *desc)
+{
+       int size_a, size_b;
+       int dimma_id, dimmb_id;
+
+       dimma_id = 0;
+       dimmb_id = 1;
+       if (dimm_ch & MCH_CORE_DIMM_A_SELECT) {
+               dimma_id = 1;
+               dimmb_id = 0;
+       }
+
+       size_a = __SHIFTOUT(dimm_ch, MCH_CORE_DIMM_A_SIZE);
+       if (size_a != 0) {
+               device_printf(sc->sc_dev, "%s, DIMM%d %dMB %dx%d\n", desc,
+                   dimma_id, size_a * MCH_CORE_DIMM_SIZE_UNIT,
+                   (dimm_ch & MCH_CORE_DIMM_A_DUAL_RANK) ? 2 : 1,
+                   (dimm_ch & MCH_CORE_DIMM_A_X16) ? 16 : 8);
+       }
+
+       size_b = __SHIFTOUT(dimm_ch, MCH_CORE_DIMM_B_SIZE);
+       if (size_b != 0) {
+               device_printf(sc->sc_dev, "%s, DIMM%d %dMB %dx%d\n", desc,
+                   dimmb_id, size_b * MCH_CORE_DIMM_SIZE_UNIT,
+                   (dimm_ch & MCH_CORE_DIMM_B_DUAL_RANK) ? 2 : 1,
+                   (dimm_ch & MCH_CORE_DIMM_B_X16) ? 16 : 8);
+       }
+
+       if (size_a == 0 && size_b == 0)
+               return;
+
+       if (sc->sc_ver == COREMCTL_VER_1 || sc->sc_ver == COREMCTL_VER_2) {
+               /* This bit is v3 only */
+               dimm_ch &= ~MCH_CORE_DIMM_HORI;
+       }
+       if (dimm_ch & (MCH_CORE_DIMM_ENHI | MCH_CORE_DIMM_RI |
+           MCH_CORE_DIMM_HORI)) {
+               device_printf(sc->sc_dev, "%s", desc);
+               if (dimm_ch & MCH_CORE_DIMM_RI)
+                       kprintf(", rank interleave");
+               if (dimm_ch & MCH_CORE_DIMM_ENHI)
+                       kprintf(", enhanced interleave");
+               if (dimm_ch & MCH_CORE_DIMM_HORI)
+                       kprintf(", high order rank interleave");
+               kprintf("\n");
+       }
+}
+
+static int
+coremctl_detach(device_t dev)
+{
+       struct coremctl_softc *sc = device_get_softc(dev);
+
+       if (sc->sc_ecc != NULL)
+               device_delete_child(dev, sc->sc_ecc);
+       bus_generic_detach(dev);
+
+       if (sc->sc_mch != NULL)
+               pmap_unmapdev((vm_offset_t)sc->sc_mch, MCH_CORE_SIZE);
+       return 0;
+}
+
+static int
+coremctl_mch_readreg(device_t dev, int reg, uint32_t *val)
+{
+       struct coremctl_softc *sc = device_get_softc(dev);
+
+       if (sc->sc_mch == NULL)
+               return EOPNOTSUPP;
+
+       *val = CSR_READ_4(sc, reg);
+       return 0;
+}
+
+static int
+coremctl_pci_read_ivar(device_t dev, device_t child, int which,
+    uintptr_t *result)
+{
+       return BUS_READ_IVAR(device_get_parent(dev), dev, which, result);
+}
+
+static uint32_t
+coremctl_pci_read_config(device_t dev, device_t child, int reg, int width)
+{
+       return pci_read_config(dev, reg, width);
+}
+
+static void
+coremctl_pci_write_config(device_t dev, device_t child, int reg, uint32_t val,
+    int width)
+{
+       pci_write_config(dev, reg, val, width);
+}
diff --git a/sys/dev/misc/coremctl/coremctl_if.m b/sys/dev/misc/coremctl/coremctl_if.m
new file mode 100644 (file)
index 0000000..b9fa263
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sys/bus.h>
+
+INTERFACE coremctl;
+
+METHOD int mch_read {
+       device_t                dev;
+       int                     reg;
+       uint32_t                *val;
+};
diff --git a/sys/dev/misc/coremctl/coremctl_reg.h b/sys/dev/misc/coremctl/coremctl_reg.h
new file mode 100644 (file)
index 0000000..bea78a6
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef _COREMCTL_REG_H_
+#define _COREMCTL_REG_H_
+
+#ifndef _SYS_BITOPS_H_
+#include <sys/bitops.h>
+#endif
+
+#define PCI_CORE_MEMCTL_VID            0x8086
+#define PCI_E3V1_MEMCTL_DID            0x0108
+#define PCI_E3V2_MEMCTL_DID            0x0158
+#define PCI_E3V3_MEMCTL_DID            0x0c08
+#define PCI_COREV3_MEMCTL_DID          0x0c00
+
+#define PCI_CORE_MCHBAR_LO             0x48
+#define PCI_CORE_MCHBAR_LO_EN          0x1
+#define PCI_CORE_MCHBAR_HI             0x4c
+
+#define PCI_E3_ERRSTS                  0xc8
+#define PCI_E3_ERRSTS_DMERR            __BIT(1)
+#define PCI_E3_ERRSTS_DSERR            __BIT(0)
+
+#define PCI_CORE_CAPID0_A              0xe4
+#define PCI_CORE_CAPID0_A_DMFC __BITS(0, 2)    /* v1 */
+#define PCI_CORE_CAPID0_A_ECCDIS       __BIT(25)
+
+#define PCI_CORE_CAPID0_B              0xe8
+#define PCI_CORE_CAPID0_B_DMFC         __BITS(4, 6)    /* v2/v3 */
+
+#define PCI_CORE_CAPID0_DMFC_V1_ALL    0x0     /* v1 */
+#define PCI_CORE_CAPID0_DMFC_2933      0x0     /* v2/v3 */
+#define PCI_CORE_CAPID0_DMFC_2667      0x1     /* v2/v3 */
+#define PCI_CORE_CAPID0_DMFC_2400      0x2     /* v2/v3 */
+#define PCI_CORE_CAPID0_DMFC_2133      0x3     /* v2/v3 */
+#define PCI_CORE_CAPID0_DMFC_1867      0x4     /* v2/v3 */
+#define PCI_CORE_CAPID0_DMFC_1600      0x5     /* v2/v3 */
+#define PCI_CORE_CAPID0_DMFC_1333      0x6
+#define PCI_CORE_CAPID0_DMFC_1067      0x7
+
+#define PCI_CORE_MCHBAR_ADDRMASK       __BITS64(15, 38)
+
+#define MCH_CORE_SIZE                  (32 * 1024)
+
+#define MCH_E3_ERRLOG0_C0              0x40c8
+#define MCH_E3_ERRLOG1_C0              0x40cc
+
+#define MCH_E3_ERRLOG0_C1              0x44c8
+#define MCH_E3_ERRLOG1_C1              0x44cc
+
+#define MCH_E3_ERRLOG0_CERRSTS         __BIT(0)
+#define MCH_E3_ERRLOG0_MERRSTS         __BIT(1)
+#define MCH_E3_ERRLOG0_ERRSYND         __BITS(16, 23)
+#define MCH_E3_ERRLOG0_ERRCHUNK                __BITS(24, 26)
+#define MCH_E3_ERRLOG0_ERRRANK         __BITS(27, 28)
+#define MCH_E3_ERRLOG0_ERRBANK         __BITS(29, 31)
+
+#define MCH_E3_ERRLOG1_ERRROW          __BITS(0, 15)
+#define MCH_E3_ERRLOG1_ERRCOL          __BITS(16, 31)
+
+#define MCH_CORE_DIMM_CH0              0x5004
+#define MCH_CORE_DIMM_CH1              0x5008
+
+#define MCH_CORE_DIMM_SIZE_UNIT        256             /* MB */
+#define MCH_CORE_DIMM_A_SIZE           __BITS(0, 7)
+#define MCH_CORE_DIMM_B_SIZE           __BITS(8, 15)
+#define MCH_CORE_DIMM_A_SELECT         __BIT(16)
+#define MCH_CORE_DIMM_A_DUAL_RANK      __BIT(17)
+#define MCH_CORE_DIMM_B_DUAL_RANK      __BIT(18)
+#define MCH_CORE_DIMM_A_X16            __BIT(19)
+#define MCH_CORE_DIMM_B_X16            __BIT(20)
+#define MCH_CORE_DIMM_RI               __BIT(21)       /* rank interleave */
+/* enchanced interleave */
+#define MCH_CORE_DIMM_ENHI             __BIT(22)
+#define MCH_E3_DIMM_ECC                        __BITS(24, 25)
+#define MCH_E3_DIMM_ECC_NONE           0x0
+#define MCH_E3_DIMM_ECC_IO             0x1
+#define MCH_E3_DIMM_ECC_LOGIC          0x2
+#define MCH_E3_DIMM_ECC_ALL            0x3
+/* high order rank interleave */
+#define MCH_CORE_DIMM_HORI             __BIT(26)       /* v3 */
+/* high order rank interleave address (addr bits [20,27]) */
+#define MCH_CORE_DIMM_HORIADDR         __BITS(27, 29)  /* v3 */
+
+#endif /* !_COREMCTL_REG_H_ */
index dff2e5f..d0cf274 100644 (file)
@@ -1,6 +1,6 @@
 KMOD = ecc
-SRCS = ecc_amd8000.c ecc_e31200.c ecc_e5.c
+SRCS = ecc_amd8000.c ecc_e3.c ecc_e5.c
 #ecc_x3400.c
-SRCS += device_if.h bus_if.h pci_if.h pcib_if.h
+SRCS += device_if.h bus_if.h pci_if.h pcib_if.h coremctl_if.h
 
 .include <bsd.kmod.mk>
diff --git a/sys/dev/misc/ecc/ecc_e3.c b/sys/dev/misc/ecc/ecc_e3.c
new file mode 100644 (file)
index 0000000..1cfba70
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Sepherosa Ziehau <sepherosa@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bitops.h>
+
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcibus.h>
+#include <bus/pci/pci_cfgreg.h>
+
+#include <vm/pmap.h>
+
+#include "coremctl_if.h"
+#include "pcib_if.h"
+
+#include <dev/misc/coremctl/coremctl_reg.h>
+
+#define ECC_E3_VER_1   1       /* Sandy Bridge */
+#define ECC_E3_VER_2   2       /* Ivy Bridge */
+#define ECC_E3_VER_3   3       /* Haswell */
+
+struct ecc_e3_type {
+       uint16_t        did;
+       const char      *desc;
+       int             ver;            /* ECC_E3_VER_ */
+};
+
+struct ecc_e3_softc {
+       device_t        ecc_dev;
+       device_t        ecc_parent;     /* non-NULL if parent has MCHBAR */
+       struct callout  ecc_callout;
+       int             ecc_ver;        /* ECC_E3_VER_ */
+};
+
+#define ecc_printf(sc, fmt, arg...) \
+       device_printf((sc)->ecc_dev, fmt , ##arg)
+
+static int     ecc_e3_probe(device_t);
+static int     ecc_e3_attach(device_t);
+static int     ecc_e3_detach(device_t);
+static void    ecc_e3_shutdown(device_t);
+
+static void    ecc_e3_chaninfo(struct ecc_e3_softc *, uint32_t, const char *);
+static void    ecc_e3_status(struct ecc_e3_softc *);
+static void    ecc_e3_callout(void *);
+static void    ecc_e3_errlog(struct ecc_e3_softc *);
+static void    ecc_e3_errlog_ch(struct ecc_e3_softc *, int, int, const char *);
+
+static const struct ecc_e3_type ecc_e3_types[] = {
+       { PCI_E3V1_MEMCTL_DID, "Intel E3 ECC", ECC_E3_VER_1 },
+       { PCI_E3V2_MEMCTL_DID, "Intel E3 v2 ECC", ECC_E3_VER_2 },
+       { PCI_E3V3_MEMCTL_DID, "Intel E3 v3 ECC", ECC_E3_VER_3 },
+       { 0, NULL, 0 } /* required last entry */
+};
+
+static device_method_t ecc_e3_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         ecc_e3_probe),
+       DEVMETHOD(device_attach,        ecc_e3_attach),
+       DEVMETHOD(device_detach,        ecc_e3_detach),
+       DEVMETHOD(device_shutdown,      ecc_e3_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+       DEVMETHOD_END
+};
+
+static driver_t ecc_e3_driver = {
+       "ecc",
+       ecc_e3_methods,
+       sizeof(struct ecc_e3_softc)
+};
+static devclass_t ecc_devclass;
+DRIVER_MODULE(ecc_e3, coremctl, ecc_e3_driver, ecc_devclass, NULL, NULL);
+MODULE_DEPEND(ecc_e3, pci, 1, 1, 1);
+MODULE_DEPEND(ecc_e3, coremctl, 1, 1, 1);
+
+static __inline uint32_t
+CSR_READ_4(struct ecc_e3_softc *sc, int ofs)
+{
+       uint32_t val;
+       int error;
+
+       error = COREMCTL_MCH_READ(sc->ecc_parent, ofs, &val);
+       KASSERT(!error, ("mch read failed"));
+
+       return val;
+}
+
+static int
+ecc_e3_probe(device_t dev)
+{
+       const struct ecc_e3_type *t;
+       uint16_t did;
+
+       if (pci_get_vendor(dev) != PCI_CORE_MEMCTL_VID)
+               return ENXIO;
+
+       did = pci_get_device(dev);
+       for (t = ecc_e3_types; t->desc != NULL; ++t) {
+               if (t->did == did) {
+                       struct ecc_e3_softc *sc = device_get_softc(dev);
+
+                       device_set_desc(dev, t->desc);
+                       sc->ecc_ver = t->ver;
+                       return 0;
+               }
+       }
+       return ENXIO;
+}
+
+static int
+ecc_e3_attach(device_t dev)
+{
+       struct ecc_e3_softc *sc = device_get_softc(dev);
+       uint32_t val;
+       int error;
+
+       callout_init_mp(&sc->ecc_callout);
+       sc->ecc_dev = dev;
+
+       /* Probe the existance of MCHBAR */
+       error = COREMCTL_MCH_READ(device_get_parent(dev), MCH_CORE_DIMM_CH0,
+           &val);
+       if (!error)
+               sc->ecc_parent = device_get_parent(dev);
+
+       if (sc->ecc_parent != NULL) {
+               uint32_t dimm_ch0, dimm_ch1;
+               int ecc_active;
+
+               if (bootverbose) {
+                       ecc_printf(sc, "LOG0_C0 %#x\n",
+                           CSR_READ_4(sc, MCH_E3_ERRLOG0_C0));
+                       ecc_printf(sc, "LOG0_C1 %#x\n",
+                           CSR_READ_4(sc, MCH_E3_ERRLOG0_C1));
+               }
+
+               dimm_ch0 = CSR_READ_4(sc, MCH_CORE_DIMM_CH0);
+               dimm_ch1 = CSR_READ_4(sc, MCH_CORE_DIMM_CH1);
+
+               if (bootverbose) {
+                       ecc_e3_chaninfo(sc, dimm_ch0, "channel0");
+                       ecc_e3_chaninfo(sc, dimm_ch1, "channel1");
+               }
+
+               ecc_active = 1;
+               if (sc->ecc_ver == ECC_E3_VER_1 ||
+                   sc->ecc_ver == ECC_E3_VER_2) {
+                       if (((dimm_ch0 | dimm_ch1) & MCH_E3_DIMM_ECC) ==
+                           MCH_E3_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_E3_DIMM_ECC);
+                       ecc_mode1 = __SHIFTOUT(dimm_ch1, MCH_E3_DIMM_ECC);
+
+                       /*
+                        * Only active ALL/NONE is supported
+                        */
+
+                       if (ecc_mode0 != MCH_E3_DIMM_ECC_NONE &&
+                           ecc_mode0 != MCH_E3_DIMM_ECC_ALL) {
+                               ecc_active = 0;
+                               ecc_printf(sc, "channel0, invalid ECC "
+                                   "active 0x%x\n", ecc_mode0);
+                       }
+                       if (ecc_mode1 != MCH_E3_DIMM_ECC_NONE &&
+                           ecc_mode1 != MCH_E3_DIMM_ECC_ALL) {
+                               ecc_active = 0;
+                               ecc_printf(sc, "channel1, invalid ECC "
+                                   "active 0x%x\n", ecc_mode1);
+                       }
+
+                       if (ecc_mode0 == MCH_E3_DIMM_ECC_NONE &&
+                           ecc_mode1 == MCH_E3_DIMM_ECC_NONE) {
+                               ecc_active = 0;
+                               ecc_printf(sc, "No ECC active\n");
+                       }
+               }
+
+               if (!ecc_active)
+                       return 0;
+       } else {
+               ecc_printf(sc, "MCHBAR is not enabled\n");
+       }
+
+       ecc_e3_status(sc);
+       callout_reset(&sc->ecc_callout, hz, ecc_e3_callout, sc);
+
+       return 0;
+}
+
+static void
+ecc_e3_callout(void *xsc)
+{
+       struct ecc_e3_softc *sc = xsc;
+
+       ecc_e3_status(sc);
+       callout_reset(&sc->ecc_callout, hz, ecc_e3_callout, sc);
+}
+
+static void
+ecc_e3_status(struct ecc_e3_softc *sc)
+{
+       device_t dev = sc->ecc_dev;
+       uint16_t errsts;
+
+       errsts = pci_read_config(dev, PCI_E3_ERRSTS, 2);
+       if (errsts & PCI_E3_ERRSTS_DMERR)
+               ecc_printf(sc, "Uncorrectable multilple-bit ECC error\n");
+       else if (errsts & PCI_E3_ERRSTS_DSERR)
+               ecc_printf(sc, "Correctable single-bit ECC error\n");
+
+       if (errsts & (PCI_E3_ERRSTS_DSERR | PCI_E3_ERRSTS_DMERR)) {
+               if (sc->ecc_parent != NULL)
+                       ecc_e3_errlog(sc);
+
+               /* Clear pending errors */
+               pci_write_config(dev, PCI_E3_ERRSTS, errsts, 2);
+       }
+}
+
+static void
+ecc_e3_chaninfo(struct ecc_e3_softc *sc, uint32_t dimm_ch, const char *desc)
+{
+       int size_a, size_b, ecc;
+
+       size_a = __SHIFTOUT(dimm_ch, MCH_CORE_DIMM_A_SIZE);
+       size_b = __SHIFTOUT(dimm_ch, MCH_CORE_DIMM_B_SIZE);
+       if (size_a == 0 && size_b == 0)
+               return;
+
+       ecc = __SHIFTOUT(dimm_ch, MCH_E3_DIMM_ECC);
+       if (ecc == MCH_E3_DIMM_ECC_NONE) {
+               ecc_printf(sc, "%s, no ECC active\n", desc);
+       } else if (ecc == MCH_E3_DIMM_ECC_ALL) {
+               ecc_printf(sc, "%s, ECC active IO/logic\n", desc);
+       } else {
+               if (sc->ecc_ver == ECC_E3_VER_1 ||
+                   sc->ecc_ver == ECC_E3_VER_2) {
+                       if (ecc == MCH_E3_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);
+               }
+       }
+}
+
+static void
+ecc_e3_errlog(struct ecc_e3_softc *sc)
+{
+       ecc_e3_errlog_ch(sc, MCH_E3_ERRLOG0_C0, MCH_E3_ERRLOG1_C0,
+           "channel0");
+       ecc_e3_errlog_ch(sc, MCH_E3_ERRLOG0_C1, MCH_E3_ERRLOG1_C1,
+           "channel1");
+}
+
+static void
+ecc_e3_errlog_ch(struct ecc_e3_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_E3_ERRLOG0_CERRSTS | MCH_E3_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_E3_ERRLOG0_ERRBANK),
+           __SHIFTOUT(err0, MCH_E3_ERRLOG0_ERRRANK),
+           __SHIFTOUT(err0, MCH_E3_ERRLOG0_ERRCHUNK),
+           __SHIFTOUT(err0, MCH_E3_ERRLOG0_ERRSYND),
+           __SHIFTOUT(err1, MCH_E3_ERRLOG1_ERRROW),
+           __SHIFTOUT(err1, MCH_E3_ERRLOG1_ERRCOL));
+}
+
+static int
+ecc_e3_detach(device_t dev)
+{
+       struct ecc_e3_softc *sc = device_get_softc(dev);
+
+       callout_stop_sync(&sc->ecc_callout);
+       return 0;
+}
+
+static void
+ecc_e3_shutdown(device_t dev)
+{
+       struct ecc_e3_softc *sc = device_get_softc(dev);
+
+       callout_stop_sync(&sc->ecc_callout);
+}
diff --git a/sys/dev/misc/ecc/ecc_e31200.c b/sys/dev/misc/ecc/ecc_e31200.c
deleted file mode 100644 (file)
index 1485691..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
- *
- * This code is derived from software contributed to The DragonFly Project
- * by Sepherosa Ziehau <sepherosa@gmail.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name of The DragonFly Project nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific, prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
- * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/bitops.h>
-
-#include <bus/pci/pcivar.h>
-#include <bus/pci/pcireg.h>
-#include <bus/pci/pcibus.h>
-#include <bus/pci/pci_cfgreg.h>
-
-#include <vm/pmap.h>
-
-#include "pcib_if.h"
-
-#include <dev/misc/ecc/ecc_e31200_reg.h>
-
-#define ECC_E31200_VER_1       1       /* Sandy Bridge */
-#define ECC_E31200_VER_2       2       /* Ivy Bridge */
-#define ECC_E31200_VER_3       3       /* Haswell */
-
-struct ecc_e31200_memctrl {
-       uint16_t        vid;
-       uint16_t        did;
-       const char      *desc;
-       int             ver;            /* ECC_E31200_VER_ */
-};
-
-struct ecc_e31200_softc {
-       device_t        ecc_dev;
-       struct callout  ecc_callout;
-       int             ecc_ver;        /* ECC_E31200_VER_ */
-       volatile uint8_t *ecc_addr;
-};
-
-#define CSR_READ_4(sc, ofs)    (*(volatile uint32_t *)((sc)->ecc_addr + (ofs)))
-
-#define ecc_printf(sc, fmt, arg...) \
-       device_printf((sc)->ecc_dev, fmt , ##arg)
-
-static void    ecc_e31200_identify(driver_t *, device_t);
-static int     ecc_e31200_probe(device_t);
-static int     ecc_e31200_attach(device_t);
-static int     ecc_e31200_detach(device_t);
-static void    ecc_e31200_shutdown(device_t);
-
-static void    ecc_e31200_chaninfo(struct ecc_e31200_softc *, uint32_t,
-                   const char *);
-static void    ecc_e31200_status(struct ecc_e31200_softc *);
-static void    ecc_e31200_callout(void *);
-static void    ecc_e31200_errlog(struct ecc_e31200_softc *);
-static void    ecc_e31200_errlog_ch(struct ecc_e31200_softc *, int, int,
-                   const char *);
-
-static const struct ecc_e31200_memctrl ecc_memctrls[] = {
-       { 0x8086, 0x0108, "Intel E3-1200 memory controller",
-         ECC_E31200_VER_1 },
-       { 0x8086, 0x0158, "Intel E3-1200 v2 memory controller",
-         ECC_E31200_VER_2 },
-       { 0x8086, 0x0c08, "Intel E3-1200 v3 memory controller",
-         ECC_E31200_VER_3 },
-       { 0, 0, NULL } /* required last entry */
-};
-
-static device_method_t ecc_e31200_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_identify,      ecc_e31200_identify),
-       DEVMETHOD(device_probe,         ecc_e31200_probe),
-       DEVMETHOD(device_attach,        ecc_e31200_attach),
-       DEVMETHOD(device_detach,        ecc_e31200_detach),
-       DEVMETHOD(device_shutdown,      ecc_e31200_shutdown),
-       DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
-       DEVMETHOD_END
-};
-
-static driver_t ecc_e31200_driver = {
-       "ecc",
-       ecc_e31200_methods,
-       sizeof(struct ecc_e31200_softc)
-};
-static devclass_t ecc_devclass;
-DRIVER_MODULE(ecc_e31200, hostb, ecc_e31200_driver, ecc_devclass, NULL, NULL);
-MODULE_DEPEND(ecc_e31200, pci, 1, 1, 1);
-
-static void
-ecc_e31200_identify(driver_t *driver, device_t parent)
-{
-       const struct ecc_e31200_memctrl *mc;
-       uint16_t vid, did;
-
-       /* Already identified */
-       if (device_find_child(parent, "ecc", -1) != NULL)
-               return;
-
-       vid = pci_get_vendor(parent);
-       did = pci_get_device(parent);
-
-       for (mc = ecc_memctrls; mc->desc != NULL; ++mc) {
-               if (mc->vid == vid && mc->did == did) {
-                       if (device_add_child(parent, "ecc", -1) == NULL)
-                               device_printf(parent, "add ecc child failed\n");
-                       return;
-               }
-       }
-}
-
-static int
-ecc_e31200_probe(device_t dev)
-{
-       const struct ecc_e31200_memctrl *mc;
-       uint16_t vid, did;
-
-       vid = pci_get_vendor(dev);
-       did = pci_get_device(dev);
-
-       for (mc = ecc_memctrls; mc->desc != NULL; ++mc) {
-               if (mc->vid == vid && mc->did == did) {
-                       struct ecc_e31200_softc *sc = device_get_softc(dev);
-
-                       device_set_desc(dev, mc->desc);
-                       sc->ecc_ver = mc->ver;
-                       return (0);
-               }
-       }
-       return (ENXIO);
-}
-
-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 dmfc_parsed = 1;
-
-       callout_init_mp(&sc->ecc_callout);
-       sc->ecc_dev = dev;
-
-       capa = pci_read_config(dev, 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 = pci_read_config(dev, 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 = pci_read_config(dev, PCI_E31200_MCHBAR_LO, 4);
-       mch_barhi = pci_read_config(dev, 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);
-                       sc->ecc_addr = NULL;
-                       return 0;
-               }
-       } else {
-               ecc_printf(sc, "MCHBAR is not enabled\n");
-       }
-
-       ecc_e31200_status(sc);
-       callout_reset(&sc->ecc_callout, hz, ecc_e31200_callout, sc);
-
-       return 0;
-}
-
-static void
-ecc_e31200_callout(void *xsc)
-{
-       struct ecc_e31200_softc *sc = xsc;
-
-       ecc_e31200_status(sc);
-       callout_reset(&sc->ecc_callout, hz, ecc_e31200_callout, sc);
-}
-
-static void
-ecc_e31200_status(struct ecc_e31200_softc *sc)
-{
-       device_t dev = sc->ecc_dev;
-       uint16_t errsts;
-
-       errsts = pci_read_config(dev, 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 */
-               pci_write_config(dev, PCI_E31200_ERRSTS, 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_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 void
-ecc_e31200_errlog(struct ecc_e31200_softc *sc)
-{
-       ecc_e31200_errlog_ch(sc, MCH_E31200_ERRLOG0_C0, MCH_E31200_ERRLOG1_C0,
-           "channel0");
-       ecc_e31200_errlog_ch(sc, MCH_E31200_ERRLOG0_C1, MCH_E31200_ERRLOG1_C1,
-           "channel1");
-}
-
-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_detach(device_t dev)
-{
-       struct ecc_e31200_softc *sc = device_get_softc(dev);
-
-       callout_stop_sync(&sc->ecc_callout);
-       if (sc->ecc_addr != NULL)
-               pmap_unmapdev((vm_offset_t)sc->ecc_addr, MCH_E31200_SIZE);
-       return 0;
-}
-
-static void
-ecc_e31200_shutdown(device_t dev)
-{
-       struct ecc_e31200_softc *sc = device_get_softc(dev);
-
-       callout_stop_sync(&sc->ecc_callout);
-}
diff --git a/sys/dev/misc/ecc/ecc_e31200_reg.h b/sys/dev/misc/ecc/ecc_e31200_reg.h
deleted file mode 100644 (file)
index 69a0766..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef _ECC_E31200_REG_H_
-#define _ECC_E31200_REG_H_
-
-#ifndef _SYS_BITOPS_H_
-#include <sys/bitops.h>
-#endif
-
-#define PCI_E31200_MCHBAR_LO           0x48
-#define PCI_E31200_MCHBAR_LO_EN                0x1
-#define PCI_E31200_MCHBAR_HI           0x4c
-
-#define PCI_E31200_ERRSTS              0xc8
-#define PCI_E31200_ERRSTS_DMERR                __BIT(1)
-#define PCI_E31200_ERRSTS_DSERR                __BIT(0)
-
-#define PCI_E31200_CAPID0_A            0xe4
-#define PCI_E31200_CAPID0_A_DMFC       __BITS(0, 2)    /* V1 */
-#define PCI_E31200_CAPID0_A_ECCDIS     __BIT(25)
-
-#define PCI_E31200_CAPID0_B            0xe8
-#define PCI_E31200_CAPID0_B_DMFC       __BITS(4, 6)    /* V2/V3 */
-
-#define PCI_E31200_CAPID0_DMFC_V1_ALL  0x0     /* V1 */
-#define PCI_E31200_CAPID0_DMFC_2933    0x0     /* V2/V3 */
-#define PCI_E31200_CAPID0_DMFC_2667    0x1     /* V2/V3 */
-#define PCI_E31200_CAPID0_DMFC_2400    0x2     /* V2/V3 */
-#define PCI_E31200_CAPID0_DMFC_2133    0x3     /* V2/V3 */
-#define PCI_E31200_CAPID0_DMFC_1867    0x4     /* V2/V3 */
-#define PCI_E31200_CAPID0_DMFC_1600    0x5     /* V2/V3 */
-#define PCI_E31200_CAPID0_DMFC_1333    0x6
-#define PCI_E31200_CAPID0_DMFC_1067    0x7
-
-#define PCI_E31200_MCHBAR_ADDRMASK     __BITS64(15, 38)
-
-#define MCH_E31200_SIZE                        (32 * 1024)
-
-#define MCH_E31200_ERRLOG0_C0          0x40c8
-#define MCH_E31200_ERRLOG1_C0          0x40cc
-
-#define MCH_E31200_ERRLOG0_C1          0x44c8
-#define MCH_E31200_ERRLOG1_C1          0x44cc
-
-#define MCH_E31200_ERRLOG0_CERRSTS     __BIT(0)
-#define MCH_E31200_ERRLOG0_MERRSTS     __BIT(1)
-#define MCH_E31200_ERRLOG0_ERRSYND     __BITS(16, 23)
-#define MCH_E31200_ERRLOG0_ERRCHUNK    __BITS(24, 26)
-#define MCH_E31200_ERRLOG0_ERRRANK     __BITS(27, 28)
-#define MCH_E31200_ERRLOG0_ERRBANK     __BITS(29, 31)
-
-#define MCH_E31200_ERRLOG1_ERRROW      __BITS(0, 15)
-#define MCH_E31200_ERRLOG1_ERRCOL      __BITS(16, 31)
-
-#define MCH_E31200_DIMM_CH0            0x5004
-#define MCH_E31200_DIMM_CH1            0x5008
-
-#define MCH_E31200_DIMM_SIZE_UNIT      256             /* MB */
-#define MCH_E31200_DIMM_A_SIZE         __BITS(0, 7)
-#define MCH_E31200_DIMM_B_SIZE         __BITS(8, 15)
-#define MCH_E31200_DIMM_A_DUAL_RANK    __BIT(17)
-#define MCH_E31200_DIMM_B_DUAL_RANK    __BIT(18)
-#define MCH_E31200_DIMM_A_X16          __BIT(19)
-#define MCH_E31200_DIMM_B_X16          __BIT(20)
-#define MCH_E31200_DIMM_RI             __BIT(21)       /* rank interleave */
-/* enchanced interleave */
-#define MCH_E31200_DIMM_ENHI           __BIT(22)
-#define MCH_E31200_DIMM_ECC            __BITS(24, 25)
-#define MCH_E31200_DIMM_ECC_NONE       0x0
-#define MCH_E31200_DIMM_ECC_IO         0x1
-#define MCH_E31200_DIMM_ECC_LOGIC      0x2
-#define MCH_E31200_DIMM_ECC_ALL                0x3
-/* high order rank interleave */
-#define MCH_E31200_DIMM_HORI           __BIT(26)       /* V3 */
-/* high order rank interleave address (addr bits [20,27]) */
-#define MCH_E31200_DIMM_HORIADDR       __BITS(27, 29)  /* V3 */
-
-#endif /* !_ECC_E31200_REG_H_ */