Changeset View
Standalone View
sys/dev/pci/pci.c
Show All 24 Lines | |||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_bus.h" | #include "opt_bus.h" | ||||
#include "opt_pciehp.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/linker.h> | #include <sys/linker.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
static int pci_msi_blacklisted(void); | static int pci_msi_blacklisted(void); | ||||
static int pci_msix_blacklisted(void); | static int pci_msix_blacklisted(void); | ||||
static void pci_resume_msi(device_t dev); | static void pci_resume_msi(device_t dev); | ||||
static void pci_resume_msix(device_t dev); | static void pci_resume_msix(device_t dev); | ||||
static int pci_remap_intr_method(device_t bus, device_t dev, | static int pci_remap_intr_method(device_t bus, device_t dev, | ||||
u_int irq); | u_int irq); | ||||
static uint16_t pci_get_rid_method(device_t dev, device_t child); | static uint16_t pci_get_rid_method(device_t dev, device_t child); | ||||
static int pci_child_present(device_t, uint8_t, uint8_t, uint8_t); | |||||
static int pci_bus_child_present(device_t dev, device_t child); | |||||
static device_t pci_add_child_method(device_t, uint8_t, uint8_t); | |||||
static struct pci_devinfo * pci_fill_devinfo(device_t pcib, int d, int b, int s, | static struct pci_devinfo *pci_fill_devinfo(device_t pcib, int d, int b, int s, | ||||
int f, uint16_t vid, uint16_t did, size_t size); | int f, uint16_t vid, uint16_t did, size_t size); | ||||
static device_method_t pci_methods[] = { | static device_method_t pci_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, pci_probe), | DEVMETHOD(device_probe, pci_probe), | ||||
DEVMETHOD(device_attach, pci_attach), | DEVMETHOD(device_attach, pci_attach), | ||||
#ifdef PCI_RES_BUS | #ifdef PCI_RES_BUS | ||||
DEVMETHOD(device_detach, pci_detach), | DEVMETHOD(device_detach, pci_detach), | ||||
Show All 24 Lines | #endif | ||||
DEVMETHOD(bus_activate_resource, pci_activate_resource), | DEVMETHOD(bus_activate_resource, pci_activate_resource), | ||||
DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource), | DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource), | ||||
DEVMETHOD(bus_child_detached, pci_child_detached), | DEVMETHOD(bus_child_detached, pci_child_detached), | ||||
DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), | DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), | ||||
DEVMETHOD(bus_child_location_str, pci_child_location_str_method), | DEVMETHOD(bus_child_location_str, pci_child_location_str_method), | ||||
DEVMETHOD(bus_remap_intr, pci_remap_intr_method), | DEVMETHOD(bus_remap_intr, pci_remap_intr_method), | ||||
DEVMETHOD(bus_suspend_child, pci_suspend_child), | DEVMETHOD(bus_suspend_child, pci_suspend_child), | ||||
DEVMETHOD(bus_resume_child, pci_resume_child), | DEVMETHOD(bus_resume_child, pci_resume_child), | ||||
DEVMETHOD(bus_child_present, pci_bus_child_present), | |||||
/* PCI interface */ | /* PCI interface */ | ||||
DEVMETHOD(pci_read_config, pci_read_config_method), | DEVMETHOD(pci_read_config, pci_read_config_method), | ||||
DEVMETHOD(pci_write_config, pci_write_config_method), | DEVMETHOD(pci_write_config, pci_write_config_method), | ||||
DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), | DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), | ||||
DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), | DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), | ||||
DEVMETHOD(pci_enable_io, pci_enable_io_method), | DEVMETHOD(pci_enable_io, pci_enable_io_method), | ||||
DEVMETHOD(pci_disable_io, pci_disable_io_method), | DEVMETHOD(pci_disable_io, pci_disable_io_method), | ||||
Show All 11 Lines | #endif | ||||
DEVMETHOD(pci_enable_msix, pci_enable_msix_method), | DEVMETHOD(pci_enable_msix, pci_enable_msix_method), | ||||
DEVMETHOD(pci_disable_msi, pci_disable_msi_method), | DEVMETHOD(pci_disable_msi, pci_disable_msi_method), | ||||
DEVMETHOD(pci_remap_msix, pci_remap_msix_method), | DEVMETHOD(pci_remap_msix, pci_remap_msix_method), | ||||
DEVMETHOD(pci_release_msi, pci_release_msi_method), | DEVMETHOD(pci_release_msi, pci_release_msi_method), | ||||
DEVMETHOD(pci_msi_count, pci_msi_count_method), | DEVMETHOD(pci_msi_count, pci_msi_count_method), | ||||
DEVMETHOD(pci_msix_count, pci_msix_count_method), | DEVMETHOD(pci_msix_count, pci_msix_count_method), | ||||
DEVMETHOD(pci_get_rid, pci_get_rid_method), | DEVMETHOD(pci_get_rid, pci_get_rid_method), | ||||
DEVMETHOD(pci_child_added, pci_child_added_method), | DEVMETHOD(pci_child_added, pci_child_added_method), | ||||
DEVMETHOD(pci_add_child, pci_add_child_method), | |||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
DEVMETHOD(pci_iov_attach, pci_iov_attach_method), | DEVMETHOD(pci_iov_attach, pci_iov_attach_method), | ||||
DEVMETHOD(pci_iov_detach, pci_iov_detach_method), | DEVMETHOD(pci_iov_detach, pci_iov_detach_method), | ||||
DEVMETHOD(pci_create_iov_child, pci_create_iov_child_method), | DEVMETHOD(pci_create_iov_child, pci_create_iov_child_method), | ||||
#endif | #endif | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 406 Lines • ▼ Show 20 Lines | case PCIM_HDRTYPE_CARDBUS: | ||||
cfg->nummaps = PCI_MAXMAPS_2; | cfg->nummaps = PCI_MAXMAPS_2; | ||||
break; | break; | ||||
} | } | ||||
#undef REG | #undef REG | ||||
} | } | ||||
/* read configuration header into pcicfgregs structure */ | /* read configuration header into pcicfgregs structure */ | ||||
struct pci_devinfo * | struct pci_devinfo * | ||||
pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size) | pci_read_device(device_t pcib, uint32_t d, uint8_t b, uint8_t s, uint8_t f, | ||||
size_t size) | |||||
{ | { | ||||
#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) | #define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) | ||||
uint16_t vid, did; | uint16_t vid, did; | ||||
vid = REG(PCIR_VENDOR, 2); | vid = REG(PCIR_VENDOR, 2); | ||||
did = REG(PCIR_DEVICE, 2); | did = REG(PCIR_DEVICE, 2); | ||||
if (vid != 0xffff) | if (vid != 0xffff) | ||||
return (pci_fill_devinfo(pcib, d, b, s, f, vid, did, size)); | return (pci_fill_devinfo(pcib, d, b, s, f, vid, did, size)); | ||||
▲ Show 20 Lines • Show All 2,877 Lines • ▼ Show 20 Lines | #if defined(NEW_PCIB) && defined(PCI_RES_BUS) | ||||
/* | /* | ||||
* Reserve resources for secondary bus ranges behind bridge | * Reserve resources for secondary bus ranges behind bridge | ||||
* devices. | * devices. | ||||
*/ | */ | ||||
pci_reserve_secbus(bus, dev, cfg, rl); | pci_reserve_secbus(bus, dev, cfg, rl); | ||||
#endif | #endif | ||||
} | } | ||||
static struct pci_devinfo * | |||||
jhb: You could keep this to avoid the code duplication in pci_add_children(). It could do something… | |||||
pci_identify_function(device_t pcib, device_t dev, int domain, int busno, | |||||
int slot, int func, size_t dinfo_size) | |||||
{ | |||||
struct pci_devinfo *dinfo; | |||||
dinfo = pci_read_device(pcib, domain, busno, slot, func, dinfo_size); | |||||
if (dinfo != NULL) | |||||
pci_add_child(dev, dinfo); | |||||
return (dinfo); | |||||
} | |||||
void | void | ||||
pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size) | pci_add_children(device_t dev) | ||||
{ | { | ||||
#define REG(n, w) PCIB_READ_CONFIG(pcib, busno, s, f, n, w) | device_t pcib, child; | ||||
device_t pcib = device_get_parent(dev); | |||||
struct pci_devinfo *dinfo; | |||||
int maxslots; | int maxslots; | ||||
int s, f, pcifunchigh; | int s, f, pcifunchigh; | ||||
uint32_t domain; | |||||
uint8_t busno; | |||||
uint8_t hdrtype; | uint8_t hdrtype; | ||||
int first_func; | int first_func; | ||||
pcib = device_get_parent(dev); | |||||
domain = pcib_get_domain(dev); | |||||
busno = pcib_get_bus(dev); | |||||
/* | /* | ||||
* Try to detect a device at slot 0, function 0. If it exists, try to | * Try to detect a device at slot 0, function 0. If it exists, try to | ||||
* enable ARI. We must enable ARI before detecting the rest of the | * enable ARI. We must enable ARI before detecting the rest of the | ||||
* functions on this bus as ARI changes the set of slots and functions | * functions on this bus as ARI changes the set of slots and functions | ||||
* that are legal on this bus. | * that are legal on this bus. | ||||
*/ | */ | ||||
dinfo = pci_identify_function(pcib, dev, domain, busno, 0, 0, | if (pci_child_present(pcib, busno, 0, 0) == -1 && | ||||
dinfo_size); | pci_find_dbsf(domain, busno, 0, 0) == NULL) { | ||||
if (dinfo != NULL && pci_enable_ari) | child = PCI_ADD_CHILD(dev, 0, 0); | ||||
PCIB_TRY_ENABLE_ARI(pcib, dinfo->cfg.dev); | if (pci_enable_ari) | ||||
PCIB_TRY_ENABLE_ARI(pcib, child); | |||||
} | |||||
/* | /* | ||||
* Start looking for new devices on slot 0 at function 1 because we | * Start looking for new devices on slot 0 at function 1 because we | ||||
* just identified the device at slot 0, function 0. | * just identified the device at slot 0, function 0. | ||||
*/ | */ | ||||
first_func = 1; | first_func = 1; | ||||
KASSERT(dinfo_size >= sizeof(struct pci_devinfo), | |||||
("dinfo_size too small")); | |||||
maxslots = PCIB_MAXSLOTS(pcib); | maxslots = PCIB_MAXSLOTS(pcib); | ||||
for (s = 0; s <= maxslots; s++, first_func = 0) { | for (s = 0; s <= maxslots; s++, first_func = 0) { | ||||
pcifunchigh = 0; | pcifunchigh = 0; | ||||
f = 0; | f = 0; | ||||
DELAY(1); | hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1); | ||||
impUnsubmitted Not Done Inline ActionsI'd be very hesitant to remove this DELAY. I think it is really needed for some legacy hardware. imp: I'd be very hesitant to remove this DELAY. I think it is really needed for some legacy hardware. | |||||
jmgAuthorUnsubmitted Not Done Inline ActionsI talked w/ gavin (iirc) about this, and this was only required for a special AMD8111 chip that was never put into production (I believe pre production) that FreeBSD did devel on. See: jmg: I talked w/ gavin (iirc) about this, and this was only required for a special AMD8111 chip that… | |||||
impUnsubmitted Not Done Inline ActionsOK. The pre-production status of this part wasn't clear from reading the commit log. imp: OK. The pre-production status of this part wasn't clear from reading the commit log.
| |||||
gavinUnsubmitted Not Done Inline ActionsNope, not me. I know nothing about this line's history other than from commit logs. gavin: Nope, not me. I know nothing about this line's history other than from commit logs. | |||||
jhbUnsubmitted Not Done Inline ActionsI would leave the REG() here to reduce the noise in the diff. jhb: I would leave the REG() here to reduce the noise in the diff. | |||||
hdrtype = REG(PCIR_HDRTYPE, 1); | |||||
if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) | if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) | ||||
continue; | continue; | ||||
if (hdrtype & PCIM_MFDEV) | if (hdrtype & PCIM_MFDEV) | ||||
pcifunchigh = PCIB_MAXFUNCS(pcib); | pcifunchigh = PCIB_MAXFUNCS(pcib); | ||||
for (f = first_func; f <= pcifunchigh; f++) | for (f = first_func; f <= pcifunchigh; f++) { | ||||
pci_identify_function(pcib, dev, domain, busno, s, f, | if (pci_child_present(pcib, busno, s, f) == -1 && | ||||
dinfo_size); | pci_find_dbsf(domain, busno, s, f) == NULL) | ||||
PCI_ADD_CHILD(dev, s, f); | |||||
} | } | ||||
#undef REG | |||||
} | } | ||||
} | |||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
device_t | device_t | ||||
pci_add_iov_child(device_t bus, device_t pf, size_t size, uint16_t rid, | pci_add_iov_child(device_t bus, device_t pf, size_t size, uint16_t rid, | ||||
uint16_t vid, uint16_t did) | uint16_t vid, uint16_t did) | ||||
{ | { | ||||
struct pci_devinfo *pf_dinfo, *vf_dinfo; | struct pci_devinfo *pf_dinfo, *vf_dinfo; | ||||
device_t pcib; | device_t pcib; | ||||
Show All 33 Lines | pci_create_iov_child_method(device_t bus, device_t pf, uint16_t rid, | ||||
return (pci_add_iov_child(bus, pf, sizeof(struct pci_devinfo), rid, vid, | return (pci_add_iov_child(bus, pf, sizeof(struct pci_devinfo), rid, vid, | ||||
did)); | did)); | ||||
} | } | ||||
#endif | #endif | ||||
void | void | ||||
pci_add_child(device_t bus, struct pci_devinfo *dinfo) | pci_add_child(device_t bus, struct pci_devinfo *dinfo) | ||||
{ | { | ||||
impUnsubmitted Not Done Inline ActionsThis style change looks independent of the rest of the work. imp: This style change looks independent of the rest of the work.
| |||||
jmgAuthorUnsubmitted Not Done Inline Actionsok, missed that w/ my recent white space clean up last night.. I'll commit this separately shortly. jmg: ok, missed that w/ my recent white space clean up last night.. I'll commit this separately… | |||||
dinfo->cfg.dev = device_add_child(bus, NULL, -1); | dinfo->cfg.dev = device_add_child(bus, NULL, -1); | ||||
device_set_ivars(dinfo->cfg.dev, dinfo); | device_set_ivars(dinfo->cfg.dev, dinfo); | ||||
resource_list_init(&dinfo->resources); | resource_list_init(&dinfo->resources); | ||||
pci_cfg_save(dinfo->cfg.dev, dinfo, 0); | pci_cfg_save(dinfo->cfg.dev, dinfo, 0); | ||||
pci_cfg_restore(dinfo->cfg.dev, dinfo); | pci_cfg_restore(dinfo->cfg.dev, dinfo); | ||||
pci_print_verbose(dinfo); | pci_print_verbose(dinfo); | ||||
pci_add_resources(bus, dinfo->cfg.dev, 0, 0); | pci_add_resources(bus, dinfo->cfg.dev, 0, 0); | ||||
pci_child_added(dinfo->cfg.dev); | pci_child_added(dinfo->cfg.dev); | ||||
} | } | ||||
void | void | ||||
pci_child_added_method(device_t dev, device_t child) | pci_child_added_method(device_t dev, device_t child) | ||||
{ | { | ||||
} | } | ||||
static device_t | |||||
pci_add_child_method(device_t dev, uint8_t s, uint8_t f) | |||||
{ | |||||
return pci_add_child_size(dev, s, f, sizeof(struct pci_devinfo)); | |||||
jhbUnsubmitted Not Done Inline Actionsstyle(9) puts ()'s around return values, so 'return (pci_add_child_size(...))' FWIW. (Also, throughout the patch). jhb: style(9) puts ()'s around return values, so 'return (pci_add_child_size(...))' FWIW.
(Also… | |||||
} | |||||
device_t | |||||
pci_add_child_size(device_t dev, uint8_t s, uint8_t f, | |||||
size_t dinfo_size) | |||||
{ | |||||
device_t pcib; | |||||
struct pci_devinfo *dinfo; | |||||
uint32_t d; | |||||
uint8_t b; | |||||
pcib = device_get_parent(dev); | |||||
d = pcib_get_domain(dev); | |||||
b = pcib_get_bus(dev); | |||||
dinfo = pci_read_device(pcib, d, b, s, f, dinfo_size); | |||||
if (dinfo == NULL) | |||||
return NULL; | |||||
pci_add_child(dev, dinfo); | |||||
return dinfo->cfg.dev; | |||||
} | |||||
static int | static int | ||||
pci_probe(device_t dev) | pci_probe(device_t dev) | ||||
{ | { | ||||
device_set_desc(dev, "PCI bus"); | device_set_desc(dev, "PCI bus"); | ||||
/* Allow other subclasses to override this driver. */ | /* Allow other subclasses to override this driver. */ | ||||
return (BUS_PROBE_GENERIC); | return (BUS_PROBE_GENERIC); | ||||
Show All 38 Lines | if (error) | ||||
device_printf(dev, "Failed to create DMA tag: %d\n", | device_printf(dev, "Failed to create DMA tag: %d\n", | ||||
error); | error); | ||||
else | else | ||||
tag_valid = 1; | tag_valid = 1; | ||||
} | } | ||||
if (!tag_valid) | if (!tag_valid) | ||||
#endif | #endif | ||||
sc->sc_dma_tag = bus_get_dma_tag(dev); | sc->sc_dma_tag = bus_get_dma_tag(dev); | ||||
#ifdef PCI_EHP | |||||
pci_hotplug_init(dev); | |||||
#endif | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
pci_attach(device_t dev) | pci_attach(device_t dev) | ||||
{ | { | ||||
int busno, domain, error; | int error; | ||||
error = pci_attach_common(dev); | error = pci_attach_common(dev); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* Since there can be multiple independantly numbered PCI | * Since there can be multiple independantly numbered PCI | ||||
* busses on systems with multiple PCI domains, we can't use | * busses on systems with multiple PCI domains, we can't use | ||||
* the unit number to decide which bus we are probing. We ask | * the unit number to decide which bus we are probing. We ask | ||||
* the parent pcib what our domain and bus numbers are. | * the parent pcib what our domain and bus numbers are. | ||||
*/ | */ | ||||
domain = pcib_get_domain(dev); | pci_add_children(dev); | ||||
busno = pcib_get_bus(dev); | |||||
pci_add_children(dev, domain, busno, sizeof(struct pci_devinfo)); | |||||
return (bus_generic_attach(dev)); | return (bus_generic_attach(dev)); | ||||
} | } | ||||
#ifdef PCI_RES_BUS | #ifdef PCI_RES_BUS | ||||
static int | static int | ||||
pci_detach(device_t dev) | pci_detach(device_t dev) | ||||
{ | { | ||||
struct pci_softc *sc; | struct pci_softc *sc; | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | pci_resume(device_t dev) | ||||
for (i = 0; i < numdevs; i++) { | for (i = 0; i < numdevs; i++) { | ||||
child = devlist[i]; | child = devlist[i]; | ||||
switch (pci_get_class(child)) { | switch (pci_get_class(child)) { | ||||
case PCIC_DISPLAY: | case PCIC_DISPLAY: | ||||
case PCIC_MEMORY: | case PCIC_MEMORY: | ||||
case PCIC_BRIDGE: | case PCIC_BRIDGE: | ||||
case PCIC_BASEPERIPH: | case PCIC_BASEPERIPH: | ||||
BUS_RESUME_CHILD(dev, child); | BUS_RESUME_CHILD(dev, child); | ||||
devlist[i] = NULL; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
for (i = 0; i < numdevs; i++) { | for (i = 0; i < numdevs; i++) { | ||||
child = devlist[i]; | child = devlist[i]; | ||||
switch (pci_get_class(child)) { | if (child != NULL) | ||||
case PCIC_DISPLAY: | |||||
case PCIC_MEMORY: | |||||
case PCIC_BRIDGE: | |||||
case PCIC_BASEPERIPH: | |||||
break; | |||||
default: | |||||
BUS_RESUME_CHILD(dev, child); | BUS_RESUME_CHILD(dev, child); | ||||
} | } | ||||
impUnsubmitted Not Done Inline ActionsThis cleanup looks independent of the rest of the work. imp: This cleanup looks independent of the rest of the work.
| |||||
jmgAuthorUnsubmitted Not Done Inline ActionsStandard problem of cleaning up code while looking at related code, and trying to pull changes apart. Shall I just commit this fix then? jmg: Standard problem of cleaning up code while looking at related code, and trying to pull changes… | |||||
impUnsubmitted Not Done Inline ActionsYes. Reduce the diffs. Easier to review, and easier to bisect changes if one of these cleanups winds up causing trouble. imp: Yes. Reduce the diffs. Easier to review, and easier to bisect changes if one of these cleanups… | |||||
} | |||||
free(devlist, M_TEMP); | free(devlist, M_TEMP); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
pci_load_vendor_data(void) | pci_load_vendor_data(void) | ||||
{ | { | ||||
caddr_t data; | caddr_t data; | ||||
▲ Show 20 Lines • Show All 1,536 Lines • ▼ Show 20 Lines | pci_restore_state(device_t dev) | ||||
pci_cfg_restore(dev, dinfo); | pci_cfg_restore(dev, dinfo); | ||||
} | } | ||||
static uint16_t | static uint16_t | ||||
pci_get_rid_method(device_t dev, device_t child) | pci_get_rid_method(device_t dev, device_t child) | ||||
{ | { | ||||
return (PCIB_GET_RID(device_get_parent(dev), child)); | return (PCIB_GET_RID(device_get_parent(dev), child)); | ||||
} | |||||
static int | |||||
pci_child_present(device_t pcib, uint8_t b, uint8_t s, uint8_t f) | |||||
{ | |||||
if (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVVENDOR, 4) != 0xfffffffful) | |||||
impUnsubmitted Not Done Inline ActionsThis isn't necessarily a good test. There are many devices that don't expect you to read config space for function > 0 since they are single function devices, as defined in the header for function 0. While most are well behaved, an interesting number are not. imp: This isn't necessarily a good test.
There are many devices that don't expect you to read… | |||||
jmgAuthorUnsubmitted Not Done Inline ActionsWell, pci_child_present is called in two contexts, either a) a device was present and went away (and in this case I believe it's well defined) (so, should be fine) or b) we are probing for devices, but we always check 0, 0 first, before going on. If you follow the code, this code should be virtually identical (here we check all 32 bits instead of just the vendor).. See pci_read_device for the original check. jmg: Well, pci_child_present is called in two contexts, either a) a device was present and went away… | |||||
impUnsubmitted Not Done Inline ActionsDocument this with a comment then. imp: Document this with a comment then. | |||||
jhbUnsubmitted Not Done Inline ActionsYou should only check the vendor. That is what the PCI spec defines (as it were) in that it says that a vendor ID of 0xFFFFh is always invalid. It makes no guarantees about the device ID. jhb: You should only check the vendor. That is what the PCI spec defines (as it were) in that it… | |||||
return -1; /* present */ | |||||
return 0; | |||||
} | |||||
static int | |||||
pci_bus_child_present(device_t dev, device_t child) | |||||
{ | |||||
uint8_t b, s, f; | |||||
b = pci_get_bus(child); | |||||
s = pci_get_slot(child); | |||||
f = pci_get_function(child); | |||||
return pci_child_present(device_get_parent(dev), b, s, f); | |||||
} | } |
You could keep this to avoid the code duplication in pci_add_children(). It could do something like this:
Then to handle ARI you would just do: