1 /* $OpenBSD: pci.c,v 1.14 1998/10/29 18:11:53 csapuntz Exp $ */ 2 /* $NetBSD: pci.c,v 1.31 1997/06/06 23:48:04 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1995, 1996 Christopher G. Demetriou. All rights reserved. 6 * Copyright (c) 1994 Charles Hannum. 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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles Hannum. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * PCI bus autoconfiguration. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcidevs.h> 45 46 int pcimatch __P((struct device *, void *, void *)); 47 void pciattach __P((struct device *, struct device *, void *)); 48 49 struct cfattach pci_ca = { 50 sizeof(struct device), pcimatch, pciattach 51 }; 52 53 struct cfdriver pci_cd = { 54 NULL, "pci", DV_DULL 55 }; 56 57 int pciprint __P((void *, const char *)); 58 int pcisubmatch __P((struct device *, void *, void *)); 59 60 /* 61 * Callback so that ISA/EISA bridges can attach their child busses 62 * after PCI configuration is done. 63 * 64 * This works because: 65 * (1) there can be at most one ISA/EISA bridge per PCI bus, and 66 * (2) any ISA/EISA bridges must be attached to primary PCI 67 * busses (i.e. bus zero). 68 * 69 * That boils down to: there can only be one of these outstanding 70 * at a time, it is cleared when configuring PCI bus 0 before any 71 * subdevices have been found, and it is run after all subdevices 72 * of PCI bus 0 have been found. 73 * 74 * This is needed because there are some (legacy) PCI devices which 75 * can show up as ISA/EISA devices as well (the prime example of which 76 * are VGA controllers). If you attach ISA from a PCI-ISA/EISA bridge, 77 * and the bridge is seen before the video board is, the board can show 78 * up as an ISA device, and that can (bogusly) complicate the PCI device's 79 * attach code, or make the PCI device not be properly attached at all. 80 */ 81 static void (*pci_isa_bridge_callback) __P((void *)); 82 static void *pci_isa_bridge_callback_arg; 83 84 int 85 pcimatch(parent, match, aux) 86 struct device *parent; 87 void *match, *aux; 88 { 89 struct cfdata *cf = match; 90 struct pcibus_attach_args *pba = aux; 91 92 if (strcmp(pba->pba_busname, cf->cf_driver->cd_name)) 93 return (0); 94 95 /* Check the locators */ 96 if (cf->pcibuscf_bus != PCIBUS_UNK_BUS && 97 cf->pcibuscf_bus != pba->pba_bus) 98 return (0); 99 100 /* sanity */ 101 if (pba->pba_bus < 0 || pba->pba_bus > 255) 102 return (0); 103 104 /* 105 * XXX check other (hardware?) indicators 106 */ 107 108 return 1; 109 } 110 111 void 112 pciattach(parent, self, aux) 113 struct device *parent, *self; 114 void *aux; 115 { 116 struct pcibus_attach_args *pba = aux; 117 bus_space_tag_t iot, memt; 118 pci_chipset_tag_t pc; 119 int bus, device, maxndevs, function, nfunctions; 120 121 pci_attach_hook(parent, self, pba); 122 printf("\n"); 123 124 iot = pba->pba_iot; 125 memt = pba->pba_memt; 126 pc = pba->pba_pc; 127 bus = pba->pba_bus; 128 maxndevs = pci_bus_maxdevs(pc, bus); 129 130 if (bus == 0) 131 pci_isa_bridge_callback = NULL; 132 133 for (device = 0; device < maxndevs; device++) { 134 pcitag_t tag; 135 pcireg_t id, class, intr, bhlcr; 136 struct pci_attach_args pa; 137 int pin; 138 139 tag = pci_make_tag(pc, bus, device, 0); 140 id = pci_conf_read(pc, tag, PCI_ID_REG); 141 142 /* Invalid vendor ID value? */ 143 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 144 continue; 145 /* XXX Not invalid, but we've done this ~forever. */ 146 if (PCI_VENDOR(id) == 0) 147 continue; 148 149 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 150 nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; 151 152 for (function = 0; function < nfunctions; function++) { 153 tag = pci_make_tag(pc, bus, device, function); 154 id = pci_conf_read(pc, tag, PCI_ID_REG); 155 156 /* Invalid vendor ID value? */ 157 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 158 continue; 159 /* XXX Not invalid, but we've done this ~forever. */ 160 if (PCI_VENDOR(id) == 0) 161 continue; 162 163 class = pci_conf_read(pc, tag, PCI_CLASS_REG); 164 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 165 166 pa.pa_iot = iot; 167 pa.pa_memt = memt; 168 pa.pa_dmat = pba->pba_dmat; 169 pa.pa_pc = pc; 170 pa.pa_device = device; 171 pa.pa_function = function; 172 pa.pa_tag = tag; 173 pa.pa_id = id; 174 pa.pa_class = class; 175 176 if (bus == 0) { 177 pa.pa_intrswiz = 0; 178 pa.pa_intrtag = tag; 179 } else { 180 pa.pa_intrswiz = pba->pba_intrswiz + device; 181 pa.pa_intrtag = pba->pba_intrtag; 182 } 183 pin = PCI_INTERRUPT_PIN(intr); 184 if (pin == PCI_INTERRUPT_PIN_NONE) { 185 /* no interrupt */ 186 pa.pa_intrpin = 0; 187 } else { 188 /* 189 * swizzle it based on the number of 190 * busses we're behind and our device 191 * number. 192 */ 193 pa.pa_intrpin = /* XXX */ 194 ((pin + pa.pa_intrswiz - 1) % 4) + 1; 195 } 196 pa.pa_intrline = PCI_INTERRUPT_LINE(intr); 197 198 config_found_sm(self, &pa, pciprint, pcisubmatch); 199 } 200 } 201 202 if (bus == 0 && pci_isa_bridge_callback != NULL) 203 (*pci_isa_bridge_callback)(pci_isa_bridge_callback_arg); 204 } 205 206 int 207 pciprint(aux, pnp) 208 void *aux; 209 const char *pnp; 210 { 211 register struct pci_attach_args *pa = aux; 212 char devinfo[256]; 213 214 if (pnp) { 215 pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo); 216 printf("%s at %s", devinfo, pnp); 217 } 218 printf(" dev %d function %d", pa->pa_device, pa->pa_function); 219 if (!pnp) { 220 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo); 221 printf(" %s", devinfo); 222 } 223 224 return (UNCONF); 225 } 226 227 int 228 pcisubmatch(parent, match, aux) 229 struct device *parent; 230 void *match, *aux; 231 { 232 struct cfdata *cf = match; 233 struct pci_attach_args *pa = aux; 234 int success; 235 236 if (cf->pcicf_dev != PCI_UNK_DEV && 237 cf->pcicf_dev != pa->pa_device) 238 return 0; 239 if (cf->pcicf_function != PCI_UNK_FUNCTION && 240 cf->pcicf_function != pa->pa_function) 241 return 0; 242 243 success = (*cf->cf_attach->ca_match)(parent, match, aux); 244 245 /* My Dell BIOS does not enable certain non-critical PCI devices 246 for IO and memory cycles (e.g. network card). This is 247 the generic approach to fixing this problem. Basically, if 248 we support the card, then we enable its IO cycles. 249 */ 250 if (success) { 251 u_int32_t csr = pci_conf_read(pa->pa_pc, pa->pa_tag, 252 PCI_COMMAND_STATUS_REG); 253 254 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 255 csr | PCI_COMMAND_MASTER_ENABLE | 256 PCI_COMMAND_IO_ENABLE | 257 PCI_COMMAND_MEM_ENABLE); 258 } 259 260 return (success); 261 } 262 263 int 264 pci_io_find(pc, pcitag, reg, iobasep, iosizep) 265 pci_chipset_tag_t pc; 266 pcitag_t pcitag; 267 int reg; 268 bus_addr_t *iobasep; 269 bus_size_t *iosizep; 270 { 271 pcireg_t addrdata, sizedata; 272 int s; 273 274 if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) 275 panic("pci_io_find: bad request"); 276 277 /* XXX? 278 * Section 6.2.5.1, `Address Maps', tells us that: 279 * 280 * 1) The builtin software should have already mapped the device in a 281 * reasonable way. 282 * 283 * 2) A device which wants 2^n bytes of memory will hardwire the bottom 284 * n bits of the address to 0. As recommended, we write all 1s and see 285 * what we get back. 286 */ 287 addrdata = pci_conf_read(pc, pcitag, reg); 288 289 s = splhigh(); 290 pci_conf_write(pc, pcitag, reg, 0xffffffff); 291 sizedata = pci_conf_read(pc, pcitag, reg); 292 pci_conf_write(pc, pcitag, reg, addrdata); 293 splx(s); 294 295 if (PCI_MAPREG_TYPE(addrdata) != PCI_MAPREG_TYPE_IO) 296 panic("pci_io_find: not an I/O region"); 297 298 if (iobasep != NULL) 299 *iobasep = PCI_MAPREG_IO_ADDR(addrdata); 300 if (iosizep != NULL) 301 *iosizep = PCI_MAPREG_IO_SIZE(sizedata); 302 303 #ifdef powerpc 304 /* 305 * Open Firmware (yuck) shuts down devices before entering a 306 * program so we need to bring them back 'online' to respond 307 * to bus accesses... so far this is true on the power.4e. 308 */ 309 s = splhigh(); 310 sizedata = pci_conf_read(pc, pcitag, PCI_COMMAND_STATUS_REG); 311 sizedata |= (PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE | 312 PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE); 313 pci_conf_write(pc, pcitag, PCI_COMMAND_STATUS_REG, sizedata); 314 splx(s); 315 #endif 316 317 return (0); 318 } 319 320 int 321 pci_mem_find(pc, pcitag, reg, membasep, memsizep, cacheablep) 322 pci_chipset_tag_t pc; 323 pcitag_t pcitag; 324 int reg; 325 bus_addr_t *membasep; 326 bus_size_t *memsizep; 327 int *cacheablep; 328 { 329 pcireg_t addrdata, sizedata; 330 int s; 331 332 if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) 333 panic("pci_find_mem: bad request"); 334 335 /* 336 * Section 6.2.5.1, `Address Maps', tells us that: 337 * 338 * 1) The builtin software should have already mapped the device in a 339 * reasonable way. 340 * 341 * 2) A device which wants 2^n bytes of memory will hardwire the bottom 342 * n bits of the address to 0. As recommended, we write all 1s and see 343 * what we get back. 344 */ 345 addrdata = pci_conf_read(pc, pcitag, reg); 346 347 s = splhigh(); 348 pci_conf_write(pc, pcitag, reg, 0xffffffff); 349 sizedata = pci_conf_read(pc, pcitag, reg); 350 pci_conf_write(pc, pcitag, reg, addrdata); 351 splx(s); 352 353 if (PCI_MAPREG_TYPE(addrdata) == PCI_MAPREG_TYPE_IO) 354 panic("pci_find_mem: I/O region"); 355 356 switch (PCI_MAPREG_MEM_TYPE(addrdata)) { 357 case PCI_MAPREG_MEM_TYPE_32BIT: 358 case PCI_MAPREG_MEM_TYPE_32BIT_1M: 359 break; 360 case PCI_MAPREG_MEM_TYPE_64BIT: 361 /* XXX */ printf("pci_find_mem: 64-bit region\n"); 362 /* XXX */ return (1); 363 default: 364 printf("pci_find_mem: reserved region type\n"); 365 return (1); 366 } 367 368 if (membasep != NULL) 369 *membasep = PCI_MAPREG_MEM_ADDR(addrdata); /* PCI addr */ 370 if (memsizep != NULL) 371 *memsizep = PCI_MAPREG_MEM_SIZE(sizedata); 372 if (cacheablep != NULL) 373 *cacheablep = PCI_MAPREG_MEM_CACHEABLE(addrdata); 374 375 #ifdef powerpc 376 /* 377 * Open Firmware (yuck) shuts down devices before entering a 378 * program so we need to bring them back 'online' to respond 379 * to bus accesses... so far this is true on the power.4e. 380 */ 381 s = splhigh(); 382 sizedata = pci_conf_read(pc, pcitag, PCI_COMMAND_STATUS_REG); 383 sizedata |= (PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE | 384 PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE); 385 pci_conf_write(pc, pcitag, PCI_COMMAND_STATUS_REG, sizedata); 386 splx(s); 387 #endif 388 389 return 0; 390 } 391 392 void 393 set_pci_isa_bridge_callback(fn, arg) 394 void (*fn) __P((void *)); 395 void *arg; 396 { 397 398 if (pci_isa_bridge_callback != NULL) 399 panic("set_pci_isa_bridge_callback"); 400 pci_isa_bridge_callback = fn; 401 pci_isa_bridge_callback_arg = arg; 402 } 403