1 /* $OpenBSD: pchb.c,v 1.43 2018/04/28 15:44:59 jasper Exp $ */ 2 /* $NetBSD: pchb.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ 3 /* 4 * Copyright (c) 2000 Michael Shalayeff 5 * All rights reserved. 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 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /*- 29 * Copyright (c) 1996, 1998, 2000 The NetBSD Foundation, Inc. 30 * All rights reserved. 31 * 32 * This code is derived from software contributed to The NetBSD Foundation 33 * by Jason R. Thorpe. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 45 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 47 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 54 * POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57 #include <sys/param.h> 58 #include <sys/systm.h> 59 #include <sys/device.h> 60 #include <sys/timeout.h> 61 62 #include <machine/bus.h> 63 64 #include <dev/pci/pcivar.h> 65 #include <dev/pci/pcireg.h> 66 #include <dev/pci/pcidevs.h> 67 68 #include <dev/pci/agpvar.h> 69 #include <dev/pci/ppbreg.h> 70 71 #include <dev/rndvar.h> 72 73 #include <dev/ic/i82802reg.h> 74 75 #include "agp.h" 76 77 /* XXX should be in dev/ic/i82424{reg.var}.h */ 78 #define I82424_CPU_BCTL_REG 0x53 79 #define I82424_PCI_BCTL_REG 0x54 80 81 #define I82424_BCTL_CPUMEM_POSTEN 0x01 82 #define I82424_BCTL_CPUPCI_POSTEN 0x02 83 #define I82424_BCTL_PCIMEM_BURSTEN 0x01 84 #define I82424_BCTL_PCI_BURSTEN 0x02 85 86 /* XXX should be in dev/ic/amd64htreg.h */ 87 #define AMD64HT_LDT0_BUS 0x94 88 #define AMD64HT_LDT0_TYPE 0x98 89 #define AMD64HT_LDT1_BUS 0xb4 90 #define AMD64HT_LDT1_TYPE 0xb8 91 #define AMD64HT_LDT2_BUS 0xd4 92 #define AMD64HT_LDT2_TYPE 0xd8 93 #define AMD64HT_LDT3_BUS 0xf4 94 #define AMD64HT_LDT3_TYPE 0xf8 95 96 #define AMD64HT_NUM_LDT 4 97 98 #define AMD64HT_LDT_TYPE_MASK 0x0000001f 99 #define AMD64HT_LDT_INIT_COMPLETE 0x00000002 100 #define AMD64HT_LDT_NC 0x00000004 101 102 #define AMD64HT_LDT_SEC_BUS_NUM(reg) (((reg) >> 8) & 0xff) 103 104 struct pchb_softc { 105 struct device sc_dev; 106 107 bus_space_tag_t sc_bt; 108 bus_space_handle_t sc_bh; 109 110 /* rng stuff */ 111 int sc_rng_active; 112 int sc_rng_ax; 113 int sc_rng_i; 114 struct timeout sc_rng_to; 115 }; 116 117 int pchbmatch(struct device *, void *, void *); 118 void pchbattach(struct device *, struct device *, void *); 119 int pchbactivate(struct device *, int); 120 121 struct cfattach pchb_ca = { 122 sizeof(struct pchb_softc), pchbmatch, pchbattach, NULL, 123 pchbactivate 124 }; 125 126 struct cfdriver pchb_cd = { 127 NULL, "pchb", DV_DULL 128 }; 129 130 int pchb_print(void *, const char *); 131 void pchb_rnd(void *); 132 void pchb_amd64ht_attach(struct device *, struct pci_attach_args *, int); 133 134 int 135 pchbmatch(struct device *parent, void *match, void *aux) 136 { 137 struct pci_attach_args *pa = aux; 138 139 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 140 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST) 141 return (1); 142 143 return (0); 144 } 145 146 void 147 pchbattach(struct device *parent, struct device *self, void *aux) 148 { 149 struct pchb_softc *sc = (struct pchb_softc *)self; 150 struct pci_attach_args *pa = aux; 151 struct pcibus_attach_args pba; 152 pcireg_t bcreg, bir; 153 u_char pbnum; 154 pcitag_t tag; 155 int i, r; 156 int doattach = 0; 157 158 switch (PCI_VENDOR(pa->pa_id)) { 159 case PCI_VENDOR_AMD: 160 printf("\n"); 161 switch (PCI_PRODUCT(pa->pa_id)) { 162 case PCI_PRODUCT_AMD_AMD64_0F_HT: 163 case PCI_PRODUCT_AMD_AMD64_10_HT: 164 for (i = 0; i < AMD64HT_NUM_LDT; i++) 165 pchb_amd64ht_attach(self, pa, i); 166 break; 167 } 168 break; 169 case PCI_VENDOR_INTEL: 170 switch (PCI_PRODUCT(pa->pa_id)) { 171 case PCI_PRODUCT_INTEL_82915G_HB: 172 case PCI_PRODUCT_INTEL_82945G_HB: 173 case PCI_PRODUCT_INTEL_82925X_HB: 174 case PCI_PRODUCT_INTEL_82955X_HB: 175 sc->sc_bt = pa->pa_memt; 176 if (bus_space_map(sc->sc_bt, I82802_IOBASE, 177 I82802_IOSIZE, 0, &sc->sc_bh)) 178 break; 179 180 /* probe and init rng */ 181 if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh, 182 I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT)) 183 break; 184 185 /* enable RNG */ 186 bus_space_write_1(sc->sc_bt, sc->sc_bh, 187 I82802_RNG_HWST, 188 bus_space_read_1(sc->sc_bt, sc->sc_bh, 189 I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE); 190 191 /* see if we can read anything */ 192 for (i = 1000; i-- && 193 !(bus_space_read_1(sc->sc_bt, sc->sc_bh, 194 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV); ) 195 DELAY(10); 196 197 if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh, 198 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV)) 199 break; 200 201 r = bus_space_read_1(sc->sc_bt, sc->sc_bh, 202 I82802_RNG_DATA); 203 204 timeout_set(&sc->sc_rng_to, pchb_rnd, sc); 205 sc->sc_rng_i = 4; 206 pchb_rnd(sc); 207 sc->sc_rng_active = 1; 208 break; 209 } 210 printf("\n"); 211 break; 212 case PCI_VENDOR_VIATECH: 213 switch (PCI_PRODUCT(pa->pa_id)) { 214 case PCI_PRODUCT_VIATECH_VT8251_PCIE_0: 215 /* 216 * Bump the host bridge into PCI-PCI bridge 217 * mode by clearing magic bit on the VLINK 218 * device. This allows us to read the bus 219 * number for the PCI bus attached to this 220 * host bridge. 221 */ 222 tag = pci_make_tag(pa->pa_pc, 0, 17, 7); 223 bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc); 224 bcreg &= ~0x00000004; /* XXX Magic */ 225 pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); 226 227 bir = pci_conf_read(pa->pa_pc, 228 pa->pa_tag, PPB_REG_BUSINFO); 229 pbnum = PPB_BUSINFO_PRIMARY(bir); 230 if (pbnum > 0) 231 doattach = 1; 232 233 /* Switch back to host bridge mode. */ 234 bcreg |= 0x00000004; /* XXX Magic */ 235 pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); 236 break; 237 } 238 printf("\n"); 239 break; 240 default: 241 printf("\n"); 242 break; 243 } 244 245 #if NAGP > 0 246 /* 247 * Intel IGD have an odd interface and attach at vga, however, 248 * in that mode they don't have the AGP cap bit, so this 249 * test should be sufficient 250 */ 251 if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, 252 NULL, NULL) != 0) { 253 struct agp_attach_args aa; 254 aa.aa_busname = "agp"; 255 aa.aa_pa = pa; 256 257 config_found(self, &aa, agpdev_print); 258 } 259 #endif /* NAGP > 0 */ 260 261 if (doattach == 0) 262 return; 263 264 bzero(&pba, sizeof(pba)); 265 pba.pba_busname = "pci"; 266 pba.pba_iot = pa->pa_iot; 267 pba.pba_memt = pa->pa_memt; 268 pba.pba_dmat = pa->pa_dmat; 269 pba.pba_busex = pa->pa_busex; 270 pba.pba_domain = pa->pa_domain; 271 pba.pba_bus = pbnum; 272 pba.pba_pc = pa->pa_pc; 273 config_found(self, &pba, pchb_print); 274 } 275 276 int 277 pchbactivate(struct device *self, int act) 278 { 279 struct pchb_softc *sc = (struct pchb_softc *)self; 280 int rv = 0; 281 282 switch (act) { 283 case DVACT_RESUME: 284 /* re-enable RNG, if we have it */ 285 if (sc->sc_rng_active) 286 bus_space_write_1(sc->sc_bt, sc->sc_bh, 287 I82802_RNG_HWST, 288 bus_space_read_1(sc->sc_bt, sc->sc_bh, 289 I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE); 290 rv = config_activate_children(self, act); 291 break; 292 default: 293 rv = config_activate_children(self, act); 294 break; 295 } 296 return (rv); 297 } 298 299 int 300 pchb_print(void *aux, const char *pnp) 301 { 302 struct pcibus_attach_args *pba = aux; 303 304 if (pnp) 305 printf("%s at %s", pba->pba_busname, pnp); 306 printf(" bus %d", pba->pba_bus); 307 return (UNCONF); 308 } 309 310 /* 311 * Should do FIPS testing as per: 312 * http://csrc.nist.gov/publications/fips/fips140-1/fips1401.pdf 313 */ 314 void 315 pchb_rnd(void *v) 316 { 317 struct pchb_softc *sc = v; 318 319 /* 320 * Don't wait for data to be ready. If it's not there, we'll check 321 * next time. 322 */ 323 if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_RNGST) & 324 I82802_RNG_RNGST_DATAV)) { 325 326 sc->sc_rng_ax = (sc->sc_rng_ax << 8) | 327 bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_DATA); 328 329 if (!sc->sc_rng_i--) { 330 sc->sc_rng_i = 4; 331 enqueue_randomness(sc->sc_rng_ax); 332 } 333 } 334 335 timeout_add(&sc->sc_rng_to, 1); 336 } 337 338 void 339 pchb_amd64ht_attach(struct device *self, struct pci_attach_args *pa, int i) 340 { 341 struct pcibus_attach_args pba; 342 pcireg_t type, bus; 343 int reg; 344 345 reg = AMD64HT_LDT0_TYPE + i * 0x20; 346 type = pci_conf_read(pa->pa_pc, pa->pa_tag, reg); 347 if ((type & AMD64HT_LDT_INIT_COMPLETE) == 0 || 348 (type & AMD64HT_LDT_NC) == 0) 349 return; 350 351 reg = AMD64HT_LDT0_BUS + i * 0x20; 352 bus = pci_conf_read(pa->pa_pc, pa->pa_tag, reg); 353 if (AMD64HT_LDT_SEC_BUS_NUM(bus) > 0) { 354 bzero(&pba, sizeof(pba)); 355 pba.pba_busname = "pci"; 356 pba.pba_iot = pa->pa_iot; 357 pba.pba_memt = pa->pa_memt; 358 pba.pba_dmat = pa->pa_dmat; 359 pba.pba_busex = pa->pa_busex; 360 pba.pba_domain = pa->pa_domain; 361 pba.pba_bus = AMD64HT_LDT_SEC_BUS_NUM(bus); 362 pba.pba_pc = pa->pa_pc; 363 config_found(self, &pba, pchb_print); 364 } 365 } 366