pci_pir.c (97694) | pci_pir.c (100435) |
---|---|
1/* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4 * Copyright (c) 2000, BSDi 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 --- 11 unchanged lines hidden (view full) --- 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * | 1/* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4 * Copyright (c) 2000, BSDi 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 --- 11 unchanged lines hidden (view full) --- 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * |
28 * $FreeBSD: head/sys/i386/pci/pci_pir.c 97694 2002-06-01 05:14:11Z imp $ | 28 * $FreeBSD: head/sys/i386/pci/pci_pir.c 100435 2002-07-21 05:35:42Z imp $ |
29 * 30 */ 31 32#include <sys/param.h> /* XXX trim includes */ 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/kernel.h> 36#include <sys/module.h> 37#include <sys/malloc.h> 38#include <vm/vm.h> 39#include <vm/pmap.h> 40#include <machine/md_var.h> | 29 * 30 */ 31 32#include <sys/param.h> /* XXX trim includes */ 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/kernel.h> 36#include <sys/module.h> 37#include <sys/malloc.h> 38#include <vm/vm.h> 39#include <vm/pmap.h> 40#include <machine/md_var.h> |
41#include 42#include | 41#include <dev/pci/pcivar.h> 42#include <dev/pci/pcireg.h> |
43#include <isa/isavar.h> 44#include <machine/nexusvar.h> 45#include <machine/pci_cfgreg.h> 46#include <machine/segments.h> 47#include <machine/pc/bios.h> 48 49#ifdef APIC_IO 50#include <machine/smp.h> --- 30 unchanged lines hidden (view full) --- 81 * 0 in the intline rather than 255 to indicate none. Some use 82 * numbers in the range 128-254 to indicate something strange and 83 * apparently undocumented anywhere. Assume these are completely bogus 84 * and map them to 255, which means "none". 85 */ 86static __inline__ int 87pci_i386_map_intline(int line) 88{ | 43#include <isa/isavar.h> 44#include <machine/nexusvar.h> 45#include <machine/pci_cfgreg.h> 46#include <machine/segments.h> 47#include <machine/pc/bios.h> 48 49#ifdef APIC_IO 50#include <machine/smp.h> --- 30 unchanged lines hidden (view full) --- 81 * 0 in the intline rather than 255 to indicate none. Some use 82 * numbers in the range 128-254 to indicate something strange and 83 * apparently undocumented anywhere. Assume these are completely bogus 84 * and map them to 255, which means "none". 85 */ 86static __inline__ int 87pci_i386_map_intline(int line) 88{ |
89 if (line == 0 || line >= 128) 90 return (255); 91 return (line); | 89 if (line == 0 || line >= 128) 90 return (PCI_INVALID_IRQ); 91 return (line); |
92} 93 94int 95pci_pcibios_active(void) 96{ | 92} 93 94int 95pci_pcibios_active(void) 96{ |
97 return usebios; | 97 return (usebios); |
98} 99 100int 101pci_kill_pcibios(void) 102{ | 98} 99 100int 101pci_kill_pcibios(void) 102{ |
103 usebios = 0; 104 return pcireg_cfgopen() != 0; | 103 usebios = 0; 104 return (pcireg_cfgopen() != 0); |
105} 106 107static u_int16_t 108pcibios_get_version(void) 109{ | 105} 106 107static u_int16_t 108pcibios_get_version(void) 109{ |
110 struct bios_regs args; | 110 struct bios_regs args; |
111 | 111 |
112 if (PCIbios.entry == 0) { 113 PRVERB(("pcibios: No call entry point\n")); 114 return (0); 115 } 116 args.eax = PCIBIOS_BIOS_PRESENT; 117 if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 118 PRVERB(("pcibios: BIOS_PRESENT call failed\n")); 119 return (0); 120 } 121 if (args.edx != 0x20494350) { 122 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n")); 123 return (0); 124 } 125 return (args.ebx & 0xffff); | 112 if (PCIbios.entry == 0) { 113 PRVERB(("pcibios: No call entry point\n")); 114 return (0); 115 } 116 args.eax = PCIBIOS_BIOS_PRESENT; 117 if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 118 PRVERB(("pcibios: BIOS_PRESENT call failed\n")); 119 return (0); 120 } 121 if (args.edx != 0x20494350) { 122 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n")); 123 return (0); 124 } 125 return (args.ebx & 0xffff); |
126} 127 128/* 129 * Initialise access to PCI configuration space 130 */ 131int 132pci_cfgregopen(void) 133{ | 126} 127 128/* 129 * Initialise access to PCI configuration space 130 */ 131int 132pci_cfgregopen(void) 133{ |
134 static int opened = 0; 135 u_long sigaddr; 136 static struct PIR_table *pt; 137 u_int8_t ck, *cv; 138 int i; | 134 static int opened = 0; 135 u_long sigaddr; 136 static struct PIR_table *pt; 137 u_int8_t ck, *cv; 138 int i; |
139 | 139 |
140 if (opened) 141 return(1); | 140 if (opened) 141 return(1); |
142 | 142 |
143 if (pcibios_cfgopen() != 0) { 144 usebios = 1; 145 } else if (pcireg_cfgopen() != 0) { 146 usebios = 0; 147 } else { 148 return(0); 149 } | 143 if (pcibios_cfgopen() != 0) 144 usebios = 1; 145 else if (pcireg_cfgopen() != 0) 146 usebios = 0; 147 else 148 return(0); |
150 | 149 |
151 /* 152 * Look for the interrupt routing table. 153 * 154 * We use PCI BIOS's PIR table if it's available $PIR is the 155 * standard way to do this. Sadly, some machines are not 156 * standards conforming and have _PIR instead. We shrug and cope 157 * by looking for both. 158 */ 159 if (pcibios_get_version() >= 0x0210 && pt == NULL) { 160 sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0); 161 if (sigaddr == 0) 162 sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0); 163 if (sigaddr != 0) { 164 pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); 165 for (cv = (u_int8_t *)pt, ck = 0, i = 0; 166 i < (pt->pt_header.ph_length); i++) { 167 ck += cv[i]; 168 } 169 if (ck == 0) { 170 pci_route_table = pt; 171 pci_route_count = (pt->pt_header.ph_length - 172 sizeof(struct PIR_header)) / sizeof(struct PIR_entry); 173 printf("Using $PIR table, %d entries at %p\n", 174 pci_route_count, pci_route_table); 175 } | 150 /* 151 * Look for the interrupt routing table. 152 * 153 * We use PCI BIOS's PIR table if it's available $PIR is the 154 * standard way to do this. Sadly, some machines are not 155 * standards conforming and have _PIR instead. We shrug and cope 156 * by looking for both. 157 */ 158 if (pcibios_get_version() >= 0x0210 && pt == NULL) { 159 sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0); 160 if (sigaddr == 0) 161 sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0); 162 if (sigaddr != 0) { 163 pt = (struct PIR_table *)(uintptr_t) 164 BIOS_PADDRTOVADDR(sigaddr); 165 for (cv = (u_int8_t *)pt, ck = 0, i = 0; 166 i < (pt->pt_header.ph_length); i++) { 167 ck += cv[i]; 168 } 169 if (ck == 0) { 170 pci_route_table = pt; 171 pci_route_count = (pt->pt_header.ph_length - 172 sizeof(struct PIR_header)) / 173 sizeof(struct PIR_entry); 174 printf("Using $PIR table, %d entries at %p\n", 175 pci_route_count, pci_route_table); 176 } 177 } |
176 } | 178 } |
177 } 178 opened = 1; 179 return(1); | 179 opened = 1; 180 return(1); |
180} 181 182/* 183 * Read configuration space register 184 */ 185static u_int32_t 186pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes) 187{ | 181} 182 183/* 184 * Read configuration space register 185 */ 186static u_int32_t 187pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes) 188{ |
188 return(usebios ? 189 pcibios_cfgread(bus, slot, func, reg, bytes) : 190 pcireg_cfgread(bus, slot, func, reg, bytes)); | 189 return(usebios ? 190 pcibios_cfgread(bus, slot, func, reg, bytes) : 191 pcireg_cfgread(bus, slot, func, reg, bytes)); |
191} 192 193u_int32_t 194pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 195{ | 192} 193 194u_int32_t 195pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 196{ |
196 uint32_t line, pin; | 197 uint32_t line; |
197#ifdef APIC_IO | 198#ifdef APIC_IO |
198 /* 199 * If we are using the APIC, the contents of the intline register will probably 200 * be wrong (since they are set up for use with the PIC. 201 * Rather than rewrite these registers (maybe that would be smarter) we trap 202 * attempts to read them and translate to our private vector numbers. 203 */ 204 if ((reg == PCIR_INTLINE) && (bytes == 1)) { | 199 uint32_t pin; |
205 | 200 |
206 pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); 207 line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); | 201 /* 202 * If we are using the APIC, the contents of the intline 203 * register will probably be wrong (since they are set up for 204 * use with the PIC. Rather than rewrite these registers 205 * (maybe that would be smarter) we trap attempts to read them 206 * and translate to our private vector numbers. 207 */ 208 if ((reg == PCIR_INTLINE) && (bytes == 1)) { |
208 | 209 |
209 if (pin != 0) { 210 int airq; | 210 pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); 211 line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); |
211 | 212 |
212 airq = pci_apic_irq(bus, slot, pin); 213 if (airq >= 0) { 214 /* PCI specific entry found in MP table */ 215 if (airq != line) 216 undirect_pci_irq(line); 217 return(airq); 218 } else { 219 /* 220 * PCI interrupts might be redirected to the 221 * ISA bus according to some MP tables. Use the 222 * same methods as used by the ISA devices 223 * devices to find the proper IOAPIC int pin. 224 */ 225 airq = isa_apic_irq(line); 226 if ((airq >= 0) && (airq != line)) { 227 /* XXX: undirect_pci_irq() ? */ 228 undirect_isa_irq(line); 229 return(airq); | 213 if (pin != 0) { 214 int airq; 215 216 airq = pci_apic_irq(bus, slot, pin); 217 if (airq >= 0) { 218 /* PCI specific entry found in MP table */ 219 if (airq != line) 220 undirect_pci_irq(line); 221 return(airq); 222 } else { 223 /* 224 * PCI interrupts might be redirected 225 * to the ISA bus according to some MP 226 * tables. Use the same methods as 227 * used by the ISA devices devices to 228 * find the proper IOAPIC int pin. 229 */ 230 airq = isa_apic_irq(line); 231 if ((airq >= 0) && (airq != line)) { 232 /* XXX: undirect_pci_irq() ? */ 233 undirect_isa_irq(line); 234 return(airq); 235 } 236 } |
230 } | 237 } |
231 } | 238 return(line); |
232 } | 239 } |
233 return(line); 234 } | |
235#else | 240#else |
236 /* 237 * Some BIOS writers seem to want to ignore the spec and put 238 * 0 in the intline rather than 255 to indicate none. The rest of 239 * the code uses 255 as an invalid IRQ. 240 */ 241 if (reg == PCIR_INTLINE && bytes == 1) { 242 line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); 243 pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); 244 return pci_i386_map_intline(line); 245 } | 241 /* 242 * Some BIOS writers seem to want to ignore the spec and put 243 * 0 in the intline rather than 255 to indicate none. The rest of 244 * the code uses 255 as an invalid IRQ. 245 */ 246 if (reg == PCIR_INTLINE && bytes == 1) { 247 line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); 248 return pci_i386_map_intline(line); 249 } |
246#endif /* APIC_IO */ | 250#endif /* APIC_IO */ |
247 return(pci_do_cfgregread(bus, slot, func, reg, bytes)); | 251 return(pci_do_cfgregread(bus, slot, func, reg, bytes)); |
248} 249 250/* 251 * Write configuration space register 252 */ 253void 254pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 255{ | 252} 253 254/* 255 * Write configuration space register 256 */ 257void 258pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 259{ |
256 return(usebios ? 257 pcibios_cfgwrite(bus, slot, func, reg, data, bytes) : 258 pcireg_cfgwrite(bus, slot, func, reg, data, bytes)); | 260 return (usebios ? 261 pcibios_cfgwrite(bus, slot, func, reg, data, bytes) : 262 pcireg_cfgwrite(bus, slot, func, reg, data, bytes)); |
259} 260 261/* 262 * Route a PCI interrupt 263 * 264 * XXX we don't do anything "right" with the function number in the PIR table 265 * (because the consumer isn't currently passing it in). We don't care 266 * anyway, due to the way PCI interrupts are assigned. 267 */ 268int 269pci_cfgintr(int bus, int device, int pin) 270{ | 263} 264 265/* 266 * Route a PCI interrupt 267 * 268 * XXX we don't do anything "right" with the function number in the PIR table 269 * (because the consumer isn't currently passing it in). We don't care 270 * anyway, due to the way PCI interrupts are assigned. 271 */ 272int 273pci_cfgintr(int bus, int device, int pin) 274{ |
271 struct PIR_entry *pe; 272 int i, irq; 273 struct bios_regs args; 274 u_int16_t v; 275 int already = 0; | 275 struct PIR_entry *pe; 276 int i, irq; 277 struct bios_regs args; 278 u_int16_t v; 279 int already = 0; |
276 | 280 |
277 v = pcibios_get_version(); 278 if (v < 0x0210) { 279 PRVERB(( 280 "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n", 281 (v & 0xff00) >> 8, v & 0xff)); 282 return (255); 283 } 284 if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || 285 (pin < 1) || (pin > 4)) 286 return(255); | 281 v = pcibios_get_version(); 282 if (v < 0x0210) { 283 PRVERB(( 284 "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n", 285 (v & 0xff00) >> 8, v & 0xff)); 286 return (PCI_INVALID_IRQ); 287 } 288 if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) || 289 (pin < 1) || (pin > 4)) 290 return(PCI_INVALID_IRQ); |
287 | 291 |
288 /* 289 * Scan the entry table for a contender 290 */ 291 for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, pe++) { 292 if ((bus != pe->pe_bus) || (device != pe->pe_device)) 293 continue; 294 295 irq = pci_cfgintr_linked(pe, pin); 296 if (irq == 255) 297 irq = pci_cfgintr_unique(pe, pin); 298 if (irq != 255) 299 already = 1; 300 if (irq == 255) 301 irq = pci_cfgintr_virgin(pe, pin); 302 if (irq == 255) 303 break; 304 | |
305 /* | 292 /* |
306 * Ask the BIOS to route the interrupt | 293 * Scan the entry table for a contender |
307 */ | 294 */ |
308 args.eax = PCIBIOS_ROUTE_INTERRUPT; 309 args.ebx = (bus << 8) | (device << 3); 310 args.ecx = (irq << 8) | (0xa + pin - 1); /* pin value is 0xa - 0xd */ 311 if (!already && bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 312 /* 313 * XXX if it fails, we should try to smack the router 314 * hardware directly. 315 * XXX Also, there may be other choices that we can try that 316 * will work. 317 */ 318 PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n")); 319 return(255); | 295 for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; 296 i++, pe++) { 297 if ((bus != pe->pe_bus) || (device != pe->pe_device)) 298 continue; 299 300 irq = pci_cfgintr_linked(pe, pin); 301 if (irq == PCI_INVALID_IRQ) 302 irq = pci_cfgintr_unique(pe, pin); 303 if (irq != PCI_INVALID_IRQ) 304 already = 1; 305 if (irq == PCI_INVALID_IRQ) 306 irq = pci_cfgintr_virgin(pe, pin); 307 if (irq == PCI_INVALID_IRQ) 308 break; 309 310 /* 311 * Ask the BIOS to route the interrupt 312 */ 313 args.eax = PCIBIOS_ROUTE_INTERRUPT; 314 args.ebx = (bus << 8) | (device << 3); 315 /* pin value is 0xa - 0xd */ 316 args.ecx = (irq << 8) | (0xa + pin - 1); 317 if (!already && 318 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) { 319 /* 320 * XXX if it fails, we should try to smack the router 321 * hardware directly. 322 * XXX Also, there may be other choices that we can 323 * try that will work. 324 */ 325 PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n")); 326 return(PCI_INVALID_IRQ); 327 } 328 printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus, 329 device, 'A' + pin - 1, irq); 330 return(irq); |
320 } | 331 } |
321 printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus, device, 'A' + pin - 1, irq); 322 return(irq); 323 } | |
324 | 332 |
325 PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, device, 'A' + pin - 1)); 326 return(255); | 333 PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, 334 device, 'A' + pin - 1)); 335 return(PCI_INVALID_IRQ); |
327} 328 329/* 330 * Look to see if the routing table claims this pin is uniquely routed. 331 */ 332static int 333pci_cfgintr_unique(struct PIR_entry *pe, int pin) 334{ | 336} 337 338/* 339 * Look to see if the routing table claims this pin is uniquely routed. 340 */ 341static int 342pci_cfgintr_unique(struct PIR_entry *pe, int pin) 343{ |
335 int irq; 336 uint32_t irqmask; | 344 int irq; 345 uint32_t irqmask; |
337 | 346 |
338 irqmask = pe->pe_intpin[pin - 1].irqs; 339 if (irqmask != 0 && powerof2(irqmask)) { 340 irq = ffs(irqmask) - 1; 341 PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); 342 return(irq); 343 } 344 return(255); | 347 irqmask = pe->pe_intpin[pin - 1].irqs; 348 if (irqmask != 0 && powerof2(irqmask)) { 349 irq = ffs(irqmask) - 1; 350 PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); 351 return(irq); 352 } 353 return(PCI_INVALID_IRQ); |
345} 346 347/* 348 * Look for another device which shares the same link byte and 349 * already has a unique IRQ, or which has had one routed already. 350 */ 351static int 352pci_cfgintr_linked(struct PIR_entry *pe, int pin) 353{ | 354} 355 356/* 357 * Look for another device which shares the same link byte and 358 * already has a unique IRQ, or which has had one routed already. 359 */ 360static int 361pci_cfgintr_linked(struct PIR_entry *pe, int pin) 362{ |
354 struct PIR_entry *oe; 355 struct PIR_intpin *pi; 356 int i, j, irq; | 363 struct PIR_entry *oe; 364 struct PIR_intpin *pi; 365 int i, j, irq; |
357 | 366 |
358 /* 359 * Scan table slots. 360 */ 361 for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, oe++) { | 367 /* 368 * Scan table slots. 369 */ 370 for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; 371 i++, oe++) { 372 /* scan interrupt pins */ 373 for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) { |
362 | 374 |
363 /* scan interrupt pins */ 364 for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) { | 375 /* don't look at the entry we're trying to match */ 376 if ((pe == oe) && (i == (pin - 1))) 377 continue; 378 /* compare link bytes */ 379 if (pi->link != pe->pe_intpin[pin - 1].link) 380 continue; 381 /* link destination mapped to a unique interrupt? */ 382 if (pi->irqs != 0 && powerof2(pi->irqs)) { 383 irq = ffs(pi->irqs) - 1; 384 PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", 385 pi->link, irq)); 386 return(irq); 387 } |
365 | 388 |
366 /* don't look at the entry we're trying to match with */ 367 if ((pe == oe) && (i == (pin - 1))) 368 continue; 369 370 /* compare link bytes */ 371 if (pi->link != pe->pe_intpin[pin - 1].link) 372 continue; 373 374 /* link destination mapped to a unique interrupt? */ 375 if (pi->irqs != 0 && powerof2(pi->irqs)) { 376 irq = ffs(pi->irqs) - 1; 377 PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", 378 pi->link, irq)); 379 return(irq); 380 } 381 382 /* look for the real PCI device that matches this table entry */ 383 if ((irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, j, pin)) != 255) 384 return(irq); | 389 /* 390 * look for the real PCI device that matches this 391 * table entry 392 */ 393 irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, 394 j, pin); 395 if (irq != PCI_INVALID_IRQ) 396 return(irq); 397 } |
385 } | 398 } |
386 } 387 return(255); | 399 return(PCI_INVALID_IRQ); |
388} 389 390/* 391 * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and 392 * see if it has already been assigned an interrupt. 393 */ 394static int 395pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin) 396{ | 400} 401 402/* 403 * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and 404 * see if it has already been assigned an interrupt. 405 */ 406static int 407pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin) 408{ |
397 devclass_t pci_devclass; 398 device_t *pci_devices; 399 int pci_count; 400 device_t *pci_children; 401 int pci_childcount; 402 device_t *busp, *childp; 403 int i, j, irq; | 409 devclass_t pci_devclass; 410 device_t *pci_devices; 411 int pci_count; 412 device_t *pci_children; 413 int pci_childcount; 414 device_t *busp, *childp; 415 int i, j, irq; |
404 | 416 |
405 /* 406 * Find all the PCI busses. 407 */ 408 pci_count = 0; 409 if ((pci_devclass = devclass_find("pci")) != NULL) 410 devclass_get_devices(pci_devclass, &pci_devices, &pci_count); | 417 /* 418 * Find all the PCI busses. 419 */ 420 pci_count = 0; 421 if ((pci_devclass = devclass_find("pci")) != NULL) 422 devclass_get_devices(pci_devclass, &pci_devices, &pci_count); |
411 | 423 |
412 /* 413 * Scan all the PCI busses/devices looking for this one. 414 */ 415 irq = 255; 416 for (i = 0, busp = pci_devices; (i < pci_count) && (irq == 255); i++, busp++) { 417 pci_childcount = 0; 418 device_get_children(*busp, &pci_children, &pci_childcount); | 424 /* 425 * Scan all the PCI busses/devices looking for this one. 426 */ 427 irq = PCI_INVALID_IRQ; 428 for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ); 429 i++, busp++) { 430 pci_childcount = 0; 431 device_get_children(*busp, &pci_children, &pci_childcount); |
419 | 432 |
420 for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) { 421 if ((pci_get_bus(*childp) == bus) && 422 (pci_get_slot(*childp) == device) && 423 (pci_get_intpin(*childp) == matchpin)) { 424 irq = pci_i386_map_intline(pci_get_irq(*childp)); 425 if (irq != 255) 426 PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", 427 pe->pe_intpin[pin - 1].link, irq, 428 pci_get_bus(*childp), pci_get_slot(*childp), pci_get_function(*childp))); 429 break; 430 } | 433 for (j = 0, childp = pci_children; j < pci_childcount; j++, 434 childp++) { 435 if ((pci_get_bus(*childp) == bus) && 436 (pci_get_slot(*childp) == device) && 437 (pci_get_intpin(*childp) == matchpin)) { 438 irq = pci_i386_map_intline(pci_get_irq(*childp)); 439 if (irq != PCI_INVALID_IRQ) 440 PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", 441 pe->pe_intpin[pin - 1].link, irq, 442 pci_get_bus(*childp), 443 pci_get_slot(*childp), 444 pci_get_function(*childp))); 445 break; 446 } 447 } 448 if (pci_children != NULL) 449 free(pci_children, M_TEMP); |
431 } | 450 } |
432 if (pci_children != NULL) 433 free(pci_children, M_TEMP); 434 } 435 if (pci_devices != NULL) 436 free(pci_devices, M_TEMP); 437 return(irq); | 451 if (pci_devices != NULL) 452 free(pci_devices, M_TEMP); 453 return(irq); |
438} 439 440/* 441 * Pick a suitable IRQ from those listed as routable to this device. 442 */ 443static int 444pci_cfgintr_virgin(struct PIR_entry *pe, int pin) 445{ | 454} 455 456/* 457 * Pick a suitable IRQ from those listed as routable to this device. 458 */ 459static int 460pci_cfgintr_virgin(struct PIR_entry *pe, int pin) 461{ |
446 int irq, ibit; | 462 int irq, ibit; |
447 | 463 |
448 /* first scan the set of PCI-only interrupts and see if any of these are routable */ 449 for (irq = 0; irq < 16; irq++) { 450 ibit = (1 << irq); | 464 /* 465 * first scan the set of PCI-only interrupts and see if any of these 466 * are routable 467 */ 468 for (irq = 0; irq < 16; irq++) { 469 ibit = (1 << irq); |
451 | 470 |
452 /* can we use this interrupt? */ 453 if ((pci_route_table->pt_header.ph_pci_irqs & ibit) && 454 (pe->pe_intpin[pin - 1].irqs & ibit)) { 455 PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq)); 456 return(irq); | 471 /* can we use this interrupt? */ 472 if ((pci_route_table->pt_header.ph_pci_irqs & ibit) && 473 (pe->pe_intpin[pin - 1].irqs & ibit)) { 474 PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq)); 475 return(irq); 476 } |
457 } | 477 } |
458 } | |
459 | 478 |
460 /* life is tough, so just pick an interrupt */ 461 for (irq = 0; irq < 16; irq++) { 462 ibit = (1 << irq); 463 464 if (pe->pe_intpin[pin - 1].irqs & ibit) { 465 PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq)); 466 return(irq); | 479 /* life is tough, so just pick an interrupt */ 480 for (irq = 0; irq < 16; irq++) { 481 ibit = (1 << irq); 482 if (pe->pe_intpin[pin - 1].irqs & ibit) { 483 PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq)); 484 return(irq); 485 } |
467 } | 486 } |
468 } 469 return(255); | 487 return(PCI_INVALID_IRQ); |
470} 471 472 473/* 474 * Config space access using BIOS functions 475 */ 476static int 477pcibios_cfgread(int bus, int slot, int func, int reg, int bytes) 478{ | 488} 489 490 491/* 492 * Config space access using BIOS functions 493 */ 494static int 495pcibios_cfgread(int bus, int slot, int func, int reg, int bytes) 496{ |
479 struct bios_regs args; 480 u_int mask; | 497 struct bios_regs args; 498 u_int mask; |
481 | 499 |
482 switch(bytes) { 483 case 1: 484 args.eax = PCIBIOS_READ_CONFIG_BYTE; 485 mask = 0xff; 486 break; 487 case 2: 488 args.eax = PCIBIOS_READ_CONFIG_WORD; 489 mask = 0xffff; 490 break; 491 case 4: 492 args.eax = PCIBIOS_READ_CONFIG_DWORD; 493 mask = 0xffffffff; 494 break; 495 default: 496 return(-1); 497 } 498 args.ebx = (bus << 8) | (slot << 3) | func; 499 args.edi = reg; 500 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 501 /* check call results? */ 502 return(args.ecx & mask); | 500 switch(bytes) { 501 case 1: 502 args.eax = PCIBIOS_READ_CONFIG_BYTE; 503 mask = 0xff; 504 break; 505 case 2: 506 args.eax = PCIBIOS_READ_CONFIG_WORD; 507 mask = 0xffff; 508 break; 509 case 4: 510 args.eax = PCIBIOS_READ_CONFIG_DWORD; 511 mask = 0xffffffff; 512 break; 513 default: 514 return(-1); 515 } 516 args.ebx = (bus << 8) | (slot << 3) | func; 517 args.edi = reg; 518 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 519 /* check call results? */ 520 return(args.ecx & mask); |
503} 504 505static void 506pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 507{ | 521} 522 523static void 524pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 525{ |
508 struct bios_regs args; | 526 struct bios_regs args; |
509 | 527 |
510 switch(bytes) { 511 case 1: 512 args.eax = PCIBIOS_WRITE_CONFIG_BYTE; 513 break; 514 case 2: 515 args.eax = PCIBIOS_WRITE_CONFIG_WORD; 516 break; 517 case 4: 518 args.eax = PCIBIOS_WRITE_CONFIG_DWORD; 519 break; 520 default: 521 return; 522 } 523 args.ebx = (bus << 8) | (slot << 3) | func; 524 args.ecx = data; 525 args.edi = reg; 526 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); | 528 switch(bytes) { 529 case 1: 530 args.eax = PCIBIOS_WRITE_CONFIG_BYTE; 531 break; 532 case 2: 533 args.eax = PCIBIOS_WRITE_CONFIG_WORD; 534 break; 535 case 4: 536 args.eax = PCIBIOS_WRITE_CONFIG_DWORD; 537 break; 538 default: 539 return; 540 } 541 args.ebx = (bus << 8) | (slot << 3) | func; 542 args.ecx = data; 543 args.edi = reg; 544 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); |
527} 528 529/* 530 * Determine whether there is a PCI BIOS present 531 */ 532static int 533pcibios_cfgopen(void) 534{ | 545} 546 547/* 548 * Determine whether there is a PCI BIOS present 549 */ 550static int 551pcibios_cfgopen(void) 552{ |
535 u_int16_t v = 0; | 553 u_int16_t v = 0; |
536 | 554 |
537 if (PCIbios.entry != 0 && enable_pcibios) { 538 v = pcibios_get_version(); 539 if (v > 0) 540 printf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8, 541 v & 0xff); 542 } 543 return (v > 0); | 555 if (PCIbios.entry != 0 && enable_pcibios) { 556 v = pcibios_get_version(); 557 if (v > 0) 558 printf("pcibios: BIOS version %x.%02x\n", 559 (v & 0xff00) >> 8, v & 0xff); 560 } 561 return (v > 0); |
544} 545 546/* 547 * Configuration space access using direct register operations 548 */ 549 550/* enable configuration space accesses and return data port address */ 551static int 552pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 553{ | 562} 563 564/* 565 * Configuration space access using direct register operations 566 */ 567 568/* enable configuration space accesses and return data port address */ 569static int 570pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 571{ |
554 int dataport = 0; | 572 int dataport = 0; |
555 | 573 |
556 if (bus <= PCI_BUSMAX 557 && slot < devmax 558 && func <= PCI_FUNCMAX 559 && reg <= PCI_REGMAX 560 && bytes != 3 561 && (unsigned) bytes <= 4 562 && (reg & (bytes -1)) == 0) { 563 switch (cfgmech) { 564 case 1: 565 outl(CONF1_ADDR_PORT, (1 << 31) 566 | (bus << 16) | (slot << 11) 567 | (func << 8) | (reg & ~0x03)); 568 dataport = CONF1_DATA_PORT + (reg & 0x03); 569 break; 570 case 2: 571 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 572 outb(CONF2_FORWARD_PORT, bus); 573 dataport = 0xc000 | (slot << 8) | reg; 574 break; | 574 if (bus <= PCI_BUSMAX 575 && slot < devmax 576 && func <= PCI_FUNCMAX 577 && reg <= PCI_REGMAX 578 && bytes != 3 579 && (unsigned) bytes <= 4 580 && (reg & (bytes -1)) == 0) { 581 switch (cfgmech) { 582 case 1: 583 outl(CONF1_ADDR_PORT, (1 << 31) 584 | (bus << 16) | (slot << 11) 585 | (func << 8) | (reg & ~0x03)); 586 dataport = CONF1_DATA_PORT + (reg & 0x03); 587 break; 588 case 2: 589 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 590 outb(CONF2_FORWARD_PORT, bus); 591 dataport = 0xc000 | (slot << 8) | reg; 592 break; 593 } |
575 } | 594 } |
576 } 577 return (dataport); | 595 return (dataport); |
578} 579 580/* disable configuration space accesses */ 581static void 582pci_cfgdisable(void) 583{ | 596} 597 598/* disable configuration space accesses */ 599static void 600pci_cfgdisable(void) 601{ |
584 switch (cfgmech) { 585 case 1: 586 outl(CONF1_ADDR_PORT, 0); 587 break; 588 case 2: 589 outb(CONF2_ENABLE_PORT, 0); 590 outb(CONF2_FORWARD_PORT, 0); 591 break; 592 } | 602 switch (cfgmech) { 603 case 1: 604 outl(CONF1_ADDR_PORT, 0); 605 break; 606 case 2: 607 outb(CONF2_ENABLE_PORT, 0); 608 outb(CONF2_FORWARD_PORT, 0); 609 break; 610 } |
593} 594 595static int 596pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 597{ | 611} 612 613static int 614pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 615{ |
598 int data = -1; 599 int port; | 616 int data = -1; 617 int port; |
600 | 618 |
601 port = pci_cfgenable(bus, slot, func, reg, bytes); | 619 port = pci_cfgenable(bus, slot, func, reg, bytes); |
602 | 620 |
603 if (port != 0) { 604 switch (bytes) { 605 case 1: 606 data = inb(port); 607 break; 608 case 2: 609 data = inw(port); 610 break; 611 case 4: 612 data = inl(port); 613 break; | 621 if (port != 0) { 622 switch (bytes) { 623 case 1: 624 data = inb(port); 625 break; 626 case 2: 627 data = inw(port); 628 break; 629 case 4: 630 data = inl(port); 631 break; 632 } 633 pci_cfgdisable(); |
614 } | 634 } |
615 pci_cfgdisable(); 616 } 617 return (data); | 635 return (data); |
618} 619 620static void 621pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 622{ | 636} 637 638static void 639pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 640{ |
623 int port; | 641 int port; |
624 | 642 |
625 port = pci_cfgenable(bus, slot, func, reg, bytes); 626 if (port != 0) { 627 switch (bytes) { 628 case 1: 629 outb(port, data); 630 break; 631 case 2: 632 outw(port, data); 633 break; 634 case 4: 635 outl(port, data); 636 break; | 643 port = pci_cfgenable(bus, slot, func, reg, bytes); 644 if (port != 0) { 645 switch (bytes) { 646 case 1: 647 outb(port, data); 648 break; 649 case 2: 650 outw(port, data); 651 break; 652 case 4: 653 outl(port, data); 654 break; 655 } 656 pci_cfgdisable(); |
637 } | 657 } |
638 pci_cfgdisable(); 639 } | |
640} 641 642/* check whether the configuration mechanism has been correctly identified */ 643static int 644pci_cfgcheck(int maxdev) 645{ | 658} 659 660/* check whether the configuration mechanism has been correctly identified */ 661static int 662pci_cfgcheck(int maxdev) 663{ |
646 u_char device; | 664 u_char device; |
647 | 665 |
648 if (bootverbose) 649 printf("pci_cfgcheck:\tdevice "); 650 651 for (device = 0; device < maxdev; device++) { 652 unsigned id, class, header; | |
653 if (bootverbose) | 666 if (bootverbose) |
654 printf("%d ", device); | 667 printf("pci_cfgcheck:\tdevice "); |
655 | 668 |
656 id = inl(pci_cfgenable(0, device, 0, 0, 4)); 657 if (id == 0 || id == -1) 658 continue; | 669 for (device = 0; device < maxdev; device++) { 670 unsigned id, class, header; 671 if (bootverbose) 672 printf("%d ", device); |
659 | 673 |
660 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 661 if (bootverbose) 662 printf("[class=%06x] ", class); 663 if (class == 0 || (class & 0xf870ff) != 0) 664 continue; | 674 id = inl(pci_cfgenable(0, device, 0, 0, 4)); 675 if (id == 0 || id == -1) 676 continue; |
665 | 677 |
666 header = inb(pci_cfgenable(0, device, 0, 14, 1)); 667 if (bootverbose) 668 printf("[hdr=%02x] ", header); 669 if ((header & 0x7e) != 0) 670 continue; | 678 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 679 if (bootverbose) 680 printf("[class=%06x] ", class); 681 if (class == 0 || (class & 0xf870ff) != 0) 682 continue; |
671 | 683 |
672 if (bootverbose) 673 printf("is there (id=%08x)\n", id); | 684 header = inb(pci_cfgenable(0, device, 0, 14, 1)); 685 if (bootverbose) 686 printf("[hdr=%02x] ", header); 687 if ((header & 0x7e) != 0) 688 continue; |
674 | 689 |
675 pci_cfgdisable(); 676 return (1); 677 } 678 if (bootverbose) 679 printf("-- nothing found\n"); | 690 if (bootverbose) 691 printf("is there (id=%08x)\n", id); |
680 | 692 |
681 pci_cfgdisable(); 682 return (0); | 693 pci_cfgdisable(); 694 return (1); 695 } 696 if (bootverbose) 697 printf("-- nothing found\n"); 698 699 pci_cfgdisable(); 700 return (0); |
683} 684 685static int 686pcireg_cfgopen(void) 687{ | 701} 702 703static int 704pcireg_cfgopen(void) 705{ |
688 unsigned long mode1res,oldval1; 689 unsigned char mode2res,oldval2; | 706 unsigned long mode1res,oldval1; 707 unsigned char mode2res,oldval2; |
690 | 708 |
691 oldval1 = inl(CONF1_ADDR_PORT); | 709 oldval1 = inl(CONF1_ADDR_PORT); |
692 | 710 |
693 if (bootverbose) { 694 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 695 oldval1); 696 } | 711 if (bootverbose) { 712 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 713 oldval1); 714 } |
697 | 715 |
698 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { | 716 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { |
699 | 717 |
700 cfgmech = 1; 701 devmax = 32; | 718 cfgmech = 1; 719 devmax = 32; |
702 | 720 |
703 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 704 outb(CONF1_ADDR_PORT +3, 0); 705 mode1res = inl(CONF1_ADDR_PORT); 706 outl(CONF1_ADDR_PORT, oldval1); | 721 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 722 outb(CONF1_ADDR_PORT +3, 0); 723 mode1res = inl(CONF1_ADDR_PORT); 724 outl(CONF1_ADDR_PORT, oldval1); |
707 | 725 |
708 if (bootverbose) 709 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 710 mode1res, CONF1_ENABLE_CHK); | 726 if (bootverbose) 727 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 728 mode1res, CONF1_ENABLE_CHK); |
711 | 729 |
712 if (mode1res) { 713 if (pci_cfgcheck(32)) 714 return (cfgmech); 715 } | 730 if (mode1res) { 731 if (pci_cfgcheck(32)) 732 return (cfgmech); 733 } |
716 | 734 |
717 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 718 mode1res = inl(CONF1_ADDR_PORT); 719 outl(CONF1_ADDR_PORT, oldval1); | 735 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 736 mode1res = inl(CONF1_ADDR_PORT); 737 outl(CONF1_ADDR_PORT, oldval1); |
720 | 738 |
721 if (bootverbose) 722 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 723 mode1res, CONF1_ENABLE_CHK1); | 739 if (bootverbose) 740 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 741 mode1res, CONF1_ENABLE_CHK1); |
724 | 742 |
725 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 726 if (pci_cfgcheck(32)) 727 return (cfgmech); | 743 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 744 if (pci_cfgcheck(32)) 745 return (cfgmech); 746 } |
728 } | 747 } |
729 } | |
730 | 748 |
731 oldval2 = inb(CONF2_ENABLE_PORT); | 749 oldval2 = inb(CONF2_ENABLE_PORT); |
732 | 750 |
733 if (bootverbose) { 734 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 735 oldval2); 736 } | 751 if (bootverbose) { 752 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 753 oldval2); 754 } |
737 | 755 |
738 if ((oldval2 & 0xf0) == 0) { | 756 if ((oldval2 & 0xf0) == 0) { |
739 | 757 |
740 cfgmech = 2; 741 devmax = 16; | 758 cfgmech = 2; 759 devmax = 16; |
742 | 760 |
743 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 744 mode2res = inb(CONF2_ENABLE_PORT); 745 outb(CONF2_ENABLE_PORT, oldval2); | 761 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 762 mode2res = inb(CONF2_ENABLE_PORT); 763 outb(CONF2_ENABLE_PORT, oldval2); |
746 | 764 |
747 if (bootverbose) 748 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 749 mode2res, CONF2_ENABLE_CHK); | 765 if (bootverbose) 766 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 767 mode2res, CONF2_ENABLE_CHK); |
750 | 768 |
751 if (mode2res == CONF2_ENABLE_RES) { 752 if (bootverbose) 753 printf("pci_open(2a):\tnow trying mechanism 2\n"); | 769 if (mode2res == CONF2_ENABLE_RES) { 770 if (bootverbose) 771 printf("pci_open(2a):\tnow trying mechanism 2\n"); |
754 | 772 |
755 if (pci_cfgcheck(16)) 756 return (cfgmech); | 773 if (pci_cfgcheck(16)) 774 return (cfgmech); 775 } |
757 } | 776 } |
758 } | |
759 | 777 |
760 cfgmech = 0; 761 devmax = 0; 762 return (cfgmech); | 778 cfgmech = 0; 779 devmax = 0; 780 return (cfgmech); |
763} 764 | 781} 782 |