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