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