1 /* $OpenBSD: pchb.c,v 1.92 2020/05/29 04:42:24 deraadt Exp $ */ 2 /* $NetBSD: pchb.c,v 1.65 2007/08/15 02:26:13 markd Exp $ */ 3 4 /* 5 * Copyright (c) 2000 Michael Shalayeff 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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 the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 /*- 30 * Copyright (c) 1996, 1998, 2000 The NetBSD Foundation, Inc. 31 * All rights reserved. 32 * 33 * This code is derived from software contributed to The NetBSD Foundation 34 * by Jason R. Thorpe. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 46 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 49 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 52 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 53 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 55 * POSSIBILITY OF SUCH DAMAGE. 56 */ 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/device.h> 61 #include <sys/timeout.h> 62 #include <sys/rwlock.h> 63 64 #include <machine/bus.h> 65 66 #include <dev/pci/pcivar.h> 67 #include <dev/pci/pcireg.h> 68 #include <dev/pci/pcidevs.h> 69 70 #include <dev/pci/agpvar.h> 71 #include <dev/pci/ppbreg.h> 72 73 #include <dev/ic/i82802reg.h> 74 75 #include "agp.h" 76 77 #define PCISET_INTEL_BRIDGETYPE_MASK 0x3 78 #define PCISET_INTEL_TYPE_COMPAT 0x1 79 #define PCISET_INTEL_TYPE_AUX 0x2 80 81 #define PCISET_INTEL_BUSCONFIG_REG 0x48 82 #define PCISET_INTEL_BRIDGE_NUMBER(reg) (((reg) >> 8) & 0xff) 83 #define PCISET_INTEL_PCI_BUS_NUMBER(reg) (((reg) >> 16) & 0xff) 84 85 #define PCISET_INTEL_SDRAMC_REG 0x74 86 #define PCISET_INTEL_SDRAMC_IPDLT (1 << 24) 87 88 /* XXX should be in dev/ic/i82424{reg.var}.h */ 89 #define I82424_CPU_BCTL_REG 0x53 90 #define I82424_PCI_BCTL_REG 0x54 91 92 #define I82424_BCTL_CPUMEM_POSTEN 0x01 93 #define I82424_BCTL_CPUPCI_POSTEN 0x02 94 #define I82424_BCTL_PCIMEM_BURSTEN 0x01 95 #define I82424_BCTL_PCI_BURSTEN 0x02 96 97 /* XXX should be in dev/ic/amd64htreg.h */ 98 #define AMD64HT_LDT0_BUS 0x94 99 #define AMD64HT_LDT0_TYPE 0x98 100 #define AMD64HT_LDT1_BUS 0xb4 101 #define AMD64HT_LDT1_TYPE 0xb8 102 #define AMD64HT_LDT2_BUS 0xd4 103 #define AMD64HT_LDT2_TYPE 0xd8 104 #define AMD64HT_LDT3_BUS 0xf4 105 #define AMD64HT_LDT3_TYPE 0xf8 106 107 #define AMD64HT_NUM_LDT 4 108 109 #define AMD64HT_LDT_TYPE_MASK 0x0000001f 110 #define AMD64HT_LDT_INIT_COMPLETE 0x00000002 111 #define AMD64HT_LDT_NC 0x00000004 112 113 #define AMD64HT_LDT_SEC_BUS_NUM(reg) (((reg) >> 8) & 0xff) 114 115 struct pchb_softc { 116 struct device sc_dev; 117 118 bus_space_tag_t sc_bt; 119 bus_space_handle_t sc_bh; 120 121 /* rng stuff */ 122 int sc_rng_active; 123 int sc_rng_ax; 124 int sc_rng_i; 125 struct timeout sc_rng_to; 126 }; 127 128 int pchbmatch(struct device *, void *, void *); 129 void pchbattach(struct device *, struct device *, void *); 130 int pchbactivate(struct device *, int); 131 132 struct cfattach pchb_ca = { 133 sizeof(struct pchb_softc), pchbmatch, pchbattach, NULL, 134 pchbactivate 135 }; 136 137 struct cfdriver pchb_cd = { 138 NULL, "pchb", DV_DULL 139 }; 140 141 int pchb_print(void *, const char *); 142 void pchb_rnd(void *); 143 void pchb_amd64ht_attach(struct device *, struct pci_attach_args *, int); 144 145 int 146 pchbmatch(struct device *parent, void *match, void *aux) 147 { 148 struct pci_attach_args *pa = aux; 149 150 #ifdef __i386__ 151 /* XXX work around broken via82x866 chipsets */ 152 const struct pci_matchid via_devices[] = { 153 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_PWR }, 154 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596 }, 155 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596B_PM }, 156 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_SMB } 157 }; 158 if (pci_matchbyid(pa, via_devices, 159 sizeof(via_devices) / sizeof(via_devices[0]))) 160 return (0); 161 #endif /* __i386__ */ 162 163 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 164 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST) 165 return (1); 166 167 return (0); 168 } 169 170 void 171 pchbattach(struct device *parent, struct device *self, void *aux) 172 { 173 struct pchb_softc *sc = (struct pchb_softc *)self; 174 struct pci_attach_args *pa = aux; 175 struct pcibus_attach_args pba; 176 pcireg_t bcreg, bir; 177 u_char bdnum, pbnum; 178 pcitag_t tag; 179 int i, r; 180 int doattach = 0; 181 182 switch (PCI_VENDOR(pa->pa_id)) { 183 case PCI_VENDOR_AMD: 184 printf("\n"); 185 switch (PCI_PRODUCT(pa->pa_id)) { 186 case PCI_PRODUCT_AMD_0F_HT: 187 case PCI_PRODUCT_AMD_10_HT: 188 for (i = 0; i < AMD64HT_NUM_LDT; i++) 189 pchb_amd64ht_attach(self, pa, i); 190 break; 191 } 192 break; 193 #ifdef __i386__ 194 case PCI_VENDOR_RCC: 195 { 196 /* 197 * The variable below is a bit vector representing the 198 * Serverworks busses that have already been attached. 199 * Bit 0 represents bus 0 and so forth. The initial 200 * value is 1 because we never actually want to 201 * attach bus 0 since bus 0 is the mainbus. 202 */ 203 static u_int32_t rcc_bus_visited = 1; 204 205 printf("\n"); 206 bdnum = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x44); 207 if (bdnum >= (sizeof(rcc_bus_visited) * 8) || 208 (rcc_bus_visited & (1 << bdnum))) 209 break; 210 211 rcc_bus_visited |= 1 << bdnum; 212 213 /* 214 * This host bridge has a second PCI bus. 215 * Configure it. 216 */ 217 pbnum = bdnum; 218 doattach = 1; 219 break; 220 } 221 #endif 222 case PCI_VENDOR_INTEL: 223 switch (PCI_PRODUCT(pa->pa_id)) { 224 #ifdef __i386__ 225 case PCI_PRODUCT_INTEL_82452_HB: 226 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x40); 227 pbnum = PCISET_INTEL_BRIDGE_NUMBER(bcreg); 228 if (pbnum != 0xff) { 229 pbnum++; 230 doattach = 1; 231 } 232 break; 233 case PCI_PRODUCT_INTEL_82443BX_AGP: /* 82443BX AGP (PAC) */ 234 case PCI_PRODUCT_INTEL_82443BX_NOAGP: /* 82443BX Host-PCI (no AGP) */ 235 /* 236 * An incorrect address may be driven on the 237 * DRAM bus, resulting in memory data being 238 * fetched from the wrong location. This is 239 * the workaround. 240 */ 241 if (PCI_REVISION(pa->pa_class) < 0x3) { 242 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 243 PCISET_INTEL_SDRAMC_REG); 244 bcreg |= PCISET_INTEL_SDRAMC_IPDLT; 245 pci_conf_write(pa->pa_pc, pa->pa_tag, 246 PCISET_INTEL_SDRAMC_REG, bcreg); 247 } 248 break; 249 case PCI_PRODUCT_INTEL_PCI450_PB: 250 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 251 PCISET_INTEL_BUSCONFIG_REG); 252 bdnum = PCISET_INTEL_BRIDGE_NUMBER(bcreg); 253 pbnum = PCISET_INTEL_PCI_BUS_NUMBER(bcreg); 254 switch (bdnum & PCISET_INTEL_BRIDGETYPE_MASK) { 255 default: 256 printf(": bdnum=%x (reserved)", bdnum); 257 break; 258 case PCISET_INTEL_TYPE_COMPAT: 259 printf(": Compatibility PB (bus %d)", pbnum); 260 break; 261 case PCISET_INTEL_TYPE_AUX: 262 printf(": Auxiliary PB (bus %d)", pbnum); 263 doattach = 1; 264 } 265 break; 266 case PCI_PRODUCT_INTEL_CDC: 267 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 268 I82424_CPU_BCTL_REG); 269 if (bcreg & I82424_BCTL_CPUPCI_POSTEN) { 270 bcreg &= ~I82424_BCTL_CPUPCI_POSTEN; 271 pci_conf_write(pa->pa_pc, pa->pa_tag, 272 I82424_CPU_BCTL_REG, bcreg); 273 printf(": disabled CPU-PCI write posting"); 274 } 275 break; 276 case PCI_PRODUCT_INTEL_82454NX: 277 pbnum = 0; 278 switch (pa->pa_device) { 279 case 18: /* PXB 0 bus A - primary bus */ 280 break; 281 case 19: /* PXB 0 bus B */ 282 /* read SUBA0 from MIOC */ 283 tag = pci_make_tag(pa->pa_pc, 0, 16, 0); 284 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0); 285 pbnum = ((bcreg & 0x0000ff00) >> 8) + 1; 286 break; 287 case 20: /* PXB 1 bus A */ 288 /* read BUSNO1 from MIOC */ 289 tag = pci_make_tag(pa->pa_pc, 0, 16, 0); 290 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0); 291 pbnum = (bcreg & 0xff000000) >> 24; 292 break; 293 case 21: /* PXB 1 bus B */ 294 /* read SUBA1 from MIOC */ 295 tag = pci_make_tag(pa->pa_pc, 0, 16, 0); 296 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd4); 297 pbnum = (bcreg & 0x000000ff) + 1; 298 break; 299 } 300 if (pbnum != 0) 301 doattach = 1; 302 break; 303 /* RNG */ 304 case PCI_PRODUCT_INTEL_82810_HB: 305 case PCI_PRODUCT_INTEL_82810_DC100_HB: 306 case PCI_PRODUCT_INTEL_82810E_HB: 307 case PCI_PRODUCT_INTEL_82815_HB: 308 case PCI_PRODUCT_INTEL_82820_HB: 309 case PCI_PRODUCT_INTEL_82840_HB: 310 case PCI_PRODUCT_INTEL_82850_HB: 311 case PCI_PRODUCT_INTEL_82860_HB: 312 #endif /* __i386__ */ 313 case PCI_PRODUCT_INTEL_82915G_HB: 314 case PCI_PRODUCT_INTEL_82945G_HB: 315 case PCI_PRODUCT_INTEL_82925X_HB: 316 case PCI_PRODUCT_INTEL_82955X_HB: 317 sc->sc_bt = pa->pa_memt; 318 if (bus_space_map(sc->sc_bt, I82802_IOBASE, 319 I82802_IOSIZE, 0, &sc->sc_bh)) 320 break; 321 322 /* probe and init rng */ 323 if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh, 324 I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT)) 325 break; 326 327 /* enable RNG */ 328 bus_space_write_1(sc->sc_bt, sc->sc_bh, 329 I82802_RNG_HWST, 330 bus_space_read_1(sc->sc_bt, sc->sc_bh, 331 I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE); 332 333 /* see if we can read anything */ 334 for (i = 1000; i-- && 335 !(bus_space_read_1(sc->sc_bt, sc->sc_bh, 336 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV); ) 337 DELAY(10); 338 339 if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh, 340 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV)) 341 break; 342 343 r = bus_space_read_1(sc->sc_bt, sc->sc_bh, 344 I82802_RNG_DATA); 345 346 timeout_set(&sc->sc_rng_to, pchb_rnd, sc); 347 sc->sc_rng_i = 4; 348 pchb_rnd(sc); 349 sc->sc_rng_active = 1; 350 break; 351 } 352 printf("\n"); 353 break; 354 case PCI_VENDOR_VIATECH: 355 switch (PCI_PRODUCT(pa->pa_id)) { 356 case PCI_PRODUCT_VIATECH_VT8251_PCIE_0: 357 /* 358 * Bump the host bridge into PCI-PCI bridge 359 * mode by clearing magic bit on the VLINK 360 * device. This allows us to read the bus 361 * number for the PCI bus attached to this 362 * host bridge. 363 */ 364 tag = pci_make_tag(pa->pa_pc, 0, 17, 7); 365 bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc); 366 bcreg &= ~0x00000004; /* XXX Magic */ 367 pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); 368 369 bir = pci_conf_read(pa->pa_pc, 370 pa->pa_tag, PPB_REG_BUSINFO); 371 pbnum = PPB_BUSINFO_PRIMARY(bir); 372 if (pbnum > 0) 373 doattach = 1; 374 375 /* Switch back to host bridge mode. */ 376 bcreg |= 0x00000004; /* XXX Magic */ 377 pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); 378 break; 379 } 380 printf("\n"); 381 break; 382 default: 383 printf("\n"); 384 break; 385 } 386 387 #if NAGP > 0 388 /* 389 * Intel IGD have an odd interface and attach at vga, however, 390 * in that mode they don't have the AGP cap bit, so this 391 * test should be sufficient 392 */ 393 if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, 394 NULL, NULL) != 0) { 395 struct agp_attach_args aa; 396 aa.aa_busname = "agp"; 397 aa.aa_pa = pa; 398 399 config_found(self, &aa, agpdev_print); 400 } 401 #endif /* NAGP > 0 */ 402 403 if (doattach == 0) 404 return; 405 406 bzero(&pba, sizeof(pba)); 407 pba.pba_busname = "pci"; 408 pba.pba_iot = pa->pa_iot; 409 pba.pba_memt = pa->pa_memt; 410 pba.pba_dmat = pa->pa_dmat; 411 pba.pba_busex = pa->pa_busex; 412 pba.pba_domain = pa->pa_domain; 413 pba.pba_bus = pbnum; 414 pba.pba_pc = pa->pa_pc; 415 config_found(self, &pba, pchb_print); 416 } 417 418 int 419 pchbactivate(struct device *self, int act) 420 { 421 struct pchb_softc *sc = (struct pchb_softc *)self; 422 int rv = 0; 423 424 switch (act) { 425 case DVACT_RESUME: 426 /* re-enable RNG, if we have it */ 427 if (sc->sc_rng_active) 428 bus_space_write_1(sc->sc_bt, sc->sc_bh, 429 I82802_RNG_HWST, 430 bus_space_read_1(sc->sc_bt, sc->sc_bh, 431 I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE); 432 rv = config_activate_children(self, act); 433 break; 434 default: 435 rv = config_activate_children(self, act); 436 break; 437 } 438 return (rv); 439 } 440 441 442 int 443 pchb_print(void *aux, const char *pnp) 444 { 445 struct pcibus_attach_args *pba = aux; 446 447 if (pnp) 448 printf("%s at %s", pba->pba_busname, pnp); 449 printf(" bus %d", pba->pba_bus); 450 return (UNCONF); 451 } 452 453 /* 454 * Should do FIPS testing as per: 455 * http://csrc.nist.gov/publications/fips/fips140-1/fips1401.pdf 456 */ 457 void 458 pchb_rnd(void *v) 459 { 460 struct pchb_softc *sc = v; 461 462 /* 463 * Don't wait for data to be ready. If it's not there, we'll check 464 * next time. 465 */ 466 if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_RNGST) & 467 I82802_RNG_RNGST_DATAV)) { 468 469 sc->sc_rng_ax = (sc->sc_rng_ax << 8) | 470 bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_DATA); 471 472 if (!sc->sc_rng_i--) { 473 sc->sc_rng_i = 4; 474 enqueue_randomness(sc->sc_rng_ax); 475 } 476 } 477 478 timeout_add(&sc->sc_rng_to, 1); 479 } 480 481 void 482 pchb_amd64ht_attach(struct device *self, struct pci_attach_args *pa, int i) 483 { 484 struct pcibus_attach_args pba; 485 pcireg_t type, bus; 486 int reg; 487 488 reg = AMD64HT_LDT0_TYPE + i * 0x20; 489 type = pci_conf_read(pa->pa_pc, pa->pa_tag, reg); 490 if ((type & AMD64HT_LDT_INIT_COMPLETE) == 0 || 491 (type & AMD64HT_LDT_NC) == 0) 492 return; 493 494 reg = AMD64HT_LDT0_BUS + i * 0x20; 495 bus = pci_conf_read(pa->pa_pc, pa->pa_tag, reg); 496 if (AMD64HT_LDT_SEC_BUS_NUM(bus) > 0) { 497 bzero(&pba, sizeof(pba)); 498 pba.pba_busname = "pci"; 499 pba.pba_iot = pa->pa_iot; 500 pba.pba_memt = pa->pa_memt; 501 pba.pba_dmat = pa->pa_dmat; 502 pba.pba_busex = pa->pa_busex; 503 pba.pba_domain = pa->pa_domain; 504 pba.pba_bus = AMD64HT_LDT_SEC_BUS_NUM(bus); 505 pba.pba_pc = pa->pa_pc; 506 config_found(self, &pba, pchb_print); 507 } 508 } 509