1 /* $OpenBSD: pchb.c,v 1.39 2003/06/03 20:10:32 mickey Exp $ */ 2 /* $NetBSD: pchb.c,v 1.6 1997/06/06 23:29:16 thorpej 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 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 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the NetBSD 47 * Foundation, Inc. and its contributors. 48 * 4. Neither the name of The NetBSD Foundation nor the names of its 49 * contributors may be used to endorse or promote products derived 50 * from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 53 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 56 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62 * POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65 #include <sys/param.h> 66 #include <sys/systm.h> 67 #include <sys/device.h> 68 #include <sys/proc.h> 69 #include <sys/timeout.h> 70 71 #include <machine/bus.h> 72 73 #include <dev/pci/pcivar.h> 74 #include <dev/pci/pcireg.h> 75 #include <dev/pci/pcidevs.h> 76 77 #include <dev/rndvar.h> 78 79 #include <dev/ic/i82802reg.h> 80 81 #define PCISET_INTEL_BRIDGETYPE_MASK 0x3 82 #define PCISET_INTEL_TYPE_COMPAT 0x1 83 #define PCISET_INTEL_TYPE_AUX 0x2 84 85 #define PCISET_INTEL_BUSCONFIG_REG 0x48 86 #define PCISET_INTEL_BRIDGE_NUMBER(reg) (((reg) >> 8) & 0xff) 87 #define PCISET_INTEL_PCI_BUS_NUMBER(reg) (((reg) >> 16) & 0xff) 88 89 #define PCISET_INTEL_SDRAMC_REG 0x76 90 #define PCISET_INTEL_SDRAMC_IPDLT (1 << 8) 91 92 /* XXX should be in dev/ic/i82424{reg.var}.h */ 93 #define I82424_CPU_BCTL_REG 0x53 94 #define I82424_PCI_BCTL_REG 0x54 95 96 #define I82424_BCTL_CPUMEM_POSTEN 0x01 97 #define I82424_BCTL_CPUPCI_POSTEN 0x02 98 #define I82424_BCTL_PCIMEM_BURSTEN 0x01 99 #define I82424_BCTL_PCI_BURSTEN 0x02 100 101 struct pchb_softc { 102 struct device sc_dev; 103 104 bus_space_tag_t bt; 105 bus_space_handle_t bh; 106 107 /* rng stuff */ 108 int ax; 109 int i; 110 struct timeout sc_tmo; 111 }; 112 113 int pchbmatch(struct device *, void *, void *); 114 void pchbattach(struct device *, struct device *, void *); 115 116 int pchb_print(void *, const char *); 117 118 struct cfattach pchb_ca = { 119 sizeof(struct pchb_softc), pchbmatch, pchbattach 120 }; 121 122 struct cfdriver pchb_cd = { 123 NULL, "pchb", DV_DULL 124 }; 125 126 void pchb_rnd(void *v); 127 128 int 129 pchbmatch(parent, match, aux) 130 struct device *parent; 131 void *match, *aux; 132 { 133 struct pci_attach_args *pa = aux; 134 135 /* XXX work around broken via82x866 chipsets */ 136 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VIATECH && 137 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT82C686A_SMB) 138 return (0); 139 140 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 141 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST) 142 return (1); 143 144 return (0); 145 } 146 147 /* 148 * The variable below is a bit vector representing the Serverworks 149 * busses that have already been attached. Bit 0 represents bus 0 and 150 * so forth. The initial value is 1 because we never actually want to 151 * attach bus 0 since bus 0 is the mainbus. 152 */ 153 u_int32_t rcc_bus_visited = 1; 154 155 void 156 pchbattach(parent, self, aux) 157 struct device *parent, *self; 158 void *aux; 159 { 160 struct pchb_softc *sc = (struct pchb_softc *)self; 161 struct pci_attach_args *pa = aux; 162 struct pcibus_attach_args pba; 163 struct timeval tv1, tv2; 164 pcireg_t bcreg; 165 u_char bdnum, pbnum; 166 pcitag_t tag; 167 int neednl = 1; 168 int i, r; 169 170 /* 171 * Print out a description, and configure certain chipsets which 172 * have auxiliary PCI buses. 173 */ 174 175 switch (PCI_VENDOR(pa->pa_id)) { 176 #ifdef PCIAGP 177 case PCI_VENDOR_ALI: 178 case PCI_VENDOR_SIS: 179 case PCI_VENDOR_VIATECH: 180 pciagp_set_pchb(pa); 181 break; 182 case PCI_VENDOR_AMD: 183 switch (PCI_PRODUCT(pa->pa_id)) { 184 case PCI_PRODUCT_AMD_SC751_SC: 185 case PCI_PRODUCT_AMD_762_PCHB: 186 pciagp_set_pchb(pa); 187 break; 188 } 189 break; 190 #endif 191 case PCI_VENDOR_RCC: 192 bdnum = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x44); 193 if (bdnum >= (sizeof(rcc_bus_visited) * 8) || 194 (rcc_bus_visited & (1 << bdnum))) 195 break; 196 197 rcc_bus_visited |= 1 << bdnum; 198 199 /* 200 * This host bridge has a second PCI bus. 201 * Configure it. 202 */ 203 neednl = 0; 204 pba.pba_busname = "pci"; 205 pba.pba_iot = pa->pa_iot; 206 pba.pba_memt = pa->pa_memt; 207 pba.pba_dmat = pa->pa_dmat; 208 pba.pba_bus = bdnum; 209 pba.pba_pc = pa->pa_pc; 210 printf("\n"); 211 config_found(self, &pba, pchb_print); 212 break; 213 case PCI_VENDOR_INTEL: 214 #ifdef PCIAGP 215 pciagp_set_pchb(pa); 216 #endif 217 switch (PCI_PRODUCT(pa->pa_id)) { 218 case PCI_PRODUCT_INTEL_82443BX_AGP: /* 82443BX AGP (PAC) */ 219 case PCI_PRODUCT_INTEL_82443BX_NOAGP: /* 82443BX Host-PCI (no AGP) */ 220 /* 221 * An incorrect address may be driven on the 222 * DRAM bus, resulting in memory data being 223 * fetched from the wrong location. This is 224 * the workaround. 225 */ 226 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 227 PCISET_INTEL_SDRAMC_REG); 228 bcreg |= PCISET_INTEL_SDRAMC_IPDLT; 229 pci_conf_write(pa->pa_pc, pa->pa_tag, 230 PCISET_INTEL_SDRAMC_REG, bcreg); 231 break; 232 case PCI_PRODUCT_INTEL_PCI450_PB: 233 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 234 PCISET_INTEL_BUSCONFIG_REG); 235 bdnum = PCISET_INTEL_BRIDGE_NUMBER(bcreg); 236 pbnum = PCISET_INTEL_PCI_BUS_NUMBER(bcreg); 237 switch (bdnum & PCISET_INTEL_BRIDGETYPE_MASK) { 238 default: 239 printf(": bdnum=%x (reserved)", bdnum); 240 break; 241 case PCISET_INTEL_TYPE_COMPAT: 242 printf(": Compatibility PB (bus %d)", pbnum); 243 break; 244 case PCISET_INTEL_TYPE_AUX: 245 printf(": Auxiliary PB (bus %d)\n", pbnum); 246 neednl = 0; 247 248 /* 249 * This host bridge has a second PCI bus. 250 * Configure it. 251 */ 252 pba.pba_busname = "pci"; 253 pba.pba_iot = pa->pa_iot; 254 pba.pba_memt = pa->pa_memt; 255 pba.pba_dmat = pa->pa_dmat; 256 pba.pba_bus = pbnum; 257 pba.pba_pc = pa->pa_pc; 258 printf("\n"); 259 config_found(self, &pba, pchb_print); 260 break; 261 } 262 break; 263 case PCI_PRODUCT_INTEL_82454NX: 264 pbnum = 0; 265 switch (pa->pa_device) { 266 case 18: /* PXB 0 bus A - primary bus */ 267 break; 268 case 19: /* PXB 0 bus B */ 269 /* read SUBA0 from MIOC */ 270 tag = pci_make_tag(pa->pa_pc, 0, 16, 0); 271 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0); 272 pbnum = ((bcreg & 0x0000ff00) >> 8) + 1; 273 break; 274 case 20: /* PXB 1 bus A */ 275 /* read BUSNO1 from MIOC */ 276 tag = pci_make_tag(pa->pa_pc, 0, 16, 0); 277 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0); 278 pbnum = (bcreg & 0xff000000) >> 24; 279 break; 280 case 21: /* PXB 1 bus B */ 281 /* read SUBA1 from MIOC */ 282 tag = pci_make_tag(pa->pa_pc, 0, 16, 0); 283 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd4); 284 pbnum = (bcreg & 0x000000ff) + 1; 285 break; 286 } 287 if (pbnum != 0) { 288 pba.pba_busname = "pci"; 289 pba.pba_iot = pa->pa_iot; 290 pba.pba_memt = pa->pa_memt; 291 pba.pba_dmat = pa->pa_dmat; 292 pba.pba_bus = pbnum; 293 pba.pba_pc = pa->pa_pc; 294 printf("\n"); 295 config_found(self, &pba, pchb_print); 296 } 297 break; 298 case PCI_PRODUCT_INTEL_CDC: 299 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 300 I82424_CPU_BCTL_REG); 301 if (bcreg & I82424_BCTL_CPUPCI_POSTEN) { 302 bcreg &= ~I82424_BCTL_CPUPCI_POSTEN; 303 pci_conf_write(pa->pa_pc, pa->pa_tag, 304 I82424_CPU_BCTL_REG, bcreg); 305 printf(": disabled CPU-PCI write posting"); 306 } 307 break; 308 case PCI_PRODUCT_INTEL_82810_MCH: 309 case PCI_PRODUCT_INTEL_82810_DC100_MCH: 310 case PCI_PRODUCT_INTEL_82810E_MCH: 311 case PCI_PRODUCT_INTEL_82815_DC100_HUB: 312 case PCI_PRODUCT_INTEL_82815_NOGRAPH_HUB: 313 case PCI_PRODUCT_INTEL_82815_FULL_HUB: 314 case PCI_PRODUCT_INTEL_82815_NOAGP_HUB: 315 case PCI_PRODUCT_INTEL_82820_MCH: 316 case PCI_PRODUCT_INTEL_82840_HB: 317 case PCI_PRODUCT_INTEL_82850_HB: 318 case PCI_PRODUCT_INTEL_82860_HB: 319 sc->bt = pa->pa_memt; 320 if (bus_space_map(sc->bt, I82802_IOBASE, I82802_IOSIZE, 321 0, &sc->bh)) 322 break; 323 324 /* probe and init rng */ 325 if (!(bus_space_read_1(sc->bt, sc->bh, 326 I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT)) 327 break; 328 329 /* enable RNG */ 330 bus_space_write_1(sc->bt, sc->bh, I82802_RNG_HWST, 331 bus_space_read_1(sc->bt, sc->bh, I82802_RNG_HWST) | 332 I82802_RNG_HWST_ENABLE); 333 334 /* see if we can read anything */ 335 for (i = 1000; i-- && 336 !(bus_space_read_1(sc->bt,sc->bh,I82802_RNG_RNGST)& 337 I82802_RNG_RNGST_DATAV); 338 DELAY(10)); 339 340 if (!(bus_space_read_1(sc->bt, sc->bh, 341 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV)) 342 break; 343 344 r = bus_space_read_1(sc->bt, sc->bh, I82802_RNG_DATA); 345 346 /* benchmark the RNG */ 347 microtime(&tv1); 348 for (i = 8 * 1024; i--; ) { 349 while(!(bus_space_read_1(sc->bt, sc->bh, 350 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV)) 351 ; 352 r = bus_space_read_1(sc->bt, sc->bh, 353 I82802_RNG_DATA); 354 } 355 microtime(&tv2); 356 357 timersub(&tv2, &tv1, &tv1); 358 if (tv1.tv_sec) 359 tv1.tv_usec += 1000000 * tv1.tv_sec; 360 printf(": rng active, %dKb/sec", 361 8 * 1000000 / tv1.tv_usec); 362 363 timeout_set(&sc->sc_tmo, pchb_rnd, sc); 364 sc->i = 4; 365 pchb_rnd(sc); 366 break; 367 default: 368 break; 369 } 370 } 371 if (neednl) 372 printf("\n"); 373 } 374 375 int 376 pchb_print(aux, pnp) 377 void *aux; 378 const char *pnp; 379 { 380 struct pcibus_attach_args *pba = aux; 381 382 if (pnp) 383 printf("%s at %s", pba->pba_busname, pnp); 384 printf(" bus %d", pba->pba_bus); 385 return (UNCONF); 386 } 387 388 /* 389 * Should do FIPS testing as per: 390 * http://csrc.nist.gov/fips/fips1401.htm 391 */ 392 void 393 pchb_rnd(v) 394 void *v; 395 { 396 struct pchb_softc *sc = v; 397 398 /* 399 * Don't wait for data to be ready. If it's not there, we'll check 400 * next time. 401 */ 402 if ((bus_space_read_1(sc->bt, sc->bh, I82802_RNG_RNGST) & 403 I82802_RNG_RNGST_DATAV)) { 404 405 sc->ax = (sc->ax << 8) | 406 bus_space_read_1(sc->bt, sc->bh, I82802_RNG_DATA); 407 408 if (!sc->i--) { 409 sc->i = 4; 410 add_true_randomness(sc->ax); 411 } 412 } 413 414 timeout_add(&sc->sc_tmo, 1); 415 } 416