1 /* $OpenBSD: pci.c,v 1.5 1996/11/28 23:28:09 niklas Exp $ */ 2 /* $NetBSD: pci.c,v 1.24 1996/10/21 22:56:55 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 45 int pcimatch __P((struct device *, void *, void *)); 46 void pciattach __P((struct device *, struct device *, void *)); 47 48 struct cfattach pci_ca = { 49 sizeof(struct device), pcimatch, pciattach 50 }; 51 52 struct cfdriver pci_cd = { 53 NULL, "pci", DV_DULL 54 }; 55 56 int pciprint __P((void *, const char *)); 57 int pcisubmatch __P((struct device *, void *, void *)); 58 59 int 60 pcimatch(parent, match, aux) 61 struct device *parent; 62 void *match, *aux; 63 { 64 struct cfdata *cf = match; 65 struct pcibus_attach_args *pba = aux; 66 67 if (strcmp(pba->pba_busname, cf->cf_driver->cd_name)) 68 return (0); 69 70 /* Check the locators */ 71 if (cf->pcibuscf_bus != PCIBUS_UNK_BUS && 72 cf->pcibuscf_bus != pba->pba_bus) 73 return (0); 74 75 /* sanity */ 76 if (pba->pba_bus < 0 || pba->pba_bus > 255) 77 return (0); 78 79 /* 80 * XXX check other (hardware?) indicators 81 */ 82 83 return 1; 84 } 85 86 void 87 pciattach(parent, self, aux) 88 struct device *parent, *self; 89 void *aux; 90 { 91 struct pcibus_attach_args *pba = aux; 92 bus_space_tag_t iot, memt; 93 pci_chipset_tag_t pc; 94 int bus, device, maxndevs, function, nfunctions; 95 96 pci_attach_hook(parent, self, pba); 97 printf("\n"); 98 99 iot = pba->pba_iot; 100 memt = pba->pba_memt; 101 pc = pba->pba_pc; 102 bus = pba->pba_bus; 103 maxndevs = pci_bus_maxdevs(pc, bus); 104 105 for (device = 0; device < maxndevs; device++) { 106 pcitag_t tag; 107 pcireg_t id, class, intr, bhlcr; 108 struct pci_attach_args pa; 109 int pin; 110 111 tag = pci_make_tag(pc, bus, device, 0); 112 id = pci_conf_read(pc, tag, PCI_ID_REG); 113 if (id == 0 || id == 0xffffffff) 114 continue; 115 116 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 117 nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; 118 119 for (function = 0; function < nfunctions; function++) { 120 tag = pci_make_tag(pc, bus, device, function); 121 id = pci_conf_read(pc, tag, PCI_ID_REG); 122 if (id == 0 || id == 0xffffffff) 123 continue; 124 class = pci_conf_read(pc, tag, PCI_CLASS_REG); 125 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 126 127 pa.pa_iot = iot; 128 pa.pa_memt = memt; 129 pa.pa_pc = pc; 130 pa.pa_device = device; 131 pa.pa_function = function; 132 pa.pa_tag = tag; 133 pa.pa_id = id; 134 pa.pa_class = class; 135 136 if (bus == 0) { 137 pa.pa_intrswiz = 0; 138 pa.pa_intrtag = tag; 139 } else { 140 pa.pa_intrswiz = pba->pba_intrswiz + device; 141 pa.pa_intrtag = pba->pba_intrtag; 142 } 143 pin = PCI_INTERRUPT_PIN(intr); 144 if (pin == PCI_INTERRUPT_PIN_NONE) { 145 /* no interrupt */ 146 pa.pa_intrpin = 0; 147 } else { 148 /* 149 * swizzle it based on the number of 150 * busses we're behind and our device 151 * number. 152 */ 153 pa.pa_intrpin = /* XXX */ 154 ((pin + pa.pa_intrswiz - 1) % 4) + 1; 155 } 156 pa.pa_intrline = PCI_INTERRUPT_LINE(intr); 157 158 config_found_sm(self, &pa, pciprint, pcisubmatch); 159 } 160 } 161 } 162 163 int 164 pciprint(aux, pnp) 165 void *aux; 166 const char *pnp; 167 { 168 register struct pci_attach_args *pa = aux; 169 char devinfo[256]; 170 171 if (pnp) { 172 pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo); 173 printf("%s at %s", devinfo, pnp); 174 } 175 printf(" dev %d function %d", pa->pa_device, pa->pa_function); 176 return (UNCONF); 177 } 178 179 int 180 pcisubmatch(parent, match, aux) 181 struct device *parent; 182 void *match, *aux; 183 { 184 struct cfdata *cf = match; 185 struct pci_attach_args *pa = aux; 186 187 if (cf->pcicf_dev != PCI_UNK_DEV && 188 cf->pcicf_dev != pa->pa_device) 189 return 0; 190 if (cf->pcicf_function != PCI_UNK_FUNCTION && 191 cf->pcicf_function != pa->pa_function) 192 return 0; 193 return ((*cf->cf_attach->ca_match)(parent, match, aux)); 194 } 195 196 int 197 pci_io_find(pc, pcitag, reg, iobasep, iosizep) 198 pci_chipset_tag_t pc; 199 pcitag_t pcitag; 200 int reg; 201 bus_addr_t *iobasep; 202 bus_size_t *iosizep; 203 { 204 pcireg_t addrdata, sizedata; 205 int s; 206 207 if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) 208 panic("pci_io_find: bad request"); 209 210 /* XXX? 211 * Section 6.2.5.1, `Address Maps', tells us that: 212 * 213 * 1) The builtin software should have already mapped the device in a 214 * reasonable way. 215 * 216 * 2) A device which wants 2^n bytes of memory will hardwire the bottom 217 * n bits of the address to 0. As recommended, we write all 1s and see 218 * what we get back. 219 */ 220 addrdata = pci_conf_read(pc, pcitag, reg); 221 222 s = splhigh(); 223 pci_conf_write(pc, pcitag, reg, 0xffffffff); 224 sizedata = pci_conf_read(pc, pcitag, reg); 225 pci_conf_write(pc, pcitag, reg, addrdata); 226 splx(s); 227 228 if (PCI_MAPREG_TYPE(addrdata) != PCI_MAPREG_TYPE_IO) 229 panic("pci_io_find: not an I/O region"); 230 231 if (iobasep != NULL) 232 *iobasep = PCI_MAPREG_IO_ADDR(addrdata); 233 if (iosizep != NULL) 234 *iosizep = PCI_MAPREG_IO_SIZE(sizedata); 235 236 return (0); 237 } 238 239 int 240 pci_mem_find(pc, pcitag, reg, membasep, memsizep, cacheablep) 241 pci_chipset_tag_t pc; 242 pcitag_t pcitag; 243 int reg; 244 bus_addr_t *membasep; 245 bus_size_t *memsizep; 246 int *cacheablep; 247 { 248 pcireg_t addrdata, sizedata; 249 int s; 250 251 if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) 252 panic("pci_find_mem: bad request"); 253 254 /* 255 * Section 6.2.5.1, `Address Maps', tells us that: 256 * 257 * 1) The builtin software should have already mapped the device in a 258 * reasonable way. 259 * 260 * 2) A device which wants 2^n bytes of memory will hardwire the bottom 261 * n bits of the address to 0. As recommended, we write all 1s and see 262 * what we get back. 263 */ 264 addrdata = pci_conf_read(pc, pcitag, reg); 265 266 s = splhigh(); 267 pci_conf_write(pc, pcitag, reg, 0xffffffff); 268 sizedata = pci_conf_read(pc, pcitag, reg); 269 pci_conf_write(pc, pcitag, reg, addrdata); 270 splx(s); 271 272 if (PCI_MAPREG_TYPE(addrdata) == PCI_MAPREG_TYPE_IO) 273 panic("pci_find_mem: I/O region"); 274 275 switch (PCI_MAPREG_MEM_TYPE(addrdata)) { 276 case PCI_MAPREG_MEM_TYPE_32BIT: 277 case PCI_MAPREG_MEM_TYPE_32BIT_1M: 278 break; 279 case PCI_MAPREG_MEM_TYPE_64BIT: 280 /* XXX */ printf("pci_find_mem: 64-bit region\n"); 281 /* XXX */ return (1); 282 default: 283 printf("pci_find_mem: reserved region type\n"); 284 return (1); 285 } 286 287 if (membasep != NULL) 288 *membasep = PCI_MAPREG_MEM_ADDR(addrdata); /* PCI addr */ 289 if (memsizep != NULL) 290 *memsizep = PCI_MAPREG_MEM_SIZE(sizedata); 291 if (cacheablep != NULL) 292 *cacheablep = PCI_MAPREG_MEM_CACHEABLE(addrdata); 293 294 return 0; 295 } 296