1 /* $NetBSD: pci.c,v 1.29 1997/08/30 06:53:57 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1995, 1996, 1997 5 * 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 #ifdef __BROKEN_INDIRECT_CONFIG 46 int pcimatch __P((struct device *, void *, void *)); 47 #else 48 int pcimatch __P((struct device *, struct cfdata *, void *)); 49 #endif 50 void pciattach __P((struct device *, struct device *, void *)); 51 52 struct cfattach pci_ca = { 53 sizeof(struct device), pcimatch, pciattach 54 }; 55 56 struct cfdriver pci_cd = { 57 NULL, "pci", DV_DULL 58 }; 59 60 int pciprint __P((void *, const char *)); 61 #ifdef __BROKEN_INDIRECT_CONFIG 62 int pcisubmatch __P((struct device *, void *, void *)); 63 #else 64 int pcisubmatch __P((struct device *, struct cfdata *, void *)); 65 #endif 66 67 /* 68 * Callback so that ISA/EISA bridges can attach their child busses 69 * after PCI configuration is done. 70 * 71 * This works because: 72 * (1) there can be at most one ISA/EISA bridge per PCI bus, and 73 * (2) any ISA/EISA bridges must be attached to primary PCI 74 * busses (i.e. bus zero). 75 * 76 * That boils down to: there can only be one of these outstanding 77 * at a time, it is cleared when configuring PCI bus 0 before any 78 * subdevices have been found, and it is run after all subdevices 79 * of PCI bus 0 have been found. 80 * 81 * This is needed because there are some (legacy) PCI devices which 82 * can show up as ISA/EISA devices as well (the prime example of which 83 * are VGA controllers). If you attach ISA from a PCI-ISA/EISA bridge, 84 * and the bridge is seen before the video board is, the board can show 85 * up as an ISA device, and that can (bogusly) complicate the PCI device's 86 * attach code, or make the PCI device not be properly attached at all. 87 */ 88 static void (*pci_isa_bridge_callback) __P((void *)); 89 static void *pci_isa_bridge_callback_arg; 90 91 int 92 #ifdef __BROKEN_INDIRECT_CONFIG 93 pcimatch(parent, match, aux) 94 #else 95 pcimatch(parent, cf, aux) 96 #endif 97 struct device *parent; 98 #ifdef __BROKEN_INDIRECT_CONFIG 99 void *match; 100 #else 101 struct cfdata *cf; 102 #endif 103 void *aux; 104 { 105 #ifdef __BROKEN_INDIRECT_CONFIG 106 struct cfdata *cf = match; 107 #endif 108 struct pcibus_attach_args *pba = aux; 109 110 if (strcmp(pba->pba_busname, cf->cf_driver->cd_name)) 111 return (0); 112 113 /* Check the locators */ 114 if (cf->pcibuscf_bus != PCIBUS_UNK_BUS && 115 cf->pcibuscf_bus != pba->pba_bus) 116 return (0); 117 118 /* sanity */ 119 if (pba->pba_bus < 0 || pba->pba_bus > 255) 120 return (0); 121 122 /* 123 * XXX check other (hardware?) indicators 124 */ 125 126 return 1; 127 } 128 129 void 130 pciattach(parent, self, aux) 131 struct device *parent, *self; 132 void *aux; 133 { 134 struct pcibus_attach_args *pba = aux; 135 bus_space_tag_t iot, memt; 136 pci_chipset_tag_t pc; 137 int bus, device, maxndevs, function, nfunctions; 138 139 pci_attach_hook(parent, self, pba); 140 printf("\n"); 141 142 iot = pba->pba_iot; 143 memt = pba->pba_memt; 144 pc = pba->pba_pc; 145 bus = pba->pba_bus; 146 maxndevs = pci_bus_maxdevs(pc, bus); 147 148 if (bus == 0) 149 pci_isa_bridge_callback = NULL; 150 151 for (device = 0; device < maxndevs; device++) { 152 pcitag_t tag; 153 pcireg_t id, class, intr, bhlcr, csr; 154 struct pci_attach_args pa; 155 int pin; 156 157 tag = pci_make_tag(pc, bus, device, 0); 158 id = pci_conf_read(pc, tag, PCI_ID_REG); 159 if (id == 0 || id == 0xffffffff) 160 continue; 161 162 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 163 nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; 164 165 for (function = 0; function < nfunctions; function++) { 166 tag = pci_make_tag(pc, bus, device, function); 167 id = pci_conf_read(pc, tag, PCI_ID_REG); 168 if (id == 0 || id == 0xffffffff) 169 continue; 170 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 171 class = pci_conf_read(pc, tag, PCI_CLASS_REG); 172 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 173 174 pa.pa_iot = iot; 175 pa.pa_memt = memt; 176 pa.pa_dmat = pba->pba_dmat; 177 pa.pa_pc = pc; 178 pa.pa_device = device; 179 pa.pa_function = function; 180 pa.pa_tag = tag; 181 pa.pa_id = id; 182 pa.pa_class = class; 183 184 /* set up memory and I/O enable flags as appropriate */ 185 pa.pa_flags = 0; 186 if ((pba->pba_flags & PCI_FLAGS_IO_ENABLED) && 187 (csr & PCI_COMMAND_IO_ENABLE)) 188 pa.pa_flags |= PCI_FLAGS_IO_ENABLED; 189 if ((pba->pba_flags & PCI_FLAGS_MEM_ENABLED) && 190 (csr & PCI_COMMAND_MEM_ENABLE)) 191 pa.pa_flags |= PCI_FLAGS_MEM_ENABLED; 192 193 if (bus == 0) { 194 pa.pa_intrswiz = 0; 195 pa.pa_intrtag = tag; 196 } else { 197 pa.pa_intrswiz = pba->pba_intrswiz + device; 198 pa.pa_intrtag = pba->pba_intrtag; 199 } 200 pin = PCI_INTERRUPT_PIN(intr); 201 if (pin == PCI_INTERRUPT_PIN_NONE) { 202 /* no interrupt */ 203 pa.pa_intrpin = 0; 204 } else { 205 /* 206 * swizzle it based on the number of 207 * busses we're behind and our device 208 * number. 209 */ 210 pa.pa_intrpin = /* XXX */ 211 ((pin + pa.pa_intrswiz - 1) % 4) + 1; 212 } 213 pa.pa_intrline = PCI_INTERRUPT_LINE(intr); 214 215 config_found_sm(self, &pa, pciprint, pcisubmatch); 216 } 217 } 218 219 if (bus == 0 && pci_isa_bridge_callback != NULL) 220 (*pci_isa_bridge_callback)(pci_isa_bridge_callback_arg); 221 } 222 223 int 224 pciprint(aux, pnp) 225 void *aux; 226 const char *pnp; 227 { 228 register struct pci_attach_args *pa = aux; 229 char devinfo[256]; 230 231 if (pnp) { 232 pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo); 233 printf("%s at %s", devinfo, pnp); 234 } 235 printf(" dev %d function %d", pa->pa_device, pa->pa_function); 236 #if 0 237 printf(" (%si/o, %smem)", 238 pa->pa_flags & PCI_FLAGS_IO_ENABLED ? "" : "no ", 239 pa->pa_flags & PCI_FLAGS_MEM_ENABLED ? "" : "no "); 240 #endif 241 return (UNCONF); 242 } 243 244 int 245 #ifdef __BROKEN_INDIRECT_CONFIG 246 pcisubmatch(parent, match, aux) 247 #else 248 pcisubmatch(parent, cf, aux) 249 #endif 250 struct device *parent; 251 #ifdef __BROKEN_INDIRECT_CONFIG 252 void *match; 253 #else 254 struct cfdata *cf; 255 #endif 256 void *aux; 257 { 258 #ifdef __BROKEN_INDIRECT_CONFIG 259 struct cfdata *cf = match; 260 #endif 261 struct pci_attach_args *pa = aux; 262 263 if (cf->pcicf_dev != PCI_UNK_DEV && 264 cf->pcicf_dev != pa->pa_device) 265 return 0; 266 if (cf->pcicf_function != PCI_UNK_FUNCTION && 267 cf->pcicf_function != pa->pa_function) 268 return 0; 269 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 270 } 271 272 void 273 set_pci_isa_bridge_callback(fn, arg) 274 void (*fn) __P((void *)); 275 void *arg; 276 { 277 278 if (pci_isa_bridge_callback != NULL) 279 panic("set_pci_isa_bridge_callback"); 280 pci_isa_bridge_callback = fn; 281 pci_isa_bridge_callback_arg = arg; 282 } 283