xref: /dragonfly/sys/dev/misc/coremctl/coremctl.c (revision 0db87cb7)
1 /*
2  * Copyright (c) 2015 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Sepherosa Ziehau <sepherosa@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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
16  *    distribution.
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.
20  *
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
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/bitops.h>
41 
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 
47 #include <vm/pmap.h>
48 
49 #include "coremctl_if.h"
50 #include "pcib_if.h"
51 
52 #include <dev/misc/coremctl/coremctl_reg.h>
53 
54 #define COREMCTL_VER_1	1	/* Sandy Bridge */
55 #define COREMCTL_VER_2	2	/* Ivy Bridge */
56 #define COREMCTL_VER_3	3	/* Haswell */
57 
58 struct coremctl_type {
59 	uint16_t	did;
60 	const char	*desc;
61 	int		ver;		/* COREMCTL_VER_ */
62 };
63 
64 struct coremctl_softc {
65 	device_t	sc_dev;
66 	int		sc_ver;	/* COREMCTL_VER_ */
67 	device_t	sc_ecc;
68 	device_t	sc_temp;
69 	volatile uint8_t *sc_mch;
70 };
71 
72 #define CSR_READ_4(sc, ofs)		\
73 	(*(volatile uint32_t *)((sc)->sc_mch + (ofs)))
74 #define CSR_WRITE_4(sc, ofs, val)	\
75 	(*(volatile uint32_t *)((sc)->sc_mch + (ofs)) = (val))
76 
77 static void	coremctl_identify(driver_t *, device_t);
78 static int	coremctl_probe(device_t);
79 static int	coremctl_attach(device_t);
80 static int	coremctl_detach(device_t);
81 static int	coremctl_mch_readreg(device_t, int, uint32_t *);
82 static int	coremctl_mch_writereg(device_t, int, uint32_t);
83 static int	coremctl_pci_read_ivar(device_t, device_t, int, uintptr_t *);
84 static uint32_t	coremctl_pci_read_config(device_t, device_t, int, int);
85 static void	coremctl_pci_write_config(device_t, device_t, int, uint32_t,
86 		    int);
87 
88 static void	coremctl_chaninfo(struct coremctl_softc *, uint32_t,
89 		    const char *);
90 
91 static const struct coremctl_type coremctl_types[] = {
92 	{ PCI_E3V1_MEMCTL_DID, "Intel E3 memory controller",
93 	  COREMCTL_VER_1 },
94 
95 	{ PCI_E3V2_MEMCTL_DID, "Intel E3 v2 memory controller",
96 	  COREMCTL_VER_2 },
97 
98 	{ PCI_E3V3_MEMCTL_DID, "Intel E3 v3 memory controller",
99 	  COREMCTL_VER_3 },
100 
101 	{ PCI_COREV3_MEMCTL_DID, "Intel i3/i5/i7 Haswell memory controller",
102 	  COREMCTL_VER_3 },
103 
104 	{ 0, NULL, 0 } /* required last entry */
105 };
106 
107 static device_method_t coremctl_methods[] = {
108 	/* Device interface */
109 	DEVMETHOD(device_identify,	coremctl_identify),
110 	DEVMETHOD(device_probe,		coremctl_probe),
111 	DEVMETHOD(device_attach,	coremctl_attach),
112 	DEVMETHOD(device_detach,	coremctl_detach),
113 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
114 	DEVMETHOD(device_suspend,	bus_generic_suspend),
115 	DEVMETHOD(device_resume,	bus_generic_resume),
116 
117 	/* Bus interface */
118 	DEVMETHOD(bus_read_ivar,	coremctl_pci_read_ivar),
119 
120 	/* PCI interface */
121 	DEVMETHOD(pci_read_config,	coremctl_pci_read_config),
122 	DEVMETHOD(pci_write_config,	coremctl_pci_write_config),
123 
124 	/* Core memory controller interface */
125 	DEVMETHOD(coremctl_mch_read,	coremctl_mch_readreg),
126 	DEVMETHOD(coremctl_mch_write,	coremctl_mch_writereg),
127 
128 	DEVMETHOD_END
129 };
130 
131 static driver_t coremctl_driver = {
132 	"coremctl",
133 	coremctl_methods,
134 	sizeof(struct coremctl_softc)
135 };
136 static devclass_t coremctl_devclass;
137 
138 DRIVER_MODULE(coremctl, hostb, coremctl_driver, coremctl_devclass, NULL, NULL);
139 MODULE_VERSION(coremctl, 1);
140 MODULE_DEPEND(coremctl, pci, 1, 1, 1);
141 
142 static void
143 coremctl_identify(driver_t *driver, device_t parent)
144 {
145 	const struct coremctl_type *t;
146 	uint16_t did;
147 
148 	/* Already identified */
149 	if (device_find_child(parent, "coremctl", -1) != NULL)
150 		return;
151 
152 	if (pci_get_vendor(parent) != PCI_CORE_MEMCTL_VID)
153 		return;
154 
155 	did = pci_get_device(parent);
156 	for (t = coremctl_types; t->desc != NULL; ++t) {
157 		if (t->did == did) {
158 			if (device_add_child(parent, "coremctl", -1) == NULL)
159 				device_printf(parent, "add coremctl failed\n");
160 			return;
161 		}
162 	}
163 }
164 
165 static int
166 coremctl_probe(device_t dev)
167 {
168 	const struct coremctl_type *t;
169 	uint16_t did;
170 
171 	if (pci_get_vendor(dev) != PCI_CORE_MEMCTL_VID)
172 		return ENXIO;
173 
174 	did = pci_get_device(dev);
175 	for (t = coremctl_types; t->desc != NULL; ++t) {
176 		if (t->did == did) {
177 			struct coremctl_softc *sc = device_get_softc(dev);
178 
179 			device_set_desc(dev, t->desc);
180 			sc->sc_ver = t->ver;
181 			return 0;
182 		}
183 	}
184 	return ENXIO;
185 }
186 
187 static int
188 coremctl_attach(device_t dev)
189 {
190 	struct coremctl_softc *sc = device_get_softc(dev);
191 	uint32_t capa, dmfc, mch_barlo, mch_barhi;
192 	uint64_t mch_bar;
193 	int dmfc_parsed = 1;
194 
195 	sc->sc_dev = dev;
196 
197 	capa = pci_read_config(dev, PCI_CORE_CAPID0_A, 4);
198 
199 	if (sc->sc_ver == COREMCTL_VER_1) {
200 		dmfc = __SHIFTOUT(capa, PCI_CORE_CAPID0_A_DMFC);
201 	} else { /* v2/v3 */
202 		uint32_t capb;
203 
204 		capb = pci_read_config(dev, PCI_CORE_CAPID0_B, 4);
205 		dmfc = __SHIFTOUT(capb, PCI_CORE_CAPID0_B_DMFC);
206 	}
207 
208 	if (dmfc == PCI_CORE_CAPID0_DMFC_1067) {
209 		device_printf(dev, "CAP DDR3 1067 ");
210 	} else if (dmfc == PCI_CORE_CAPID0_DMFC_1333) {
211 		device_printf(dev, "CAP DDR3 1333 ");
212 	} else {
213 		if (sc->sc_ver == COREMCTL_VER_1) {
214 			if (dmfc == PCI_CORE_CAPID0_DMFC_V1_ALL)
215 				device_printf(dev, "no CAP ");
216 			else
217 				dmfc_parsed = 0;
218 		} else { /* v2/v3 */
219 			if (dmfc == PCI_CORE_CAPID0_DMFC_1600)
220 				device_printf(dev, "CAP DDR3 1600 ");
221 			else if (dmfc == PCI_CORE_CAPID0_DMFC_1867)
222 				device_printf(dev, "CAP DDR3 1867 ");
223 			else if (dmfc == PCI_CORE_CAPID0_DMFC_2133)
224 				device_printf(dev, "CAP DDR3 2133 ");
225 			else if (dmfc == PCI_CORE_CAPID0_DMFC_2400)
226 				device_printf(dev, "CAP DDR3 2400 ");
227 			else if (dmfc == PCI_CORE_CAPID0_DMFC_2667)
228 				device_printf(dev, "CAP DDR3 2667 ");
229 			else if (dmfc == PCI_CORE_CAPID0_DMFC_2933)
230 				device_printf(dev, "CAP DDR3 2933 ");
231 			else
232 				dmfc_parsed = 0;
233 		}
234 	}
235 	if (!dmfc_parsed) {
236 		device_printf(dev, "unknown DMFC %#x\n", dmfc);
237 		return 0;
238 	}
239 
240 	if (capa & PCI_CORE_CAPID0_A_ECCDIS) {
241 		kprintf("NON-ECC\n");
242 	} else {
243 		kprintf("ECC\n");
244 		sc->sc_ecc = device_add_child(dev, "ecc", -1);
245 		if (sc->sc_ecc == NULL)
246 			device_printf(dev, "add ecc failed\n");
247 	}
248 
249 	mch_barlo = pci_read_config(dev, PCI_CORE_MCHBAR_LO, 4);
250 	mch_barhi = pci_read_config(dev, PCI_CORE_MCHBAR_HI, 4);
251 
252 	mch_bar = (uint64_t)mch_barlo | (((uint64_t)mch_barhi) << 32);
253 	if (bootverbose)
254 		device_printf(dev, "MCHBAR 0x%jx\n", (uintmax_t)mch_bar);
255 
256 	if (mch_bar & PCI_CORE_MCHBAR_LO_EN) {
257 		uint64_t map_addr = mch_bar & PCI_CORE_MCHBAR_ADDRMASK;
258 
259 		sc->sc_mch = pmap_mapdev_uncacheable(map_addr, MCH_CORE_SIZE);
260 
261 		if (bootverbose) {
262 			uint32_t dimm_ch0, dimm_ch1;
263 
264 			dimm_ch0 = CSR_READ_4(sc, MCH_CORE_DIMM_CH0);
265 			dimm_ch1 = CSR_READ_4(sc, MCH_CORE_DIMM_CH1);
266 
267 			coremctl_chaninfo(sc, dimm_ch0, "channel0");
268 			coremctl_chaninfo(sc, dimm_ch1, "channel1");
269 		}
270 	} else {
271 		device_printf(dev, "MCHBAR is not enabled\n");
272 	}
273 
274 	if (sc->sc_ver == COREMCTL_VER_3 && sc->sc_mch != NULL) {
275 		uint32_t ptm_ctl;
276 
277 		/*
278 		 * XXX
279 		 * It seems that memory thermal sensor is available,
280 		 * if any of the following bits are set.
281 		 */
282 		ptm_ctl = CSR_READ_4(sc, MCH_CORE_DDR_PTM_CTL0);
283 		if (ptm_ctl & (MCH_CORE_DDR_PTM_CTL0_CLTM |
284 		    MCH_CORE_DDR_PTM_CTL0_EXTTS | MCH_CORE_DDR_PTM_CTL0_OLTM)) {
285 			sc->sc_temp = device_add_child(dev, "memtemp", -1);
286 			if (sc->sc_temp == NULL)
287 				device_printf(dev, "add memtemp failed\n");
288 		}
289 	}
290 
291 	bus_generic_attach(dev);
292 
293 	return 0;
294 }
295 
296 static void
297 coremctl_chaninfo(struct coremctl_softc *sc, uint32_t dimm_ch,
298     const char *desc)
299 {
300 	int size_a, size_b;
301 	int dimma_id, dimmb_id;
302 
303 	dimma_id = 0;
304 	dimmb_id = 1;
305 	if (dimm_ch & MCH_CORE_DIMM_A_SELECT) {
306 		dimma_id = 1;
307 		dimmb_id = 0;
308 	}
309 
310 	size_a = __SHIFTOUT(dimm_ch, MCH_CORE_DIMM_A_SIZE);
311 	if (size_a != 0) {
312 		device_printf(sc->sc_dev, "%s, DIMM%d %dMB %dx%d\n", desc,
313 		    dimma_id, size_a * MCH_CORE_DIMM_SIZE_UNIT,
314 		    (dimm_ch & MCH_CORE_DIMM_A_DUAL_RANK) ? 2 : 1,
315 		    (dimm_ch & MCH_CORE_DIMM_A_X16) ? 16 : 8);
316 	}
317 
318 	size_b = __SHIFTOUT(dimm_ch, MCH_CORE_DIMM_B_SIZE);
319 	if (size_b != 0) {
320 		device_printf(sc->sc_dev, "%s, DIMM%d %dMB %dx%d\n", desc,
321 		    dimmb_id, size_b * MCH_CORE_DIMM_SIZE_UNIT,
322 		    (dimm_ch & MCH_CORE_DIMM_B_DUAL_RANK) ? 2 : 1,
323 		    (dimm_ch & MCH_CORE_DIMM_B_X16) ? 16 : 8);
324 	}
325 
326 	if (size_a == 0 && size_b == 0)
327 		return;
328 
329 	if (sc->sc_ver == COREMCTL_VER_1 || sc->sc_ver == COREMCTL_VER_2) {
330 		/* This bit is v3 only */
331 		dimm_ch &= ~MCH_CORE_DIMM_HORI;
332 	}
333 	if (dimm_ch & (MCH_CORE_DIMM_ENHI | MCH_CORE_DIMM_RI |
334 	    MCH_CORE_DIMM_HORI)) {
335 		device_printf(sc->sc_dev, "%s", desc);
336 		if (dimm_ch & MCH_CORE_DIMM_RI)
337 			kprintf(", rank interleave");
338 		if (dimm_ch & MCH_CORE_DIMM_ENHI)
339 			kprintf(", enhanced interleave");
340 		if (dimm_ch & MCH_CORE_DIMM_HORI)
341 			kprintf(", high order rank interleave");
342 		kprintf("\n");
343 	}
344 }
345 
346 static int
347 coremctl_detach(device_t dev)
348 {
349 	struct coremctl_softc *sc = device_get_softc(dev);
350 
351 	if (sc->sc_ecc != NULL)
352 		device_delete_child(dev, sc->sc_ecc);
353 	if (sc->sc_temp != NULL)
354 		device_delete_child(dev, sc->sc_temp);
355 	bus_generic_detach(dev);
356 
357 	if (sc->sc_mch != NULL)
358 		pmap_unmapdev((vm_offset_t)sc->sc_mch, MCH_CORE_SIZE);
359 	return 0;
360 }
361 
362 static int
363 coremctl_mch_readreg(device_t dev, int reg, uint32_t *val)
364 {
365 	struct coremctl_softc *sc = device_get_softc(dev);
366 
367 	if (sc->sc_mch == NULL)
368 		return EOPNOTSUPP;
369 
370 	*val = CSR_READ_4(sc, reg);
371 	return 0;
372 }
373 
374 static int
375 coremctl_mch_writereg(device_t dev, int reg, uint32_t val)
376 {
377 	struct coremctl_softc *sc = device_get_softc(dev);
378 
379 	if (sc->sc_mch == NULL)
380 		return EOPNOTSUPP;
381 
382 	CSR_WRITE_4(sc, reg, val);
383 	return 0;
384 }
385 
386 static int
387 coremctl_pci_read_ivar(device_t dev, device_t child, int which,
388     uintptr_t *result)
389 {
390 	return BUS_READ_IVAR(device_get_parent(dev), dev, which, result);
391 }
392 
393 static uint32_t
394 coremctl_pci_read_config(device_t dev, device_t child, int reg, int width)
395 {
396 	return pci_read_config(dev, reg, width);
397 }
398 
399 static void
400 coremctl_pci_write_config(device_t dev, device_t child, int reg, uint32_t val,
401     int width)
402 {
403 	pci_write_config(dev, reg, val, width);
404 }
405