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_e31200_reg.h>
54 #define ECC_E31200_VER_1 1 /* Sandy Bridge */
55 #define ECC_E31200_VER_2 2 /* Ivy Bridge */
56 #define ECC_E31200_VER_3 3 /* Haswell */
58 struct ecc_e31200_memctrl
{
62 int ver
; /* ECC_E31200_VER_ */
65 struct ecc_e31200_softc
{
68 struct callout ecc_callout
;
69 int ecc_ver
; /* ECC_E31200_VER_ */
70 volatile uint8_t *ecc_addr
;
73 #define CSR_READ_4(sc, ofs) (*(volatile uint32_t *)((sc)->ecc_addr + (ofs)))
75 #define ecc_printf(sc, fmt, arg...) \
76 device_printf((sc)->ecc_mydev, fmt , ##arg)
78 static int ecc_e31200_probe(device_t
);
79 static int ecc_e31200_attach(device_t
);
80 static int ecc_e31200_detach(device_t
);
81 static void ecc_e31200_shutdown(device_t
);
83 static void ecc_e31200_chaninfo(struct ecc_e31200_softc
*, uint32_t,
85 static void ecc_e31200_status(struct ecc_e31200_softc
*);
86 static void ecc_e31200_callout(void *);
87 static void ecc_e31200_errlog(struct ecc_e31200_softc
*);
88 static void ecc_e31200_errlog_ch(struct ecc_e31200_softc
*, int, int,
91 static const struct ecc_e31200_memctrl ecc_memctrls
[] = {
92 { 0x8086, 0x0108, "Intel E3-1200 memory controller",
94 { 0x8086, 0x0158, "Intel E3-1200 v2 memory controller",
96 { 0x8086, 0x0c08, "Intel E3-1200 v3 memory controller",
98 { 0, 0, NULL
} /* required last entry */
101 static device_method_t ecc_e31200_methods
[] = {
102 /* Device interface */
103 DEVMETHOD(device_probe
, ecc_e31200_probe
),
104 DEVMETHOD(device_attach
, ecc_e31200_attach
),
105 DEVMETHOD(device_detach
, ecc_e31200_detach
),
106 DEVMETHOD(device_shutdown
, ecc_e31200_shutdown
),
107 DEVMETHOD(device_suspend
, bus_generic_suspend
),
108 DEVMETHOD(device_resume
, bus_generic_resume
),
112 static driver_t ecc_e31200_driver
= {
115 sizeof(struct ecc_e31200_softc
)
117 static devclass_t ecc_devclass
;
118 DRIVER_MODULE(ecc_e31200
, hostb
, ecc_e31200_driver
, ecc_devclass
, NULL
, NULL
);
119 MODULE_DEPEND(ecc_e31200
, pci
, 1, 1, 1);
122 ecc_e31200_probe(device_t dev
)
124 const struct ecc_e31200_memctrl
*mc
;
127 vid
= pci_get_vendor(dev
);
128 did
= pci_get_device(dev
);
130 for (mc
= ecc_memctrls
; mc
->desc
!= NULL
; ++mc
) {
131 if (mc
->vid
== vid
&& mc
->did
== did
) {
132 struct ecc_e31200_softc
*sc
= device_get_softc(dev
);
134 device_set_desc(dev
, mc
->desc
);
136 sc
->ecc_device
= device_get_parent(dev
);
137 sc
->ecc_ver
= mc
->ver
;
145 ecc_e31200_attach(device_t dev
)
147 struct ecc_e31200_softc
*sc
= device_get_softc(dev
);
148 uint32_t capa
, dmfc
, mch_barlo
, mch_barhi
;
150 int bus
, slot
, dmfc_parsed
= 1;
152 callout_init_mp(&sc
->ecc_callout
);
154 dev
= sc
->ecc_device
; /* XXX */
156 bus
= pci_get_bus(dev
);
157 slot
= pci_get_slot(dev
);
159 capa
= pcib_read_config(dev
, bus
, slot
, 0, PCI_E31200_CAPID0_A
, 4);
161 if (sc
->ecc_ver
== ECC_E31200_VER_1
) {
162 dmfc
= __SHIFTOUT(capa
, PCI_E31200_CAPID0_A_DMFC
);
166 capb
= pcib_read_config(dev
, bus
, slot
, 0,
167 PCI_E31200_CAPID0_B
, 4);
168 dmfc
= __SHIFTOUT(capb
, PCI_E31200_CAPID0_B_DMFC
);
171 if (dmfc
== PCI_E31200_CAPID0_DMFC_1067
) {
172 ecc_printf(sc
, "CAP DDR3 1067 ");
173 } else if (dmfc
== PCI_E31200_CAPID0_DMFC_1333
) {
174 ecc_printf(sc
, "CAP DDR3 1333 ");
176 if (sc
->ecc_ver
== ECC_E31200_VER_1
) {
177 if (dmfc
== PCI_E31200_CAPID0_DMFC_V1_ALL
)
178 ecc_printf(sc
, "no CAP ");
182 if (dmfc
== PCI_E31200_CAPID0_DMFC_1600
)
183 ecc_printf(sc
, "CAP DDR3 1600 ");
184 else if (dmfc
== PCI_E31200_CAPID0_DMFC_1867
)
185 ecc_printf(sc
, "CAP DDR3 1867 ");
186 else if (dmfc
== PCI_E31200_CAPID0_DMFC_2133
)
187 ecc_printf(sc
, "CAP DDR3 2133 ");
188 else if (dmfc
== PCI_E31200_CAPID0_DMFC_2400
)
189 ecc_printf(sc
, "CAP DDR3 2400 ");
190 else if (dmfc
== PCI_E31200_CAPID0_DMFC_2667
)
191 ecc_printf(sc
, "CAP DDR3 2667 ");
192 else if (dmfc
== PCI_E31200_CAPID0_DMFC_2933
)
193 ecc_printf(sc
, "CAP DDR3 2933 ");
199 ecc_printf(sc
, "unknown DMFC %#x\n", dmfc
);
203 if (capa
& PCI_E31200_CAPID0_A_ECCDIS
) {
204 kprintf("NON-ECC\n");
210 mch_barlo
= pcib_read_config(dev
, bus
, slot
, 0,
211 PCI_E31200_MCHBAR_LO
, 4);
212 mch_barhi
= pcib_read_config(dev
, bus
, slot
, 0,
213 PCI_E31200_MCHBAR_HI
, 4);
215 mch_bar
= (uint64_t)mch_barlo
| (((uint64_t)mch_barhi
) << 32);
217 ecc_printf(sc
, "MCHBAR %jx\n", (uintmax_t)mch_bar
);
219 if (mch_bar
& PCI_E31200_MCHBAR_LO_EN
) {
220 uint64_t map_addr
= mch_bar
& PCI_E31200_MCHBAR_ADDRMASK
;
221 uint32_t dimm_ch0
, dimm_ch1
;
224 sc
->ecc_addr
= pmap_mapdev_uncacheable(map_addr
,
228 ecc_printf(sc
, "LOG0_C0 %#x\n",
229 CSR_READ_4(sc
, MCH_E31200_ERRLOG0_C0
));
230 ecc_printf(sc
, "LOG0_C1 %#x\n",
231 CSR_READ_4(sc
, MCH_E31200_ERRLOG0_C1
));
234 dimm_ch0
= CSR_READ_4(sc
, MCH_E31200_DIMM_CH0
);
235 dimm_ch1
= CSR_READ_4(sc
, MCH_E31200_DIMM_CH1
);
238 ecc_e31200_chaninfo(sc
, dimm_ch0
, "channel0");
239 ecc_e31200_chaninfo(sc
, dimm_ch1
, "channel1");
243 if (sc
->ecc_ver
== ECC_E31200_VER_1
||
244 sc
->ecc_ver
== ECC_E31200_VER_2
) {
245 if (((dimm_ch0
| dimm_ch1
) & MCH_E31200_DIMM_ECC
) ==
246 MCH_E31200_DIMM_ECC_NONE
) {
248 ecc_printf(sc
, "No ECC active\n");
251 uint32_t ecc_mode0
, ecc_mode1
;
253 ecc_mode0
= __SHIFTOUT(dimm_ch0
, MCH_E31200_DIMM_ECC
);
254 ecc_mode1
= __SHIFTOUT(dimm_ch1
, MCH_E31200_DIMM_ECC
);
257 * Only active ALL/NONE is supported
260 if (ecc_mode0
!= MCH_E31200_DIMM_ECC_NONE
&&
261 ecc_mode0
!= MCH_E31200_DIMM_ECC_ALL
) {
263 ecc_printf(sc
, "channel0, invalid ECC "
264 "active 0x%x\n", ecc_mode0
);
266 if (ecc_mode1
!= MCH_E31200_DIMM_ECC_NONE
&&
267 ecc_mode1
!= MCH_E31200_DIMM_ECC_ALL
) {
269 ecc_printf(sc
, "channel1, invalid ECC "
270 "active 0x%x\n", ecc_mode1
);
273 if (ecc_mode0
== MCH_E31200_DIMM_ECC_NONE
&&
274 ecc_mode1
== MCH_E31200_DIMM_ECC_NONE
) {
276 ecc_printf(sc
, "No ECC active\n");
281 pmap_unmapdev((vm_offset_t
)sc
->ecc_addr
,
287 ecc_printf(sc
, "MCHBAR is not enabled\n");
290 ecc_e31200_status(sc
);
291 callout_reset(&sc
->ecc_callout
, hz
, ecc_e31200_callout
, sc
);
297 ecc_e31200_callout(void *xsc
)
299 struct ecc_e31200_softc
*sc
= xsc
;
301 ecc_e31200_status(sc
);
302 callout_reset(&sc
->ecc_callout
, hz
, ecc_e31200_callout
, sc
);
306 ecc_e31200_status(struct ecc_e31200_softc
*sc
)
308 device_t dev
= sc
->ecc_device
;
312 bus
= pci_get_bus(dev
);
313 slot
= pci_get_slot(dev
);
315 errsts
= pcib_read_config(dev
, bus
, slot
, 0, PCI_E31200_ERRSTS
, 2);
316 if (errsts
& PCI_E31200_ERRSTS_DMERR
)
317 ecc_printf(sc
, "Uncorrectable multilple-bit ECC error\n");
318 else if (errsts
& PCI_E31200_ERRSTS_DSERR
)
319 ecc_printf(sc
, "Correctable single-bit ECC error\n");
321 if (errsts
& (PCI_E31200_ERRSTS_DSERR
| PCI_E31200_ERRSTS_DMERR
)) {
322 if (sc
->ecc_addr
!= NULL
)
323 ecc_e31200_errlog(sc
);
325 /* Clear pending errors */
326 pcib_write_config(dev
, bus
, slot
, 0, PCI_E31200_ERRSTS
,
332 ecc_e31200_chaninfo(struct ecc_e31200_softc
*sc
, uint32_t dimm_ch
,
335 int size_a
, size_b
, ecc
;
337 size_a
= __SHIFTOUT(dimm_ch
, MCH_E31200_DIMM_A_SIZE
);
339 ecc_printf(sc
, "%s, DIMM A %dMB %s %s\n", desc
,
340 size_a
* MCH_E31200_DIMM_SIZE_UNIT
,
341 (dimm_ch
& MCH_E31200_DIMM_A_X16
) ? "X16" : "X8",
342 (dimm_ch
& MCH_E31200_DIMM_A_DUAL_RANK
) ?
346 size_b
= __SHIFTOUT(dimm_ch
, MCH_E31200_DIMM_B_SIZE
);
348 ecc_printf(sc
, "%s, DIMM B %dMB %s %s\n", desc
,
349 size_b
* MCH_E31200_DIMM_SIZE_UNIT
,
350 (dimm_ch
& MCH_E31200_DIMM_B_X16
) ? "X16" : "X8",
351 (dimm_ch
& MCH_E31200_DIMM_B_DUAL_RANK
) ?
355 if (size_a
== 0 && size_b
== 0)
358 ecc
= __SHIFTOUT(dimm_ch
, MCH_E31200_DIMM_ECC
);
359 if (ecc
== MCH_E31200_DIMM_ECC_NONE
) {
360 ecc_printf(sc
, "%s, no ECC active\n", desc
);
361 } else if (ecc
== MCH_E31200_DIMM_ECC_ALL
) {
362 ecc_printf(sc
, "%s, ECC active IO/logic\n", desc
);
364 if (sc
->ecc_ver
== ECC_E31200_VER_1
||
365 sc
->ecc_ver
== ECC_E31200_VER_2
) {
366 if (ecc
== MCH_E31200_DIMM_ECC_IO
)
367 ecc_printf(sc
, "%s, ECC active IO\n", desc
);
369 ecc_printf(sc
, "%s, ECC active logic\n", desc
);
371 ecc_printf(sc
, "%s, invalid ECC active 0x%x\n",
376 if (sc
->ecc_ver
== ECC_E31200_VER_1
||
377 sc
->ecc_ver
== ECC_E31200_VER_2
) {
378 /* This bit is V3 only */
379 dimm_ch
&= ~MCH_E31200_DIMM_HORI
;
381 if (dimm_ch
& (MCH_E31200_DIMM_ENHI
| MCH_E31200_DIMM_RI
|
382 MCH_E31200_DIMM_HORI
)) {
383 ecc_printf(sc
, "%s", desc
);
384 if (dimm_ch
& MCH_E31200_DIMM_RI
)
385 kprintf(", rank interleave");
386 if (dimm_ch
& MCH_E31200_DIMM_ENHI
)
387 kprintf(", enhanced interleave");
388 if (dimm_ch
& MCH_E31200_DIMM_HORI
)
389 kprintf(", high order rank interleave");
395 ecc_e31200_errlog(struct ecc_e31200_softc
*sc
)
397 ecc_e31200_errlog_ch(sc
, MCH_E31200_ERRLOG0_C0
, MCH_E31200_ERRLOG1_C0
,
399 ecc_e31200_errlog_ch(sc
, MCH_E31200_ERRLOG0_C1
, MCH_E31200_ERRLOG1_C1
,
404 ecc_e31200_errlog_ch(struct ecc_e31200_softc
*sc
,
405 int err0_ofs
, int err1_ofs
, const char *desc
)
409 err0
= CSR_READ_4(sc
, err0_ofs
);
410 if ((err0
& (MCH_E31200_ERRLOG0_CERRSTS
| MCH_E31200_ERRLOG0_MERRSTS
))
414 err1
= CSR_READ_4(sc
, err1_ofs
);
416 ecc_printf(sc
, "%s error @bank %d, rank %d, chunk %d, syndrome %d, "
417 "row %d, col %d\n", desc
,
418 __SHIFTOUT(err0
, MCH_E31200_ERRLOG0_ERRBANK
),
419 __SHIFTOUT(err0
, MCH_E31200_ERRLOG0_ERRRANK
),
420 __SHIFTOUT(err0
, MCH_E31200_ERRLOG0_ERRCHUNK
),
421 __SHIFTOUT(err0
, MCH_E31200_ERRLOG0_ERRSYND
),
422 __SHIFTOUT(err1
, MCH_E31200_ERRLOG1_ERRROW
),
423 __SHIFTOUT(err1
, MCH_E31200_ERRLOG1_ERRCOL
));
427 ecc_e31200_detach(device_t dev
)
429 struct ecc_e31200_softc
*sc
= device_get_softc(dev
);
431 callout_stop_sync(&sc
->ecc_callout
);
432 if (sc
->ecc_addr
!= NULL
)
433 pmap_unmapdev((vm_offset_t
)sc
->ecc_addr
, MCH_E31200_SIZE
);
438 ecc_e31200_shutdown(device_t dev
)
440 struct ecc_e31200_softc
*sc
= device_get_softc(dev
);
442 callout_stop_sync(&sc
->ecc_callout
);