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