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