Annotation of src/sys/arch/x86/pci/pci_machdep.c, Revision 1.19
1.19 ! jmcneill 1: /* $NetBSD: pci_machdep.c,v 1.18 2006/11/16 01:32:39 christos Exp $ */
1.1 fvdl 2:
3: /*-
4: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9: * NASA Ames Research Center.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
42: * Copyright (c) 1994 Charles M. Hannum. All rights reserved.
43: *
44: * Redistribution and use in source and binary forms, with or without
45: * modification, are permitted provided that the following conditions
46: * are met:
47: * 1. Redistributions of source code must retain the above copyright
48: * notice, this list of conditions and the following disclaimer.
49: * 2. Redistributions in binary form must reproduce the above copyright
50: * notice, this list of conditions and the following disclaimer in the
51: * documentation and/or other materials provided with the distribution.
52: * 3. All advertising materials mentioning features or use of this software
53: * must display the following acknowledgement:
54: * This product includes software developed by Charles M. Hannum.
55: * 4. The name of the author may not be used to endorse or promote products
56: * derived from this software without specific prior written permission.
57: *
58: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
59: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
60: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
61: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
62: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
63: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
64: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
65: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
66: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
67: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68: */
69:
70: /*
71: * Machine-specific functions for PCI autoconfiguration.
72: *
73: * On PCs, there are two methods of generating PCI configuration cycles.
74: * We try to detect the appropriate mechanism for this machine and set
75: * up a few function pointers to access the correct method directly.
76: *
77: * The configuration method can be hard-coded in the config file by
78: * using `options PCI_CONF_MODE=N', where `N' is the configuration mode
79: * as defined section 3.6.4.1, `Generating Configuration Cycles'.
80: */
81:
82: #include <sys/cdefs.h>
1.19 ! jmcneill 83: __KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.18 2006/11/16 01:32:39 christos Exp $");
1.1 fvdl 84:
85: #include <sys/types.h>
86: #include <sys/param.h>
87: #include <sys/time.h>
88: #include <sys/systm.h>
89: #include <sys/errno.h>
90: #include <sys/device.h>
91: #include <sys/lock.h>
92:
93: #include <uvm/uvm_extern.h>
94:
95: #include <machine/bus.h>
1.10 yamt 96: #include <machine/bus_private.h>
1.1 fvdl 97:
98: #include <machine/pio.h>
99:
1.3 fvdl 100: #include <dev/isa/isareg.h>
1.1 fvdl 101: #include <dev/isa/isavar.h>
102: #include <dev/pci/pcivar.h>
103: #include <dev/pci/pcireg.h>
104: #include <dev/pci/pcidevs.h>
105:
1.16 christos 106: #include "acpi.h"
1.14 bouyer 107: #include "opt_mpbios.h"
1.16 christos 108: #include "opt_acpi.h"
1.14 bouyer 109:
110: #ifdef MPBIOS
111: #include <machine/mpbiosvar.h>
112: #endif
113:
1.16 christos 114: #if NACPI > 0
1.14 bouyer 115: #include <machine/mpacpi.h>
116: #endif
117:
1.16 christos 118: #include <machine/mpconfig.h>
119:
1.1 fvdl 120: #include "opt_pci_conf_mode.h"
121:
1.19 ! jmcneill 122: #ifdef __i386__
! 123: #include "opt_xbox.h"
! 124: #ifdef XBOX
! 125: #include <machine/xbox.h>
! 126: #endif
! 127: #endif
! 128:
1.1 fvdl 129: int pci_mode = -1;
130:
1.11 sekiya 131: static void pci_bridge_hook(pci_chipset_tag_t, pcitag_t, void *);
132: struct pci_bridge_hook_arg {
133: void (*func)(pci_chipset_tag_t, pcitag_t, void *);
134: void *arg;
135: };
136:
137:
1.1 fvdl 138: struct simplelock pci_conf_slock = SIMPLELOCK_INITIALIZER;
139:
140: #define PCI_CONF_LOCK(s) \
141: do { \
142: (s) = splhigh(); \
143: simple_lock(&pci_conf_slock); \
144: } while (0)
145:
146: #define PCI_CONF_UNLOCK(s) \
147: do { \
148: simple_unlock(&pci_conf_slock); \
149: splx((s)); \
150: } while (0)
151:
152: #define PCI_MODE1_ENABLE 0x80000000UL
153: #define PCI_MODE1_ADDRESS_REG 0x0cf8
154: #define PCI_MODE1_DATA_REG 0x0cfc
155:
156: #define PCI_MODE2_ENABLE_REG 0x0cf8
157: #define PCI_MODE2_FORWARD_REG 0x0cfa
158:
159: #define _m1tag(b, d, f) \
160: (PCI_MODE1_ENABLE | ((b) << 16) | ((d) << 11) | ((f) << 8))
161: #define _qe(bus, dev, fcn, vend, prod) \
162: {_m1tag(bus, dev, fcn), PCI_ID_CODE(vend, prod)}
163: struct {
164: u_int32_t tag;
165: pcireg_t id;
166: } pcim1_quirk_tbl[] = {
167: _qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX1),
168: /* XXX Triflex2 not tested */
169: _qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX2),
170: _qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX4),
171: /* Triton needed for Connectix Virtual PC */
172: _qe(0, 0, 0, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82437FX),
173: /* Connectix Virtual PC 5 has a 440BX */
174: _qe(0, 0, 0, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82443BX_NOAGP),
1.15 soren 175: /* Parallels Desktop for Mac */
176: _qe(0, 2, 0, PCI_VENDOR_PARALLELS, PCI_PRODUCT_PARALLELS_VIDEO),
177: _qe(0, 3, 0, PCI_VENDOR_PARALLELS, PCI_PRODUCT_PARALLELS_TOOLS),
1.12 christos 178: /* SIS 741 */
179: _qe(0, 0, 0, PCI_VENDOR_SIS, PCI_PRODUCT_SIS_741),
1.1 fvdl 180: {0, 0xffffffff} /* patchable */
181: };
182: #undef _m1tag
183: #undef _id
184: #undef _qe
185:
186: /*
187: * PCI doesn't have any special needs; just use the generic versions
188: * of these functions.
189: */
190: struct x86_bus_dma_tag pci_bus_dma_tag = {
1.3 fvdl 191: #if defined(_LP64) || defined(PAE)
192: PCI32_DMA_BOUNCE_THRESHOLD, /* bounce_thresh */
193: ISA_DMA_BOUNCE_THRESHOLD, /* bounce_alloclo */
194: PCI32_DMA_BOUNCE_THRESHOLD, /* bounce_allochi */
195: #else
196: 0,
197: 0,
198: 0,
199: #endif
200: NULL, /* _may_bounce */
1.1 fvdl 201: _bus_dmamap_create,
202: _bus_dmamap_destroy,
203: _bus_dmamap_load,
204: _bus_dmamap_load_mbuf,
205: _bus_dmamap_load_uio,
206: _bus_dmamap_load_raw,
207: _bus_dmamap_unload,
1.3 fvdl 208: #if defined(_LP64) || defined(PAE)
209: _bus_dmamap_sync,
210: #else
211: NULL,
212: #endif
1.1 fvdl 213: _bus_dmamem_alloc,
214: _bus_dmamem_free,
215: _bus_dmamem_map,
216: _bus_dmamem_unmap,
217: _bus_dmamem_mmap,
218: };
1.5 fvdl 219:
220: #ifdef _LP64
221: struct x86_bus_dma_tag pci_bus_dma64_tag = {
222: 0,
223: 0,
224: 0,
225: NULL, /* _may_bounce */
226: _bus_dmamap_create,
227: _bus_dmamap_destroy,
228: _bus_dmamap_load,
229: _bus_dmamap_load_mbuf,
230: _bus_dmamap_load_uio,
231: _bus_dmamap_load_raw,
232: _bus_dmamap_unload,
233: NULL,
234: _bus_dmamem_alloc,
235: _bus_dmamem_free,
236: _bus_dmamem_map,
237: _bus_dmamem_unmap,
238: _bus_dmamem_mmap,
239: };
240: #endif
1.1 fvdl 241:
242: void
1.18 christos 243: pci_attach_hook(struct device *parent, struct device *self,
1.17 christos 244: struct pcibus_attach_args *pba)
1.1 fvdl 245: {
246:
247: if (pba->pba_bus == 0)
248: printf(": configuration mode %d", pci_mode);
1.4 fvdl 249: #ifdef MPBIOS
250: mpbios_pci_attach_hook(parent, self, pba);
251: #endif
1.16 christos 252: #if NACPI > 0
1.4 fvdl 253: mpacpi_pci_attach_hook(parent, self, pba);
254: #endif
1.1 fvdl 255: }
256:
257: int
1.18 christos 258: pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
1.1 fvdl 259: {
260:
1.19 ! jmcneill 261: #if defined(__i386__) && defined(XBOX)
! 262: /*
! 263: * Scanning above the first device is fatal on the Microsoft Xbox.
! 264: * If busno=1, only allow for one device.
! 265: */
! 266: if (arch_i386_is_xbox) {
! 267: if (busno == 1)
! 268: return 1;
! 269: else if (busno > 1)
! 270: return 0;
! 271: }
! 272: #endif
! 273:
1.1 fvdl 274: /*
275: * Bus number is irrelevant. If Configuration Mechanism 2 is in
276: * use, can only have devices 0-15 on any bus. If Configuration
277: * Mechanism 1 is in use, can have devices 0-32 (i.e. the `normal'
278: * range).
279: */
280: if (pci_mode == 2)
281: return (16);
282: else
283: return (32);
284: }
285:
286: pcitag_t
1.18 christos 287: pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
1.1 fvdl 288: {
289: pcitag_t tag;
290:
291: #ifndef PCI_CONF_MODE
292: switch (pci_mode) {
293: case 1:
294: goto mode1;
295: case 2:
296: goto mode2;
297: default:
298: panic("pci_make_tag: mode not configured");
299: }
300: #endif
301:
302: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1)
303: #ifndef PCI_CONF_MODE
304: mode1:
305: #endif
306: if (bus >= 256 || device >= 32 || function >= 8)
307: panic("pci_make_tag: bad request");
308:
309: tag.mode1 = PCI_MODE1_ENABLE |
310: (bus << 16) | (device << 11) | (function << 8);
311: return tag;
312: #endif
313:
314: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2)
315: #ifndef PCI_CONF_MODE
316: mode2:
317: #endif
318: if (bus >= 256 || device >= 16 || function >= 8)
319: panic("pci_make_tag: bad request");
320:
321: tag.mode2.port = 0xc000 | (device << 8);
322: tag.mode2.enable = 0xf0 | (function << 1);
323: tag.mode2.forward = bus;
324: return tag;
325: #endif
326: }
327:
328: void
1.18 christos 329: pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag,
1.17 christos 330: int *bp, int *dp, int *fp)
1.1 fvdl 331: {
332:
333: #ifndef PCI_CONF_MODE
334: switch (pci_mode) {
335: case 1:
336: goto mode1;
337: case 2:
338: goto mode2;
339: default:
340: panic("pci_decompose_tag: mode not configured");
341: }
342: #endif
343:
344: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1)
345: #ifndef PCI_CONF_MODE
346: mode1:
347: #endif
348: if (bp != NULL)
349: *bp = (tag.mode1 >> 16) & 0xff;
350: if (dp != NULL)
351: *dp = (tag.mode1 >> 11) & 0x1f;
352: if (fp != NULL)
353: *fp = (tag.mode1 >> 8) & 0x7;
354: return;
355: #endif
356:
357: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2)
358: #ifndef PCI_CONF_MODE
359: mode2:
360: #endif
361: if (bp != NULL)
362: *bp = tag.mode2.forward & 0xff;
363: if (dp != NULL)
364: *dp = (tag.mode2.port >> 8) & 0xf;
365: if (fp != NULL)
366: *fp = (tag.mode2.enable >> 1) & 0x7;
367: #endif
368: }
369:
370: pcireg_t
1.18 christos 371: pci_conf_read( pci_chipset_tag_t pc, pcitag_t tag,
372: int reg)
1.1 fvdl 373: {
374: pcireg_t data;
375: int s;
376:
377: #ifndef PCI_CONF_MODE
378: switch (pci_mode) {
379: case 1:
380: goto mode1;
381: case 2:
382: goto mode2;
383: default:
384: panic("pci_conf_read: mode not configured");
385: }
386: #endif
387:
388: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1)
389: #ifndef PCI_CONF_MODE
390: mode1:
391: #endif
392: PCI_CONF_LOCK(s);
393: outl(PCI_MODE1_ADDRESS_REG, tag.mode1 | reg);
394: data = inl(PCI_MODE1_DATA_REG);
395: outl(PCI_MODE1_ADDRESS_REG, 0);
396: PCI_CONF_UNLOCK(s);
397: return data;
398: #endif
399:
400: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2)
401: #ifndef PCI_CONF_MODE
402: mode2:
403: #endif
404: PCI_CONF_LOCK(s);
405: outb(PCI_MODE2_ENABLE_REG, tag.mode2.enable);
406: outb(PCI_MODE2_FORWARD_REG, tag.mode2.forward);
407: data = inl(tag.mode2.port | reg);
408: outb(PCI_MODE2_ENABLE_REG, 0);
409: PCI_CONF_UNLOCK(s);
410: return data;
411: #endif
412: }
413:
414: void
1.18 christos 415: pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg,
1.17 christos 416: pcireg_t data)
1.1 fvdl 417: {
418: int s;
419:
420: #ifndef PCI_CONF_MODE
421: switch (pci_mode) {
422: case 1:
423: goto mode1;
424: case 2:
425: goto mode2;
426: default:
427: panic("pci_conf_write: mode not configured");
428: }
429: #endif
430:
431: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1)
432: #ifndef PCI_CONF_MODE
433: mode1:
434: #endif
435: PCI_CONF_LOCK(s);
436: outl(PCI_MODE1_ADDRESS_REG, tag.mode1 | reg);
437: outl(PCI_MODE1_DATA_REG, data);
438: outl(PCI_MODE1_ADDRESS_REG, 0);
439: PCI_CONF_UNLOCK(s);
440: return;
441: #endif
442:
443: #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2)
444: #ifndef PCI_CONF_MODE
445: mode2:
446: #endif
447: PCI_CONF_LOCK(s);
448: outb(PCI_MODE2_ENABLE_REG, tag.mode2.enable);
449: outb(PCI_MODE2_FORWARD_REG, tag.mode2.forward);
450: outl(tag.mode2.port | reg, data);
451: outb(PCI_MODE2_ENABLE_REG, 0);
452: PCI_CONF_UNLOCK(s);
453: #endif
454: }
455:
456: int
457: pci_mode_detect()
458: {
459:
460: #ifdef PCI_CONF_MODE
461: #if (PCI_CONF_MODE == 1) || (PCI_CONF_MODE == 2)
462: return (pci_mode = PCI_CONF_MODE);
463: #else
464: #error Invalid PCI configuration mode.
465: #endif
466: #else
467: u_int32_t sav, val;
468: int i;
469: pcireg_t idreg;
470:
471: if (pci_mode != -1)
472: return pci_mode;
473:
474: /*
475: * We try to divine which configuration mode the host bridge wants.
476: */
477:
478: sav = inl(PCI_MODE1_ADDRESS_REG);
479:
480: pci_mode = 1; /* assume this for now */
481: /*
482: * catch some known buggy implementations of mode 1
483: */
484: for (i = 0; i < sizeof(pcim1_quirk_tbl) / sizeof(pcim1_quirk_tbl[0]);
485: i++) {
486: pcitag_t t;
487:
488: if (!pcim1_quirk_tbl[i].tag)
489: break;
490: t.mode1 = pcim1_quirk_tbl[i].tag;
491: idreg = pci_conf_read(0, t, PCI_ID_REG); /* needs "pci_mode" */
492: if (idreg == pcim1_quirk_tbl[i].id) {
493: #ifdef DEBUG
494: printf("known mode 1 PCI chipset (%08x)\n",
495: idreg);
496: #endif
497: return (pci_mode);
498: }
499: }
500:
501: /*
502: * Strong check for standard compliant mode 1:
503: * 1. bit 31 ("enable") can be set
504: * 2. byte/word access does not affect register
505: */
506: outl(PCI_MODE1_ADDRESS_REG, PCI_MODE1_ENABLE);
507: outb(PCI_MODE1_ADDRESS_REG + 3, 0);
508: outw(PCI_MODE1_ADDRESS_REG + 2, 0);
509: val = inl(PCI_MODE1_ADDRESS_REG);
510: if ((val & 0x80fffffc) != PCI_MODE1_ENABLE) {
511: #ifdef DEBUG
512: printf("pci_mode_detect: mode 1 enable failed (%x)\n",
513: val);
514: #endif
515: goto not1;
516: }
517: outl(PCI_MODE1_ADDRESS_REG, 0);
518: val = inl(PCI_MODE1_ADDRESS_REG);
519: if ((val & 0x80fffffc) != 0)
520: goto not1;
521: return (pci_mode);
522: not1:
523: outl(PCI_MODE1_ADDRESS_REG, sav);
524:
525: /*
526: * This mode 2 check is quite weak (and known to give false
527: * positives on some Compaq machines).
528: * However, this doesn't matter, because this is the
529: * last test, and simply no PCI devices will be found if
530: * this happens.
531: */
532: outb(PCI_MODE2_ENABLE_REG, 0);
533: outb(PCI_MODE2_FORWARD_REG, 0);
534: if (inb(PCI_MODE2_ENABLE_REG) != 0 ||
535: inb(PCI_MODE2_FORWARD_REG) != 0)
536: goto not2;
537: return (pci_mode = 2);
538: not2:
539:
540: return (pci_mode = 0);
541: #endif
542: }
543:
544: /*
545: * Determine which flags should be passed to the primary PCI bus's
546: * autoconfiguration node. We use this to detect broken chipsets
547: * which cannot safely use memory-mapped device access.
548: */
549: int
550: pci_bus_flags()
551: {
552: int rval = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED |
553: PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY;
554: int device, maxndevs;
555: pcitag_t tag;
556: pcireg_t id;
557:
558: maxndevs = pci_bus_maxdevs(NULL, 0);
559:
560: for (device = 0; device < maxndevs; device++) {
561: tag = pci_make_tag(NULL, 0, device, 0);
562: id = pci_conf_read(NULL, tag, PCI_ID_REG);
563:
564: /* Invalid vendor ID value? */
565: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
566: continue;
567: /* XXX Not invalid, but we've done this ~forever. */
568: if (PCI_VENDOR(id) == 0)
569: continue;
570:
571: switch (PCI_VENDOR(id)) {
572: case PCI_VENDOR_SIS:
573: switch (PCI_PRODUCT(id)) {
574: case PCI_PRODUCT_SIS_85C496:
575: goto disable_mem;
576: }
577: break;
578: }
579: }
580:
581: return (rval);
582:
583: disable_mem:
584: printf("Warning: broken PCI-Host bridge detected; "
585: "disabling memory-mapped access\n");
586: rval &= ~(PCI_FLAGS_MEM_ENABLED|PCI_FLAGS_MRL_OKAY|PCI_FLAGS_MRM_OKAY|
587: PCI_FLAGS_MWI_OKAY);
588: return (rval);
589: }
1.11 sekiya 590:
591: void
592: pci_device_foreach(pci_chipset_tag_t pc, int maxbus,
593: void (*func)(pci_chipset_tag_t, pcitag_t, void *), void *context)
594: {
595: pci_device_foreach_min(pc, 0, maxbus, func, context);
596: }
597:
598: void
599: pci_device_foreach_min(pci_chipset_tag_t pc, int minbus, int maxbus,
600: void (*func)(pci_chipset_tag_t, pcitag_t, void *), void *context)
601: {
602: const struct pci_quirkdata *qd;
603: int bus, device, function, maxdevs, nfuncs;
604: pcireg_t id, bhlcr;
605: pcitag_t tag;
606:
607: for (bus = minbus; bus <= maxbus; bus++) {
608: maxdevs = pci_bus_maxdevs(pc, bus);
609: for (device = 0; device < maxdevs; device++) {
610: tag = pci_make_tag(pc, bus, device, 0);
611: id = pci_conf_read(pc, tag, PCI_ID_REG);
612:
613: /* Invalid vendor ID value? */
614: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
615: continue;
616: /* XXX Not invalid, but we've done this ~forever. */
617: if (PCI_VENDOR(id) == 0)
618: continue;
619:
620: qd = pci_lookup_quirkdata(PCI_VENDOR(id),
621: PCI_PRODUCT(id));
622:
623: bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
624: if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
625: (qd != NULL &&
626: (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
627: nfuncs = 8;
628: else
629: nfuncs = 1;
630:
631: for (function = 0; function < nfuncs; function++) {
632: tag = pci_make_tag(pc, bus, device, function);
633: id = pci_conf_read(pc, tag, PCI_ID_REG);
634:
635: /* Invalid vendor ID value? */
636: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
637: continue;
638: /*
639: * XXX Not invalid, but we've done this
640: * ~forever.
641: */
642: if (PCI_VENDOR(id) == 0)
643: continue;
644: (*func)(pc, tag, context);
645: }
646: }
647: }
648: }
649:
650: void
651: pci_bridge_foreach(pci_chipset_tag_t pc, int minbus, int maxbus,
652: void (*func)(pci_chipset_tag_t, pcitag_t, void *), void *ctx)
653: {
654: struct pci_bridge_hook_arg bridge_hook;
655:
656: bridge_hook.func = func;
657: bridge_hook.arg = ctx;
658:
659: pci_device_foreach_min(pc, minbus, maxbus, pci_bridge_hook,
660: &bridge_hook);
661: }
662:
663: static void
664: pci_bridge_hook(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
665: {
666: struct pci_bridge_hook_arg *bridge_hook = (void *)ctx;
667: pcireg_t reg;
668:
669: reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
670: if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
671: (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
672: PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
673: (*bridge_hook->func)(pc, tag, bridge_hook->arg);
674: }
675: }
CVSweb <webmaster@jp.NetBSD.org>