1 /* $OpenBSD: pchb.c,v 1.46 2022/02/21 11:03:39 mpi 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/ic/i82802reg.h> 72 73 #include "agp.h" 74 75 /* XXX should be in dev/ic/i82424{reg.var}.h */ 76 #define I82424_CPU_BCTL_REG 0x53 77 #define I82424_PCI_BCTL_REG 0x54 78 79 #define I82424_BCTL_CPUMEM_POSTEN 0x01 80 #define I82424_BCTL_CPUPCI_POSTEN 0x02 81 #define I82424_BCTL_PCIMEM_BURSTEN 0x01 82 #define I82424_BCTL_PCI_BURSTEN 0x02 83 84 /* XXX should be in dev/ic/amd64htreg.h */ 85 #define AMD64HT_LDT0_BUS 0x94 86 #define AMD64HT_LDT0_TYPE 0x98 87 #define AMD64HT_LDT1_BUS 0xb4 88 #define AMD64HT_LDT1_TYPE 0xb8 89 #define AMD64HT_LDT2_BUS 0xd4 90 #define AMD64HT_LDT2_TYPE 0xd8 91 #define AMD64HT_LDT3_BUS 0xf4 92 #define AMD64HT_LDT3_TYPE 0xf8 93 94 #define AMD64HT_NUM_LDT 4 95 96 #define AMD64HT_LDT_TYPE_MASK 0x0000001f 97 #define AMD64HT_LDT_INIT_COMPLETE 0x00000002 98 #define AMD64HT_LDT_NC 0x00000004 99 100 #define AMD64HT_LDT_SEC_BUS_NUM(reg) (((reg) >> 8) & 0xff) 101 102 struct pchb_softc { 103 struct device sc_dev; 104 105 bus_space_tag_t sc_bt; 106 bus_space_handle_t sc_bh; 107 108 /* rng stuff */ 109 int sc_rng_active; 110 int sc_rng_ax; 111 int sc_rng_i; 112 struct timeout sc_rng_to; 113 }; 114 115 int pchbmatch(struct device *, void *, void *); 116 void pchbattach(struct device *, struct device *, void *); 117 int pchbactivate(struct device *, int); 118 119 const struct cfattach pchb_ca = { 120 sizeof(struct pchb_softc), pchbmatch, pchbattach, NULL, 121 pchbactivate 122 }; 123 124 struct cfdriver pchb_cd = { 125 NULL, "pchb", DV_DULL 126 }; 127 128 int pchb_print(void *, const char *); 129 void pchb_rnd(void *); 130 void pchb_amd64ht_attach(struct device *, struct pci_attach_args *, int); 131 132 int 133 pchbmatch(struct device *parent, void *match, void *aux) 134 { 135 struct pci_attach_args *pa = aux; 136 137 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 138 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST) 139 return (1); 140 141 return (0); 142 } 143 144 void 145 pchbattach(struct device *parent, struct device *self, void *aux) 146 { 147 struct pchb_softc *sc = (struct pchb_softc *)self; 148 struct pci_attach_args *pa = aux; 149 struct pcibus_attach_args pba; 150 pcireg_t bcreg, bir; 151 u_char pbnum; 152 pcitag_t tag; 153 int i, r; 154 int doattach = 0; 155 156 switch (PCI_VENDOR(pa->pa_id)) { 157 case PCI_VENDOR_AMD: 158 printf("\n"); 159 switch (PCI_PRODUCT(pa->pa_id)) { 160 case PCI_PRODUCT_AMD_0F_HT: 161 case PCI_PRODUCT_AMD_10_HT: 162 for (i = 0; i < AMD64HT_NUM_LDT; i++) 163 pchb_amd64ht_attach(self, pa, i); 164 break; 165 } 166 break; 167 case PCI_VENDOR_INTEL: 168 switch (PCI_PRODUCT(pa->pa_id)) { 169 case PCI_PRODUCT_INTEL_82915G_HB: 170 case PCI_PRODUCT_INTEL_82945G_HB: 171 case PCI_PRODUCT_INTEL_82925X_HB: 172 case PCI_PRODUCT_INTEL_82955X_HB: 173 sc->sc_bt = pa->pa_memt; 174 if (bus_space_map(sc->sc_bt, I82802_IOBASE, 175 I82802_IOSIZE, 0, &sc->sc_bh)) 176 break; 177 178 /* probe and init rng */ 179 if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh, 180 I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT)) 181 break; 182 183 /* enable RNG */ 184 bus_space_write_1(sc->sc_bt, sc->sc_bh, 185 I82802_RNG_HWST, 186 bus_space_read_1(sc->sc_bt, sc->sc_bh, 187 I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE); 188 189 /* see if we can read anything */ 190 for (i = 1000; i-- && 191 !(bus_space_read_1(sc->sc_bt, sc->sc_bh, 192 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV); ) 193 DELAY(10); 194 195 if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh, 196 I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV)) 197 break; 198 199 r = bus_space_read_1(sc->sc_bt, sc->sc_bh, 200 I82802_RNG_DATA); 201 202 timeout_set(&sc->sc_rng_to, pchb_rnd, sc); 203 sc->sc_rng_i = 4; 204 pchb_rnd(sc); 205 sc->sc_rng_active = 1; 206 break; 207 } 208 printf("\n"); 209 break; 210 case PCI_VENDOR_VIATECH: 211 switch (PCI_PRODUCT(pa->pa_id)) { 212 case PCI_PRODUCT_VIATECH_VT8251_PCIE_0: 213 /* 214 * Bump the host bridge into PCI-PCI bridge 215 * mode by clearing magic bit on the VLINK 216 * device. This allows us to read the bus 217 * number for the PCI bus attached to this 218 * host bridge. 219 */ 220 tag = pci_make_tag(pa->pa_pc, 0, 17, 7); 221 bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc); 222 bcreg &= ~0x00000004; /* XXX Magic */ 223 pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); 224 225 bir = pci_conf_read(pa->pa_pc, 226 pa->pa_tag, PPB_REG_BUSINFO); 227 pbnum = PPB_BUSINFO_PRIMARY(bir); 228 if (pbnum > 0) 229 doattach = 1; 230 231 /* Switch back to host bridge mode. */ 232 bcreg |= 0x00000004; /* XXX Magic */ 233 pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); 234 break; 235 } 236 printf("\n"); 237 break; 238 default: 239 printf("\n"); 240 break; 241 } 242 243 #if NAGP > 0 244 /* 245 * Intel IGD have an odd interface and attach at vga, however, 246 * in that mode they don't have the AGP cap bit, so this 247 * test should be sufficient 248 */ 249 if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, 250 NULL, NULL) != 0) { 251 struct agp_attach_args aa; 252 aa.aa_busname = "agp"; 253 aa.aa_pa = pa; 254 255 config_found(self, &aa, agpdev_print); 256 } 257 #endif /* NAGP > 0 */ 258 259 if (doattach == 0) 260 return; 261 262 bzero(&pba, sizeof(pba)); 263 pba.pba_busname = "pci"; 264 pba.pba_iot = pa->pa_iot; 265 pba.pba_memt = pa->pa_memt; 266 pba.pba_dmat = pa->pa_dmat; 267 pba.pba_busex = pa->pa_busex; 268 pba.pba_domain = pa->pa_domain; 269 pba.pba_bus = pbnum; 270 pba.pba_pc = pa->pa_pc; 271 config_found(self, &pba, pchb_print); 272 } 273 274 int 275 pchbactivate(struct device *self, int act) 276 { 277 struct pchb_softc *sc = (struct pchb_softc *)self; 278 int rv = 0; 279 280 switch (act) { 281 case DVACT_RESUME: 282 /* re-enable RNG, if we have it */ 283 if (sc->sc_rng_active) 284 bus_space_write_1(sc->sc_bt, sc->sc_bh, 285 I82802_RNG_HWST, 286 bus_space_read_1(sc->sc_bt, sc->sc_bh, 287 I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE); 288 rv = config_activate_children(self, act); 289 break; 290 default: 291 rv = config_activate_children(self, act); 292 break; 293 } 294 return (rv); 295 } 296 297 int 298 pchb_print(void *aux, const char *pnp) 299 { 300 struct pcibus_attach_args *pba = aux; 301 302 if (pnp) 303 printf("%s at %s", pba->pba_busname, pnp); 304 printf(" bus %d", pba->pba_bus); 305 return (UNCONF); 306 } 307 308 /* 309 * Should do FIPS testing as per: 310 * http://csrc.nist.gov/publications/fips/fips140-1/fips1401.pdf 311 */ 312 void 313 pchb_rnd(void *v) 314 { 315 struct pchb_softc *sc = v; 316 317 /* 318 * Don't wait for data to be ready. If it's not there, we'll check 319 * next time. 320 */ 321 if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_RNGST) & 322 I82802_RNG_RNGST_DATAV)) { 323 324 sc->sc_rng_ax = (sc->sc_rng_ax << 8) | 325 bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_DATA); 326 327 if (!sc->sc_rng_i--) { 328 sc->sc_rng_i = 4; 329 enqueue_randomness(sc->sc_rng_ax); 330 } 331 } 332 333 timeout_add(&sc->sc_rng_to, 1); 334 } 335 336 void 337 pchb_amd64ht_attach(struct device *self, struct pci_attach_args *pa, int i) 338 { 339 struct pcibus_attach_args pba; 340 pcireg_t type, bus; 341 int reg; 342 343 reg = AMD64HT_LDT0_TYPE + i * 0x20; 344 type = pci_conf_read(pa->pa_pc, pa->pa_tag, reg); 345 if ((type & AMD64HT_LDT_INIT_COMPLETE) == 0 || 346 (type & AMD64HT_LDT_NC) == 0) 347 return; 348 349 reg = AMD64HT_LDT0_BUS + i * 0x20; 350 bus = pci_conf_read(pa->pa_pc, pa->pa_tag, reg); 351 if (AMD64HT_LDT_SEC_BUS_NUM(bus) > 0) { 352 bzero(&pba, sizeof(pba)); 353 pba.pba_busname = "pci"; 354 pba.pba_iot = pa->pa_iot; 355 pba.pba_memt = pa->pa_memt; 356 pba.pba_dmat = pa->pa_dmat; 357 pba.pba_busex = pa->pa_busex; 358 pba.pba_domain = pa->pa_domain; 359 pba.pba_bus = AMD64HT_LDT_SEC_BUS_NUM(bus); 360 pba.pba_pc = pa->pa_pc; 361 config_found(self, &pba, pchb_print); 362 } 363 } 364