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. Machine-dependent code will be able to specify the bus enumeration routine in the future.
This commit is contained in:
parent
a91677eb7b
commit
7c86eb62bc
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: pci.c,v 1.58 2001/11/13 07:48:47 lukem Exp $ */
|
||||
/* $NetBSD: pci.c,v 1.59 2002/05/15 18:13:00 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995, 1996, 1997, 1998
|
||||
|
@ -36,7 +36,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.58 2001/11/13 07:48:47 lukem Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.59 2002/05/15 18:13:00 thorpej Exp $");
|
||||
|
||||
#include "opt_pci.h"
|
||||
|
||||
|
@ -61,8 +61,6 @@ struct cfattach pci_ca = {
|
|||
sizeof(struct pci_softc), pcimatch, pciattach
|
||||
};
|
||||
|
||||
int pci_probe_bus(struct device *, int (*match)(struct pci_attach_args *),
|
||||
struct pci_attach_args *);
|
||||
int pciprint __P((void *, const char *));
|
||||
int pcisubmatch __P((struct device *, struct cfdata *, void *));
|
||||
|
||||
|
@ -116,160 +114,11 @@ pcimatch(parent, cf, aux)
|
|||
* XXX check other (hardware?) indicators
|
||||
*/
|
||||
|
||||
return 1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* XXX
|
||||
* The __PCI_BUS_DEVORDER/__PCI_DEV_FUNCORDER macros should go away
|
||||
* and be implemented with device properties when they arrive.
|
||||
*/
|
||||
int
|
||||
pci_probe_bus(struct device *self, int (*match)(struct pci_attach_args *),
|
||||
struct pci_attach_args *pap)
|
||||
{
|
||||
struct pci_softc *sc = (struct pci_softc *)self;
|
||||
bus_space_tag_t iot, memt;
|
||||
pci_chipset_tag_t pc;
|
||||
int bus, device, function, nfunctions, ret;
|
||||
#ifdef __PCI_BUS_DEVORDER
|
||||
char devs[32];
|
||||
int i;
|
||||
#endif
|
||||
#ifdef __PCI_DEV_FUNCORDER
|
||||
char funcs[8];
|
||||
int j;
|
||||
#else
|
||||
const struct pci_quirkdata *qd;
|
||||
#endif
|
||||
|
||||
iot = sc->sc_iot;
|
||||
memt = sc->sc_memt;
|
||||
pc = sc->sc_pc;
|
||||
bus = sc->sc_bus;
|
||||
#ifdef __PCI_BUS_DEVORDER
|
||||
pci_bus_devorder(sc->sc_pc, sc->sc_bus, devs);
|
||||
for (i = 0; (device = devs[i]) < 32 && device >= 0; i++)
|
||||
#else
|
||||
for (device = 0; device < sc->sc_maxndevs; device++)
|
||||
#endif
|
||||
{
|
||||
pcitag_t tag;
|
||||
pcireg_t id, class, intr, bhlcr, csr;
|
||||
struct pci_attach_args pa;
|
||||
int pin;
|
||||
|
||||
#ifdef __PCI_DEV_FUNCORDER
|
||||
pci_dev_funcorder(sc->sc_pc, sc->sc_bus, device, funcs);
|
||||
nfunctions = 8;
|
||||
#else
|
||||
tag = pci_make_tag(pc, 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;
|
||||
#endif /* __PCI_DEV_FUNCORDER */
|
||||
|
||||
#ifdef __PCI_DEV_FUNCORDER
|
||||
for (j = 0; (function = funcs[j]) < nfunctions &&
|
||||
function >= 0; j++)
|
||||
#else
|
||||
for (function = 0; function < nfunctions; function++)
|
||||
#endif
|
||||
{
|
||||
tag = pci_make_tag(pc, 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)
|
||||
continue;
|
||||
/* XXX Not invalid, but we've done this ~forever. */
|
||||
if (PCI_VENDOR(id) == 0)
|
||||
continue;
|
||||
|
||||
pa.pa_iot = iot;
|
||||
pa.pa_memt = 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;
|
||||
|
||||
/*
|
||||
* Set up memory, I/O enable, and PCI command flags
|
||||
* as appropriate.
|
||||
*/
|
||||
pa.pa_flags = sc->sc_flags;
|
||||
if ((csr & PCI_COMMAND_IO_ENABLE) == 0)
|
||||
pa.pa_flags &= ~PCI_FLAGS_IO_ENABLED;
|
||||
if ((csr & PCI_COMMAND_MEM_ENABLE) == 0)
|
||||
pa.pa_flags &= ~PCI_FLAGS_MEM_ENABLED;
|
||||
|
||||
/*
|
||||
* If the cache line size is not configured, then
|
||||
* clear the MRL/MRM/MWI command-ok flags.
|
||||
*/
|
||||
if (PCI_CACHELINE(bhlcr) == 0)
|
||||
pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY|
|
||||
PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY);
|
||||
|
||||
if (bus == 0) {
|
||||
pa.pa_intrswiz = 0;
|
||||
pa.pa_intrtag = tag;
|
||||
} else {
|
||||
pa.pa_intrswiz = sc->sc_intrswiz + device;
|
||||
pa.pa_intrtag = sc->sc_intrtag;
|
||||
}
|
||||
pin = PCI_INTERRUPT_PIN(intr);
|
||||
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) {
|
||||
if (pap != NULL)
|
||||
*pap = pa;
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
config_found_sm(self, &pa, pciprint,
|
||||
pcisubmatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* XXX Temporary */
|
||||
#define pci_enumerate_bus pci_enumerate_bus_generic
|
||||
|
||||
void
|
||||
pciattach(parent, self, aux)
|
||||
|
@ -328,7 +177,7 @@ pciattach(parent, self, aux)
|
|||
sc->sc_intrswiz = pba->pba_intrswiz;
|
||||
sc->sc_intrtag = pba->pba_intrtag;
|
||||
sc->sc_flags = pba->pba_flags;
|
||||
pci_probe_bus(self, NULL, NULL);
|
||||
pci_enumerate_bus(sc, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -387,13 +236,98 @@ pcisubmatch(parent, cf, 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);
|
||||
return ((*cf->cf_attach->ca_match)(parent, cf, 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;
|
||||
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 (NULL);
|
||||
/* XXX Not invalid, but we've done this ~forever. */
|
||||
if (PCI_VENDOR(id) == 0)
|
||||
return (NULL);
|
||||
|
||||
pa.pa_iot = sc->sc_iot;
|
||||
pa.pa_memt = sc->sc_memt;
|
||||
pa.pa_dmat = sc->sc_dmat;
|
||||
pa.pa_pc = pc;
|
||||
pa.pa_device = device;
|
||||
pa.pa_function = function;
|
||||
pa.pa_tag = tag;
|
||||
pa.pa_id = id;
|
||||
pa.pa_class = class;
|
||||
|
||||
/*
|
||||
* Set up memory, I/O enable, and PCI command flags
|
||||
* as appropriate.
|
||||
*/
|
||||
pa.pa_flags = sc->sc_flags;
|
||||
if ((csr & PCI_COMMAND_IO_ENABLE) == 0)
|
||||
pa.pa_flags &= ~PCI_FLAGS_IO_ENABLED;
|
||||
if ((csr & PCI_COMMAND_MEM_ENABLE) == 0)
|
||||
pa.pa_flags &= ~PCI_FLAGS_MEM_ENABLED;
|
||||
|
||||
/*
|
||||
* If the cache line size is not configured, then
|
||||
* clear the MRL/MRM/MWI command-ok flags.
|
||||
*/
|
||||
if (PCI_CACHELINE(bhlcr) == 0)
|
||||
pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY|
|
||||
PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY);
|
||||
|
||||
if (bus == 0) {
|
||||
pa.pa_intrswiz = 0;
|
||||
pa.pa_intrtag = tag;
|
||||
} else {
|
||||
pa.pa_intrswiz = sc->sc_intrswiz + device;
|
||||
pa.pa_intrtag = sc->sc_intrtag;
|
||||
}
|
||||
pin = PCI_INTERRUPT_PIN(intr);
|
||||
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 {
|
||||
ret = config_found_sm(&sc->sc_dev, &pa, pciprint,
|
||||
pcisubmatch) != NULL;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pci_get_capability(pc, tag, capid, offset, value)
|
||||
pci_chipset_tag_t pc;
|
||||
|
@ -446,14 +380,61 @@ int
|
|||
pci_find_device(struct pci_attach_args *pa,
|
||||
int (*match)(struct pci_attach_args *))
|
||||
{
|
||||
int i;
|
||||
struct device *pcidev;
|
||||
extern struct cfdriver pci_cd;
|
||||
struct device *pcidev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pci_cd.cd_ndevs; i++) {
|
||||
pcidev = pci_cd.cd_devs[i];
|
||||
if (pcidev != NULL && pci_probe_bus(pcidev, match, pa) != 0)
|
||||
return 1;
|
||||
if (pcidev != NULL &&
|
||||
pci_enumerate_bus((struct pci_softc *) pcidev,
|
||||
match, pa) != 0)
|
||||
return (1);
|
||||
}
|
||||
return 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic PCI bus enumeration routine. Used unless machine-dependent
|
||||
* code needs to provide something else.
|
||||
*/
|
||||
int
|
||||
pci_enumerate_bus_generic(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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: pcivar.h,v 1.48 2001/09/13 21:49:40 thorpej Exp $ */
|
||||
/* $NetBSD: pcivar.h,v 1.49 2002/05/15 18:13:01 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
|
||||
|
@ -182,6 +182,10 @@ int pci_get_capability __P((pci_chipset_tag_t, pcitag_t, int,
|
|||
/*
|
||||
* Helper functions for autoconfiguration.
|
||||
*/
|
||||
int pci_enumerate_bus_generic(struct pci_softc *,
|
||||
int (*)(struct pci_attach_args *), struct pci_attach_args *);
|
||||
int pci_probe_device(struct pci_softc *, pcitag_t tag,
|
||||
int (*)(struct pci_attach_args *), struct pci_attach_args *);
|
||||
void pci_devinfo __P((pcireg_t, pcireg_t, int, char *));
|
||||
void pci_conf_print __P((pci_chipset_tag_t, pcitag_t,
|
||||
void (*)(pci_chipset_tag_t, pcitag_t, const pcireg_t *)));
|
||||
|
|
Loading…
Reference in New Issue