2 * Copyright (c) 2011 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/bitops.h>
42 #include <bus/pci/pcivar.h>
43 #include <bus/pci/pcireg.h>
44 #include <bus/pci/pcibus.h>
45 #include <bus/pci/pci_cfgreg.h>
46 #include <bus/pci/pcib_private.h>
52 #include <dev/misc/ecc/ecc_x3400_reg.h>
54 #define MC_READ_2(ofs) \
55 pci_cfgregread(PCIBUS_X3400UC, PCISLOT_X3400UC_MC, \
56 PCIFUNC_X3400UC_MC, (ofs), 2)
57 #define MC_READ_4(ofs) \
58 pci_cfgregread(PCIBUS_X3400UC, PCISLOT_X3400UC_MC, \
59 PCIFUNC_X3400UC_MC, (ofs), 4)
61 #define MCT2_READ_2(ofs) \
62 pci_cfgregread(PCIBUS_X3400UC, PCISLOT_X3400UC_MCT2, \
63 PCIFUNC_X3400UC_MCT2, (ofs), 2)
64 #define MCT2_READ_4(ofs) \
65 pci_cfgregread(PCIBUS_X3400UC, PCISLOT_X3400UC_MCT2, \
66 PCIFUNC_X3400UC_MCT2, (ofs), 4)
67 #define MCT2_WRITE_4(ofs, data) \
68 pci_cfgregwrite(PCIBUS_X3400UC, PCISLOT_X3400UC_MCT2, \
69 PCIFUNC_X3400UC_MCT2, (ofs), data, 4)
71 struct ecc_x3400_memctrl {
77 struct ecc_x3400_softc {
79 struct callout ecc_callout;
83 #define ecc_printf(sc, fmt, arg...) \
84 device_printf((sc)->ecc_mydev, fmt , ##arg)
86 static int ecc_x3400_probe(device_t);
87 static int ecc_x3400_attach(device_t);
89 static void ecc_x3400_status(struct ecc_x3400_softc *);
90 static void ecc_x3400_status_ch(struct ecc_x3400_softc *, int, int);
91 static void ecc_x3400_callout(void *);
93 static const struct ecc_x3400_memctrl ecc_memctrls[] = {
94 { 0x8086, 0xd130, "Intel X3400 memory controller" },
95 { 0, 0, NULL } /* required last entry */
98 static device_method_t ecc_x3400_methods[] = {
99 /* Device interface */
100 DEVMETHOD(device_probe, ecc_x3400_probe),
101 DEVMETHOD(device_attach, ecc_x3400_attach),
102 DEVMETHOD(device_shutdown, bus_generic_shutdown),
103 DEVMETHOD(device_suspend, bus_generic_suspend),
104 DEVMETHOD(device_resume, bus_generic_resume),
108 static driver_t ecc_x3400_driver = {
111 sizeof(struct ecc_x3400_softc)
113 static devclass_t ecc_devclass;
114 DRIVER_MODULE(ecc_x3400, hostb, ecc_x3400_driver, ecc_devclass, NULL, NULL);
115 MODULE_DEPEND(ecc_x3400, pci, 1, 1, 1);
118 ecc_x3400_probe(device_t dev)
120 const struct ecc_x3400_memctrl *mc;
123 vid = pci_get_vendor(dev);
124 did = pci_get_device(dev);
126 for (mc = ecc_memctrls; mc->desc != NULL; ++mc) {
127 if (mc->vid == vid && mc->did == did) {
128 struct ecc_x3400_softc *sc = device_get_softc(dev);
130 if (MC_READ_2(PCIR_VENDOR) != PCI_X3400UC_MC_VID_ID ||
131 MC_READ_2(PCIR_DEVICE) != PCI_X3400UC_MC_DID_ID)
133 if (MCT2_READ_2(PCIR_VENDOR) !=
134 PCI_X3400UC_MCT2_VID_ID ||
135 MCT2_READ_2(PCIR_DEVICE) !=
136 PCI_X3400UC_MCT2_DID_ID)
139 device_set_desc(dev, mc->desc);
148 ecc_x3400_attach(device_t dev)
150 struct ecc_x3400_softc *sc = device_get_softc(dev);
153 val = MC_READ_4(PCI_X3400UC_MC_CTRL);
154 if ((val & PCI_X3400UC_MC_CTRL_ECCEN) == 0) {
155 device_printf(dev, "ECC checking is not enabled\n");
159 val = MC_READ_4(PCI_X3400UC_MC_STS);
160 if ((val & PCI_X3400UC_MC_STS_ECCEN) == 0) {
161 device_printf(dev, "ECC is not enabled\n");
165 val = MC_READ_4(PCI_X3400UC_MC_MAX_DOD);
166 dimms = __SHIFTOUT(val, PCI_X3400UC_MC_MAX_DOD_DIMMS);
167 sc->ecc_dimms = dimms + 1;
168 device_printf(dev, "max dimms %d\n", sc->ecc_dimms);
170 callout_init_mp(&sc->ecc_callout);
171 callout_reset(&sc->ecc_callout, hz, ecc_x3400_callout, sc);
177 ecc_x3400_callout(void *xsc)
179 struct ecc_x3400_softc *sc = xsc;
181 ecc_x3400_status(sc);
182 callout_reset(&sc->ecc_callout, hz, ecc_x3400_callout, sc);
186 ecc_x3400_status(struct ecc_x3400_softc *sc)
188 ecc_x3400_status_ch(sc, PCI_X3400UC_MCT2_COR_ECC_CNT_0, 0);
189 ecc_x3400_status_ch(sc, PCI_X3400UC_MCT2_COR_ECC_CNT_1, 1);
190 ecc_x3400_status_ch(sc, PCI_X3400UC_MCT2_COR_ECC_CNT_2, 2);
191 ecc_x3400_status_ch(sc, PCI_X3400UC_MCT2_COR_ECC_CNT_3, 3);
195 ecc_x3400_status_ch(struct ecc_x3400_softc *sc, int ofs, int idx)
197 uint32_t cor, err0, err1;
198 const char *desc0 = NULL, *desc1 = NULL;
200 cor = MCT2_READ_4(ofs);
204 if (sc->ecc_dimms > 2) {
207 desc0 = "channel0, DIMM0";
208 desc1 = "channel0, DIMM1";
212 desc0 = "channel0, DIMM2";
216 desc0 = "channel1, DIMM0";
217 desc1 = "channel1, DIMM1";
221 desc0 = "channel1, DIMM2";
225 panic("unsupported index %d", idx);
230 desc0 = "channel0, DIMM0 RANK 0/1";
231 desc1 = "channel0, DIMM0 RANK 2/3";
235 desc0 = "channel0, DIMM1 RANK 0/1";
236 desc1 = "channel0, DIMM1 RANK 2/3";
240 desc0 = "channel1, DIMM0 RANK 0/1";
241 desc1 = "channel1, DIMM0 RANK 2/3";
245 desc0 = "channel1, DIMM1 RANK 0/1";
246 desc1 = "channel1, DIMM1 RANK 2/3";
250 panic("unsupported index %d", idx);
254 err0 = __SHIFTOUT(cor, PCI_X3400UC_MCT2_COR_DIMM0);
255 if (cor & PCI_X3400UC_MCT2_COR_DIMM0_OV)
256 ecc_printf(sc, "%s has too many errors\n", desc0);
258 ecc_printf(sc, "%s has %d errors", desc0, err0);
261 err1 = __SHIFTOUT(cor, PCI_X3400UC_MCT2_COR_DIMM1);
262 if (cor & PCI_X3400UC_MCT2_COR_DIMM1_OV)
263 ecc_printf(sc, "%s has too many errors\n", desc1);
265 ecc_printf(sc, "%s has %d errors\n", desc1, err1);
268 MCT2_WRITE_4(ofs, 0);