PCI layer diff, pciattach() changes.

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

PCI layer diff, pciattach() changes.

Brad Smith-14
Among other things this is a start towards adding CardBus support for
sparc64. In the process it removes some ugly MD code hackery in the PCI
layer. This affects all PCI-based architectures so this could use some
testing on a number of architectures, that means if you have any of the
following... alpha, amd64, cats, hppa, i386, macppc, sgi or sparc64.
With more emphasis on testing sparc64, but please test this if you
you have any of the other architectures too.


rev 1.86

make the "generic" PCI bus enumeration code the standard case which
gets used if nothing else is defined in MD headers,
introduce a "PCI_MACHDEP_ENUMERATE_BUS" CPP definition which can
be used by MD headers (just 1 port atm) to plug in special code

rev 1.62

* Implement a machine-dependent pci_enumerate_bus() for sparc64 which
  uses OFW device nodes to enumerate the bus.  When a PCI bus that is
  behind a bridge is attached, pci_attach_hook() allocates a new PCI
  chipset tag for the new bus and sets it's "curnode" to the OFW node
  of the bridge.  This is used as a starting point when enumerating
  that bus.  Root busses get the OFW node of the host bridge (psycho).

rev 1.59

Split the code that enumerates the PCI bus and that actually probes
for a device into two functions:

* pci_probe_device() actually probes/attaches the device specified
  by the provide pcitag_t.

* pci_enumerate_bus() enumerates the bus, and calls pci_probe_device()
  for each device on the bus.  A pci_enumerate_bus_generic() is provided
  which implements the old method of doing this: If something found at
  dev0/func0, determine number of functions and probe each one.

From NetBSD


Index: arch/sparc64/dev/pci_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/pci_machdep.c,v
retrieving revision 1.21
diff -u -p -r1.21 pci_machdep.c
--- arch/sparc64/dev/pci_machdep.c 6 Jan 2006 20:30:09 -0000 1.21
+++ arch/sparc64/dev/pci_machdep.c 17 Mar 2006 00:39:01 -0000
@@ -37,7 +37,6 @@
 #define SPDB_CONF 0x01
 #define SPDB_INTR 0x04
 #define SPDB_INTMAP 0x08
-#define SPDB_INTFIX 0x10
 #define SPDB_PROBE 0x20
 int sparc_pci_debug = 0x0;
 #define DPRINTF(l, s) do { if (sparc_pci_debug & l) printf s; } while (0)
@@ -73,6 +72,21 @@ struct sparc_pci_chipset _sparc_pci_chip
  NULL,
 };
 
+static pcitag_t
+ofpci_make_tag(pci_chipset_tag_t pc, int node, int b, int d, int f)
+{
+ pcitag_t tag;
+
+ tag = PCITAG_CREATE(node, b, d, f);
+
+ /* Enable all the different spaces for this device */
+ pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
+ PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE|
+ PCI_COMMAND_IO_ENABLE);
+
+ return (tag);
+}
+
 /*
  * functions provided to the MI code.
  */
@@ -95,124 +109,6 @@ pci_bus_maxdevs(pc, busno)
  return 32;
 }
 
-#ifdef __PCI_BUS_DEVORDER
-int
-pci_bus_devorder(pc, busno, devs)
- pci_chipset_tag_t pc;
- int busno;
- char *devs;
-{
- struct ofw_pci_register reg;
- int node, len, device, i = 0;
- u_int32_t done = 0;
-#ifdef DEBUG
- char name[80];
-#endif
-
- node = pc->curnode;
-#ifdef DEBUG
- if (sparc_pci_debug & SPDB_PROBE) {
- OF_getprop(node, "name", &name, sizeof(name));
- printf("pci_bus_devorder: curnode %x %s\n", node, name);
- }
-#endif
- /*
- * Initially, curnode is the root of the pci tree.  As we
- * attach bridges, curnode should be set to that of the bridge.
- */
- for (node = OF_child(node); node; node = OF_peer(node)) {
- len = OF_getproplen(node, "reg");
- if (len < sizeof(reg))
- continue;
- if (OF_getprop(node, "reg", (void *)&reg, sizeof(reg)) != len)
- panic("pci_probe_bus: OF_getprop len botch");
-
- device = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi);
-
- if (done & (1 << device))
- continue;
-
- devs[i++] = device;
- done |= 1 << device;
-#ifdef DEBUG
- if (sparc_pci_debug & SPDB_PROBE) {
- OF_getprop(node, "name", &name, sizeof(name));
- printf("pci_bus_devorder: adding %x %s\n", node, name);
- }
-#endif
- if (i == 32)
- break;
- }
- if (i < 32)
- devs[i] = -1;
-
- return i;
-}
-#endif
-
-#ifdef __PCI_DEV_FUNCORDER
-int
-pci_dev_funcorder(pc, busno, device, funcs)
- pci_chipset_tag_t pc;
- int busno;
- int device;
- char *funcs;
-{
- struct ofw_pci_register reg;
- int node, len, function, i = 0;
- u_int8_t done = 0;
-#ifdef DEBUG
- char name[80];
-#endif
-
- node = pc->curnode;
-#ifdef DEBUG
- if (sparc_pci_debug & SPDB_PROBE) {
- OF_getprop(node, "name", &name, sizeof(name));
- printf("pci_bus_funcorder: curnode %x %s\n", node, name);
- }
-#endif
- /*
- * Functions are siblings.  Presumably we're only called when the
- * first instance of this device is detected, so we should be able to
- * get to all the other functions with OF_peer().  But there seems
- * some issues with this scheme, so we always go to the first node on
- * this bus segment for a scan.  
- */
- for (node = OF_child(OF_parent(node)); node; node = OF_peer(node)) {
- len = OF_getproplen(node, "reg");
- if (len < sizeof(reg))
- continue;
- if (OF_getprop(node, "reg", (void *)&reg, sizeof(reg)) != len)
- panic("pci_probe_bus: OF_getprop len botch");
-
- if (device != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi))
- continue;
-
-
- function = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi);
-
- if (done & (1 << function))
- continue;
-
- funcs[i++] = function;
- done |= 1 << function;
-#ifdef DEBUG
- if (sparc_pci_debug & SPDB_PROBE) {
- OF_getprop(node, "name", &name, sizeof(name));
- printf("pci_bus_funcorder: adding %x %s\n", node, name);
- }
-#endif
- if (i == 8)
- break;
- }
- if (i < 8)
- funcs[i] = -1;
-
- return i;
-}
-#endif
-
 pcitag_t
 pci_make_tag(pc, b, d, f)
  pci_chipset_tag_t pc;
@@ -323,21 +219,8 @@ pci_make_tag(pc, b, d, f)
  continue;
 
  /* Got a match */
- tag = PCITAG_CREATE(node, b, d, f);
-
- /*
- * Record the node.  This has two effects:
- *
- * 1) We don't have to search as far.
- * 2) pci_bus_devorder will scan the right bus.
- */
- pc->curnode = node;
+ tag = ofpci_make_tag(pc, node, b, d, f);
 
- /* Enable all the different spaces for this device */
- pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
- PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE|
- PCI_COMMAND_IO_ENABLE);
- DPRINTF(SPDB_PROBE, ("found node %x %s\n", node, name));
  return (tag);
  }
  /* No device found -- return a dead tag */
@@ -357,6 +240,52 @@ pci_decompose_tag(pc, tag, bp, dp, fp)
  *dp = PCITAG_DEV(tag);
  if (fp != NULL)
  *fp = PCITAG_FUN(tag);
+}
+
+int
+sparc64_pci_enumerate_bus(struct pci_softc *sc,
+    int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
+{
+ struct ofw_pci_register reg;
+ pci_chipset_tag_t pc = sc->sc_pc;
+ pcitag_t tag;
+ pcireg_t class;
+ int node, b, d, f, ret;
+ char name[30];
+
+ if (sc->sc_bridgetag)
+ node = PCITAG_NODE(*sc->sc_bridgetag);
+ else
+ node = pc->rootnode;
+
+ for (node = OF_child(node); node != 0 && node != -1;
+     node = OF_peer(node)) {
+ name[0] = name[29] = 0;
+ OF_getprop(node, "name", name, sizeof(name));
+
+ if (OF_getprop(node, "class-code", &class, sizeof(class)) !=
+    sizeof(class))
+ continue;
+ if (OF_getprop(node, "reg", &reg, sizeof(reg)) < sizeof(reg))
+ panic("pci_enumerate_bus: \"%s\" regs too small", name);
+
+ b = OFW_PCI_PHYS_HI_BUS(reg.phys_hi);
+ d = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi);
+ f = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi);
+
+ if (sc->sc_bus != b) {
+ printf("%s: WARNING: incorrect bus # for \"%s\" "
+ "(%d/%d/%d)\n", sc->sc_dev.dv_xname, name, b, d, f);
+ continue;
+ }
+
+ tag = ofpci_make_tag(pc, node, b, d, f);
+ ret = pci_probe_device(sc, tag, match, pap);
+ if (match != NULL && ret != 0)
+ return (ret);
+ }
+
+ return (0);
 }
 
 /* assume we are mapped little-endian/side-effect */
Index: arch/sparc64/dev/psycho.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/psycho.c,v
retrieving revision 1.42
diff -u -p -r1.42 psycho.c
--- arch/sparc64/dev/psycho.c 13 Mar 2006 20:10:49 -0000 1.42
+++ arch/sparc64/dev/psycho.c 17 Mar 2006 00:39:02 -0000
@@ -650,7 +650,6 @@ psycho_alloc_chipset(struct psycho_pbm *
  memcpy(npc, pc, sizeof *pc);
  npc->cookie = pp;
  npc->rootnode = node;
- npc->curnode = node;
 
  return (npc);
 }
Index: arch/sparc64/dev/schizo.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/schizo.c,v
retrieving revision 1.17
diff -u -p -r1.17 schizo.c
--- arch/sparc64/dev/schizo.c 13 Mar 2006 20:10:49 -0000 1.17
+++ arch/sparc64/dev/schizo.c 17 Mar 2006 00:39:02 -0000
@@ -347,7 +347,6 @@ schizo_alloc_chipset(struct schizo_pbm *
  memcpy(npc, pc, sizeof *pc);
  npc->cookie = pbm;
  npc->rootnode = node;
- npc->curnode = node;
  return (npc);
 }
 
Index: arch/sparc64/include/pci_machdep.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/include/pci_machdep.h,v
retrieving revision 1.14
diff -u -p -r1.14 pci_machdep.h
--- arch/sparc64/include/pci_machdep.h 4 Sep 2005 20:40:53 -0000 1.14
+++ arch/sparc64/include/pci_machdep.h 17 Mar 2006 00:39:02 -0000
@@ -33,12 +33,6 @@
 #define _MACHINE_PCI_MACHDEP_H_
 
 /*
- * We want to control both device & function probe order.
- */
-#define __PCI_BUS_DEVORDER
-#define __PCI_DEV_FUNCORDER
-
-/*
  * Forward declarations.
  */
 struct pci_attach_args;
@@ -73,18 +67,11 @@ struct sparc_pci_chipset {
  bus_space_tag_t bustag;
  bus_space_handle_t bushandle;
  int rootnode; /* PCI controller */
- int curnode; /* Current OFW node */
  int (*intr_map)(struct pci_attach_args *, pci_intr_handle_t *);
 };
 
 void pci_attach_hook(struct device *, struct device *,
      struct pcibus_attach_args *);
-#ifdef __PCI_BUS_DEVORDER
-int pci_bus_devorder(pci_chipset_tag_t, int, char *);
-#endif
-#ifdef __PCI_DEV_FUNCORDER
-int pci_dev_funcorder(pci_chipset_tag_t, int, int, char *);
-#endif
 int pci_bus_maxdevs(pci_chipset_tag_t, int);
 pcitag_t pci_make_tag(pci_chipset_tag_t, int, int, int);
 void pci_decompose_tag(pci_chipset_tag_t, pcitag_t, int *, int *,
@@ -97,6 +84,12 @@ const char *pci_intr_string(pci_chipset_
 void *pci_intr_establish(pci_chipset_tag_t, pci_intr_handle_t,
  int, int (*)(void *), void *, char *);
 void pci_intr_disestablish(pci_chipset_tag_t, void *);
+
+int sparc64_pci_enumerate_bus(struct pci_softc *,
+    int (*match)(struct pci_attach_args *),
+    struct pci_attach_args *);
+
+#define PCI_MACHDEP_ENUMERATE_BUS sparc64_pci_enumerate_bus
 
 #define pciide_machdep_compat_intr_establish(a, b, c, d, e) (NULL)
 #define pciide_machdep_compat_intr_disestablish(a, b) do { } while (0)
Index: dev/pci/pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/pci.c,v
retrieving revision 1.40
diff -u -p -r1.40 pci.c
--- dev/pci/pci.c 11 Mar 2006 22:08:07 -0000 1.40
+++ dev/pci/pci.c 17 Mar 2006 00:39:02 -0000
@@ -75,6 +75,13 @@ struct cfdriver pci_cd = {
 int pciprint(void *, const char *);
 int pcisubmatch(struct device *, void *, void *);
 
+#ifdef PCI_MACHDEP_ENUMERATE_BUS
+#define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS
+#else
+int pci_enumerate_bus(struct pci_softc *,
+    int (*)(struct pci_attach_args *), struct pci_attach_args *);
+#endif
+
 /*
  * Important note about PCI-ISA bridges:
  *
@@ -125,7 +132,7 @@ pcimatch(parent, match, aux)
  * XXX check other (hardware?) indicators
  */
 
- return 1;
+ return (1);
 }
 
 void
@@ -134,171 +141,25 @@ pciattach(parent, self, aux)
  void *aux;
 {
  struct pcibus_attach_args *pba = aux;
- bus_space_tag_t iot, memt;
- pci_chipset_tag_t pc;
- int bus, device, maxndevs, function, nfunctions;
  struct pci_softc *sc = (struct pci_softc *)self;
- struct pci_dev *pd;
- struct device *dev;
-#ifdef __PCI_BUS_DEVORDER
- char devs[32];
- int i;
-#endif
-#ifdef __PCI_DEV_FUNCORDER
- char funcs[8];
- int j;
-#endif
 
  pci_attach_hook(parent, self, pba);
- printf("\n");
 
- iot = pba->pba_iot;
- memt = pba->pba_memt;
- pc = pba->pba_pc;
- bus = pba->pba_bus;
- maxndevs = pci_bus_maxdevs(pc, bus);
+ printf("\n");
 
- sc->sc_pc = pba->pba_pc;
  LIST_INIT(&sc->sc_devs);
  sc->sc_powerhook = powerhook_establish(pcipower, sc);
-#ifdef USER_PCICONF
- sc->sc_bus = bus;
-#endif
-
-#ifdef __PCI_BUS_DEVORDER
- pci_bus_devorder(pc, bus, devs);
- for (i = 0; (device = devs[i]) < 32 && device >= 0; i++) {
-#else
- for (device = 0; device < maxndevs; device++) {
-#endif
- pcitag_t tag;
- pcireg_t id, class, intr;
-#ifndef __sparc64__
- pcireg_t bhlcr;
-#endif
- struct pci_attach_args pa;
- int pin;
-
- tag = pci_make_tag(pc, bus, device, 0);
- id = pci_conf_read(pc, tag, PCI_ID_REG);
-
-#ifdef __sparc64__
- pci_dev_funcorder(pc, bus, device, funcs);
- nfunctions = 8;
-
- /* Invalid vendor ID value or 0 (see below for zero)
- * ... of course, if the pci_dev_funcorder found
- *     functions other than zero, we probably want
- *     to attach them.
- */
- if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || PCI_VENDOR(id) == 0)
- if (funcs[0] < 0)
- continue;
-
- for (j = 0; (function = funcs[j]) < nfunctions &&
-    function >= 0; j++) {
-#else
-
- /* Invalid vendor ID value? */
- if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
- continue;
- /* XXX Not invalid, but we've done this ~forever. */
- if (PCI_VENDOR(id) == 0)
- continue;
-
- bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
- nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1;
 
-#ifdef __PCI_DEV_FUNCORDER
- pci_dev_funcorder(pc, bus, device, funcs);
- for (j = 0; (function = funcs[j]) < nfunctions &&
-    function >= 0; j++) {
-#else
- for (function = 0; function < nfunctions; function++) {
-#endif
-#endif
- tag = pci_make_tag(pc, bus, device, function);
- id = pci_conf_read(pc, tag, PCI_ID_REG);
-
- /* Invalid vendor ID value? */
- if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
- continue;
- /* XXX Not invalid, but we've done this ~forever. */
- if (PCI_VENDOR(id) == 0)
- continue;
-
- class = pci_conf_read(pc, tag, PCI_CLASS_REG);
- intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
-
- pa.pa_iot = iot;
- pa.pa_memt = memt;
- pa.pa_dmat = pba->pba_dmat;
- pa.pa_pc = pc;
- pa.pa_device = device;
- pa.pa_function = function;
- pa.pa_bus = bus;
- pa.pa_tag = tag;
- pa.pa_id = id;
- pa.pa_class = class;
-
- /* This is a simplification of the NetBSD code.
-   We don't support turning off I/O or memory
-   on broken hardware. <[hidden email]> */
- pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
-#ifdef __i386__
- /*
- * on i386 we really need to know the device tag
- * and not the pci bridge tag, in intr_map
- * to be able to program the device and the
- * pci interrupt router.
- */
- pa.pa_intrtag = tag;
- pa.pa_intrswiz = 0;
-#else
- if (bus == 0) {
- pa.pa_intrswiz = 0;
- pa.pa_intrtag = tag;
- } else {
- pa.pa_intrswiz = pba->pba_intrswiz + device;
- pa.pa_intrtag = pba->pba_intrtag;
- }
-#endif
- pin = PCI_INTERRUPT_PIN(intr);
- pa.pa_rawintrpin = pin;
- if (pin == PCI_INTERRUPT_PIN_NONE) {
- /* no interrupt */
- pa.pa_intrpin = 0;
- } else {
- /*
- * swizzle it based on the number of
- * busses we're behind and our device
- * number.
- */
- pa.pa_intrpin = /* XXX */
-    ((pin + pa.pa_intrswiz - 1) % 4) + 1;
- }
- pa.pa_intrline = PCI_INTERRUPT_LINE(intr);
-
- if ((dev = config_found_sm(self, &pa, pciprint,
-    pcisubmatch))) {
- pcireg_t reg;
-
- /* skip header type != 0 */
- reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
- if (PCI_HDRTYPE_TYPE(reg) != 0)
- continue;
- if (pci_get_capability(pc, tag,
-    PCI_CAP_PWRMGMT, NULL, NULL) == 0)
- continue;
- if (!(pd = malloc(sizeof *pd, M_DEVBUF,
-    M_NOWAIT)))
- continue;
- pd->pd_tag = tag;
- pd->pd_dev = dev;
- LIST_INSERT_HEAD(&sc->sc_devs, pd, pd_next);
- }
- }
- }
+ sc->sc_iot = pba->pba_iot;
+ sc->sc_memt = pba->pba_memt;
+ sc->sc_dmat = pba->pba_dmat;
+ sc->sc_pc = pba->pba_pc;
+ sc->sc_bus = pba->pba_bus;
+ sc->sc_bridgetag = pba->pba_bridgetag;
+ sc->sc_maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus);
+ sc->sc_intrswiz = pba->pba_intrswiz;
+ sc->sc_intrtag = pba->pba_intrtag;
+ pci_enumerate_bus(sc, NULL, NULL);
 }
 
 /* save and restore the pci config space */
@@ -373,10 +234,10 @@ pcisubmatch(parent, match, aux)
 
  if (cf->pcicf_dev != PCI_UNK_DEV &&
     cf->pcicf_dev != pa->pa_device)
- return 0;
+ return (0);
  if (cf->pcicf_function != PCI_UNK_FUNCTION &&
     cf->pcicf_function != pa->pa_function)
- return 0;
+ return (0);
 
  success = (*cf->cf_attach->ca_match)(parent, match, aux);
 
@@ -399,6 +260,109 @@ pcisubmatch(parent, match, aux)
 }
 
 int
+pci_probe_device(struct pci_softc *sc, pcitag_t tag,
+    int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
+{
+ pci_chipset_tag_t pc = sc->sc_pc;
+ struct pci_attach_args pa;
+ struct pci_dev *pd;
+ struct device *dev;
+ pcireg_t id, csr, class, intr, bhlcr;
+ int ret, pin, bus, device, function;
+
+ pci_decompose_tag(pc, tag, &bus, &device, &function);
+
+ id = pci_conf_read(pc, tag, PCI_ID_REG);
+ csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+ class = pci_conf_read(pc, tag, PCI_CLASS_REG);
+ intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
+ bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ return (0);
+ /* XXX Not invalid, but we've done this ~forever. */
+ if (PCI_VENDOR(id) == 0)
+ return (0);
+
+ pa.pa_iot = sc->sc_iot;
+ pa.pa_memt = sc->sc_memt;
+ pa.pa_dmat = sc->sc_dmat;
+ pa.pa_pc = pc;
+ pa.pa_bus = bus;
+ pa.pa_device = device;
+ pa.pa_function = function;
+ pa.pa_tag = tag;
+ pa.pa_id = id;
+ pa.pa_class = class;
+
+ /* This is a simplification of the NetBSD code.
+   We don't support turning off I/O or memory
+   on broken hardware. <[hidden email]> */
+ pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
+
+#ifdef __i386__
+ /*
+ * on i386 we really need to know the device tag
+ * and not the pci bridge tag, in intr_map
+ * to be able to program the device and the
+ * pci interrupt router.
+ */
+ pa.pa_intrtag = tag;
+ pa.pa_intrswiz = 0;
+#else
+ if (sc->sc_bridgetag == NULL) {
+ pa.pa_intrswiz = 0;
+ pa.pa_intrtag = tag;
+ } else {
+ pa.pa_intrswiz = sc->sc_intrswiz + device;
+ pa.pa_intrtag = sc->sc_intrtag;
+ }
+#endif
+ pin = PCI_INTERRUPT_PIN(intr);
+ pa.pa_rawintrpin = pin;
+ if (pin == PCI_INTERRUPT_PIN_NONE) {
+ /* no interrupt */
+ pa.pa_intrpin = 0;
+ } else {
+ /*
+ * swizzle it based on the number of busses we're
+ * behind and our device number.
+ */
+ pa.pa_intrpin = /* XXX */
+    ((pin + pa.pa_intrswiz - 1) % 4) + 1;
+ }
+ pa.pa_intrline = PCI_INTERRUPT_LINE(intr);
+
+ if (match != NULL) {
+ ret = (*match)(&pa);
+ if (ret != 0 && pap != NULL)
+ *pap = pa;
+ } else {
+ if ((dev = config_found_sm(&sc->sc_dev, &pa, pciprint,
+    pcisubmatch))) {
+ pcireg_t reg;
+
+ /* skip header type != 0 */
+ reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
+ if (PCI_HDRTYPE_TYPE(reg) != 0)
+ return(0);
+ if (pci_get_capability(pc, tag,
+    PCI_CAP_PWRMGMT, NULL, NULL) == 0)
+ return(0);
+ if (!(pd = malloc(sizeof *pd, M_DEVBUF,
+    M_NOWAIT)))
+ return(0);
+ pd->pd_tag = tag;
+ pd->pd_dev = dev;
+ LIST_INSERT_HEAD(&sc->sc_devs, pd, pd_next);
+ }
+ }
+
+ return (ret);
+}
+
+int
 pci_get_capability(pc, tag, capid, offset, value)
  pci_chipset_tag_t pc;
  pcitag_t tag;
@@ -445,6 +409,54 @@ pci_get_capability(pc, tag, capid, offse
 
  return (0);
 }
+
+#ifndef PCI_MACHDEP_ENUMERATE_BUS
+/*
+ * Generic PCI bus enumeration routine.  Used unless machine-dependent
+ * code needs to provide something else.
+ */
+int
+pci_enumerate_bus(struct pci_softc *sc,
+    int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
+{
+ pci_chipset_tag_t pc = sc->sc_pc;
+ int device, function, nfunctions, ret;
+ const struct pci_quirkdata *qd;
+ pcireg_t id, bhlcr;
+ pcitag_t tag;
+
+ for (device = 0; device < sc->sc_maxndevs; device++) {
+ tag = pci_make_tag(pc, sc->sc_bus, device, 0);
+ id = pci_conf_read(pc, tag, PCI_ID_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ continue;
+ /* XXX Not invalid, but we've done this ~forever. */
+ if (PCI_VENDOR(id) == 0)
+ continue;
+
+ qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id));
+
+ bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
+ if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
+    (qd != NULL &&
+      (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
+ nfunctions = 8;
+ else
+ nfunctions = 1;
+
+ for (function = 0; function < nfunctions; function++) {
+ tag = pci_make_tag(pc, sc->sc_bus, device, function);
+ ret = pci_probe_device(sc, tag, match, pap);
+ if (match != NULL && ret != 0)
+ return (ret);
+ }
+ }
+
+ return (0);
+}
+#endif /* PCI_MACHDEP_ENUMERATE_BUS */
 
 int
 pci_matchbyid(struct pci_attach_args *pa, const struct pci_matchid *ids,
Index: dev/pci/pcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/pcivar.h,v
retrieving revision 1.44
diff -u -p -r1.44 pcivar.h
--- dev/pci/pcivar.h 13 Mar 2006 20:10:49 -0000 1.44
+++ dev/pci/pcivar.h 17 Mar 2006 00:39:02 -0000
@@ -151,11 +151,15 @@ struct pci_quirkdata {
 
 struct pci_softc {
  struct device sc_dev;
+ bus_space_tag_t sc_iot, sc_memt;
+ bus_dma_tag_t sc_dmat;
  pci_chipset_tag_t sc_pc;
  void *sc_powerhook;
  LIST_HEAD(, pci_dev) sc_devs;
- int sc_bus;
+ int sc_bus, sc_maxndevs;
  pcitag_t *sc_bridgetag;
+ u_int sc_intrswiz;
+ pcitag_t sc_intrtag;
 };
 
 /*
@@ -204,6 +208,8 @@ int pci_matchbyid(struct pci_attach_args
  * Helper functions for autoconfiguration.
  */
 const char *pci_findvendor(pcireg_t);
+int pci_probe_device(struct pci_softc *, pcitag_t tag,
+    int (*)(struct pci_attach_args *), struct pci_attach_args *);
 void pci_devinfo(pcireg_t, pcireg_t, int, char *, size_t);
 const struct pci_quirkdata *
  pci_lookup_quirkdata(pci_vendor_id_t, pci_product_id_t);