Add a new PCI bus interface method to alloc the ivars (dinfo) for a device.

The ACPI and OFW PCI bus drivers as well as CardBus override this to
allocate the larger ivars to hold additional info beyond the stock PCI ivars.

This removes the need to pass the size to functions like pci_add_iov_child()
and pci_read_device() simplifying IOV and bus rescanning implementations.

As a result of this and earlier changes, the ACPI PCI bus driver no longer
needs its own device_attach and pci_create_iov_child methods but can use
the methods in the stock PCI bus driver instead.

Differential Revision:	https://reviews.freebsd.org/D5891
This commit is contained in:
John Baldwin 2016-04-15 03:42:12 +00:00
parent 2c6167310e
commit 6cd99ae86d
10 changed files with 103 additions and 110 deletions

View File

@ -70,7 +70,7 @@ CTASSERT(ACPI_STATE_D1 == PCI_POWERSTATE_D1);
CTASSERT(ACPI_STATE_D2 == PCI_POWERSTATE_D2);
CTASSERT(ACPI_STATE_D3 == PCI_POWERSTATE_D3);
static int acpi_pci_attach(device_t dev);
static struct pci_devinfo *acpi_pci_alloc_devinfo(device_t dev);
static void acpi_pci_child_deleted(device_t dev, device_t child);
static int acpi_pci_child_location_str_method(device_t cbdev,
device_t child, char *buf, size_t buflen);
@ -86,15 +86,9 @@ static int acpi_pci_set_powerstate_method(device_t dev, device_t child,
static void acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child);
static bus_dma_tag_t acpi_pci_get_dma_tag(device_t bus, device_t child);
#ifdef PCI_IOV
static device_t acpi_pci_create_iov_child(device_t bus, device_t pf,
uint16_t rid, uint16_t vid, uint16_t did);
#endif
static device_method_t acpi_pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, acpi_pci_probe),
DEVMETHOD(device_attach, acpi_pci_attach),
/* Bus interface */
DEVMETHOD(bus_read_ivar, acpi_pci_read_ivar),
@ -105,11 +99,9 @@ static device_method_t acpi_pci_methods[] = {
DEVMETHOD(bus_get_domain, acpi_get_domain),
/* PCI interface */
DEVMETHOD(pci_alloc_devinfo, acpi_pci_alloc_devinfo),
DEVMETHOD(pci_child_added, acpi_pci_child_added),
DEVMETHOD(pci_set_powerstate, acpi_pci_set_powerstate_method),
#ifdef PCI_IOV
DEVMETHOD(pci_create_iov_child, acpi_pci_create_iov_child),
#endif
DEVMETHOD_END
};
@ -123,6 +115,15 @@ MODULE_DEPEND(acpi_pci, acpi, 1, 1, 1);
MODULE_DEPEND(acpi_pci, pci, 1, 1, 1);
MODULE_VERSION(acpi_pci, 1);
static struct pci_devinfo *
acpi_pci_alloc_devinfo(device_t dev)
{
struct acpi_pci_devinfo *dinfo;
dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
return (&dinfo->ap_dinfo);
}
static int
acpi_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
@ -298,38 +299,6 @@ void
acpi_pci_child_added(device_t dev, device_t child)
{
AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
acpi_pci_save_handle, NULL, child, NULL);
}
static int
acpi_pci_probe(device_t dev)
{
if (acpi_get_handle(dev) == NULL)
return (ENXIO);
device_set_desc(dev, "ACPI PCI bus");
return (BUS_PROBE_DEFAULT);
}
static int
acpi_pci_attach(device_t dev)
{
int busno, domain, error;
error = pci_attach_common(dev);
if (error)
return (error);
/*
* Since there can be multiple independantly numbered PCI
* busses on systems with multiple PCI domains, we can't use
* the unit number to decide which bus we are probing. We ask
* the parent pcib what our domain and bus numbers are.
*/
domain = pcib_get_domain(dev);
busno = pcib_get_bus(dev);
/*
* PCI devices are added via the bus scan in the normal PCI
* bus driver. As each device is added, the
@ -342,9 +311,18 @@ acpi_pci_attach(device_t dev)
* pci_add_children() doesn't find. We currently just ignore
* these devices.
*/
pci_add_children(dev, domain, busno, sizeof(struct acpi_pci_devinfo));
AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
acpi_pci_save_handle, NULL, child, NULL);
}
return (bus_generic_attach(dev));
static int
acpi_pci_probe(device_t dev)
{
if (acpi_get_handle(dev) == NULL)
return (ENXIO);
device_set_desc(dev, "ACPI PCI bus");
return (BUS_PROBE_DEFAULT);
}
#ifdef ACPI_DMAR
@ -372,14 +350,3 @@ acpi_pci_get_dma_tag(device_t bus, device_t child)
}
#endif
#ifdef PCI_IOV
static device_t
acpi_pci_create_iov_child(device_t bus, device_t pf, uint16_t rid, uint16_t vid,
uint16_t did)
{
return (pci_add_iov_child(bus, pf, sizeof(struct acpi_pci_devinfo), rid,
vid, did));
}
#endif

View File

@ -169,6 +169,15 @@ cardbus_device_setup_regs(pcicfgregs *cfg)
pci_write_config(dev, PCIR_MAXLAT, 0x14, 1);
}
static struct pci_devinfo *
cardbus_alloc_devinfo(device_t dev)
{
struct cardbus_devinfo *dinfo;
dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
return (&dinfo->pci);
}
static int
cardbus_attach_card(device_t cbdev)
{
@ -191,8 +200,7 @@ cardbus_attach_card(device_t cbdev)
struct cardbus_devinfo *dinfo;
dinfo = (struct cardbus_devinfo *)
pci_read_device(brdev, domain, bus, slot, func,
sizeof(struct cardbus_devinfo));
pci_read_device(brdev, cbdev, domain, bus, slot, func);
if (dinfo == NULL)
continue;
if (dinfo->pci.cfg.mfdev)
@ -343,6 +351,9 @@ static device_method_t cardbus_methods[] = {
DEVMETHOD(card_attach_card, cardbus_attach_card),
DEVMETHOD(card_detach_card, cardbus_detach_card),
/* PCI interface */
DEVMETHOD(pci_alloc_devinfo, cardbus_alloc_devinfo),
{0,0}
};

View File

@ -126,8 +126,8 @@ static int pci_remap_intr_method(device_t bus, device_t dev,
static uint16_t pci_get_rid_method(device_t dev, device_t child);
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);
static struct pci_devinfo * pci_fill_devinfo(device_t pcib, device_t bus, int d,
int b, int s, int f, uint16_t vid, uint16_t did);
static device_method_t pci_methods[] = {
/* Device interface */
@ -196,6 +196,7 @@ static device_method_t pci_methods[] = {
DEVMETHOD(pci_msix_pba_bar, pci_msix_pba_bar_method),
DEVMETHOD(pci_msix_table_bar, pci_msix_table_bar_method),
DEVMETHOD(pci_get_rid, pci_get_rid_method),
DEVMETHOD(pci_alloc_devinfo, pci_alloc_devinfo_method),
DEVMETHOD(pci_child_added, pci_child_added_method),
#ifdef PCI_IOV
DEVMETHOD(pci_iov_attach, pci_iov_attach_method),
@ -619,7 +620,7 @@ pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
/* read configuration header into pcicfgregs structure */
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, device_t bus, int d, int b, int s, int f)
{
#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w)
uint16_t vid, did;
@ -627,19 +628,27 @@ pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
vid = REG(PCIR_VENDOR, 2);
did = REG(PCIR_DEVICE, 2);
if (vid != 0xffff)
return (pci_fill_devinfo(pcib, d, b, s, f, vid, did, size));
return (pci_fill_devinfo(pcib, bus, d, b, s, f, vid, did));
return (NULL);
}
struct pci_devinfo *
pci_alloc_devinfo_method(device_t dev)
{
return (malloc(sizeof(struct pci_devinfo), M_DEVBUF,
M_WAITOK | M_ZERO));
}
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)
pci_fill_devinfo(device_t pcib, device_t bus, int d, int b, int s, int f,
uint16_t vid, uint16_t did)
{
struct pci_devinfo *devlist_entry;
pcicfgregs *cfg;
devlist_entry = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
devlist_entry = PCI_ALLOC_DEVINFO(bus);
cfg = &devlist_entry->cfg;
@ -665,7 +674,6 @@ pci_fill_devinfo(device_t pcib, int d, int b, int s, int f, uint16_t vid,
cfg->hdrtype &= ~PCIM_MFDEV;
STAILQ_INIT(&cfg->maps);
cfg->devinfo_size = size;
cfg->iov = NULL;
pci_fixancient(cfg);
@ -3854,11 +3862,11 @@ pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask)
static struct pci_devinfo *
pci_identify_function(device_t pcib, device_t dev, int domain, int busno,
int slot, int func, size_t dinfo_size)
int slot, int func)
{
struct pci_devinfo *dinfo;
dinfo = pci_read_device(pcib, domain, busno, slot, func, dinfo_size);
dinfo = pci_read_device(pcib, dev, domain, busno, slot, func);
if (dinfo != NULL)
pci_add_child(dev, dinfo);
@ -3866,7 +3874,7 @@ pci_identify_function(device_t pcib, device_t dev, int domain, int busno,
}
void
pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size)
pci_add_children(device_t dev, int domain, int busno)
{
#define REG(n, w) PCIB_READ_CONFIG(pcib, busno, s, f, n, w)
device_t pcib = device_get_parent(dev);
@ -3882,8 +3890,7 @@ pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size)
* functions on this bus as ARI changes the set of slots and functions
* that are legal on this bus.
*/
dinfo = pci_identify_function(pcib, dev, domain, busno, 0, 0,
dinfo_size);
dinfo = pci_identify_function(pcib, dev, domain, busno, 0, 0);
if (dinfo != NULL && pci_enable_ari)
PCIB_TRY_ENABLE_ARI(pcib, dinfo->cfg.dev);
@ -3893,8 +3900,6 @@ pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size)
*/
first_func = 1;
KASSERT(dinfo_size >= sizeof(struct pci_devinfo),
("dinfo_size too small"));
maxslots = PCIB_MAXSLOTS(pcib);
for (s = 0; s <= maxslots; s++, first_func = 0) {
pcifunchigh = 0;
@ -3906,16 +3911,15 @@ pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size)
if (hdrtype & PCIM_MFDEV)
pcifunchigh = PCIB_MAXFUNCS(pcib);
for (f = first_func; f <= pcifunchigh; f++)
pci_identify_function(pcib, dev, domain, busno, s, f,
dinfo_size);
pci_identify_function(pcib, dev, domain, busno, s, f);
}
#undef REG
}
#ifdef PCI_IOV
device_t
pci_add_iov_child(device_t bus, device_t pf, size_t size, uint16_t rid,
uint16_t vid, uint16_t did)
pci_add_iov_child(device_t bus, device_t pf, uint16_t rid, uint16_t vid,
uint16_t did)
{
struct pci_devinfo *pf_dinfo, *vf_dinfo;
device_t pcib;
@ -3923,23 +3927,12 @@ pci_add_iov_child(device_t bus, device_t pf, size_t size, uint16_t rid,
pf_dinfo = device_get_ivars(pf);
/*
* Do a sanity check that we have been passed the correct size. If this
* test fails then likely the pci subclass hasn't implemented the
* pci_create_iov_child method like it's supposed it.
*/
if (size != pf_dinfo->cfg.devinfo_size) {
device_printf(pf,
"PCI subclass does not properly implement PCI_IOV\n");
return (NULL);
}
pcib = device_get_parent(bus);
PCIB_DECODE_RID(pcib, rid, &busno, &slot, &func);
vf_dinfo = pci_fill_devinfo(pcib, pci_get_domain(pcib), busno, slot, func,
vid, did, size);
vf_dinfo = pci_fill_devinfo(pcib, bus, pci_get_domain(pcib), busno,
slot, func, vid, did);
vf_dinfo->cfg.flags |= PCICFG_VF;
pci_add_child(bus, vf_dinfo);
@ -3952,8 +3945,7 @@ pci_create_iov_child_method(device_t bus, device_t pf, uint16_t rid,
uint16_t vid, uint16_t did)
{
return (pci_add_iov_child(bus, pf, sizeof(struct pci_devinfo), rid, vid,
did));
return (pci_add_iov_child(bus, pf, rid, vid, did));
}
#endif
@ -4050,7 +4042,7 @@ pci_attach(device_t dev)
*/
domain = pcib_get_domain(dev);
busno = pcib_get_bus(dev);
pci_add_children(dev, domain, busno, sizeof(struct pci_devinfo));
pci_add_children(dev, domain, busno);
return (bus_generic_attach(dev));
}

View File

@ -213,6 +213,10 @@ METHOD uint16_t get_rid {
device_t child;
};
METHOD struct pci_devinfo * alloc_devinfo {
device_t dev;
};
METHOD void child_added {
device_t dev;
device_t child;

View File

@ -600,14 +600,12 @@ pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config,
device_t bus, dev, vf;
struct pcicfg_iov *iov;
struct pci_devinfo *vfinfo;
size_t size;
int i, error;
uint16_t vid, did, next_rid;
iov = dinfo->cfg.iov;
dev = dinfo->cfg.dev;
bus = device_get_parent(dev);
size = dinfo->cfg.devinfo_size;
next_rid = first_rid;
vid = pci_get_vendor(dev);
did = IOV_READ(dinfo, PCIR_SRIOV_VF_DID, 2);

View File

@ -48,14 +48,14 @@ struct pci_softc {
extern int pci_do_power_resume;
extern int pci_do_power_suspend;
void pci_add_children(device_t dev, int domain, int busno,
size_t dinfo_size);
void pci_add_children(device_t dev, int domain, int busno);
void pci_add_child(device_t bus, struct pci_devinfo *dinfo);
device_t pci_add_iov_child(device_t bus, device_t pf, size_t dinfo_size,
uint16_t rid, uint16_t vid, uint16_t did);
device_t pci_add_iov_child(device_t bus, device_t pf, uint16_t rid,
uint16_t vid, uint16_t did);
void pci_add_resources(device_t bus, device_t dev, int force,
uint32_t prefetchmask);
void pci_add_resources_ea(device_t bus, device_t dev, int alloc_iov);
struct pci_devinfo *pci_alloc_devinfo_method(device_t dev);
int pci_attach_common(device_t dev);
void pci_driver_added(device_t dev, driver_t *driver);
int pci_ea_is_enabled(device_t dev, int rid);
@ -117,8 +117,8 @@ int pci_deactivate_resource(device_t dev, device_t child, int type,
void pci_delete_resource(device_t dev, device_t child,
int type, int rid);
struct resource_list *pci_get_resource_list (device_t dev, device_t child);
struct pci_devinfo *pci_read_device(device_t pcib, int d, int b, int s, int f,
size_t size);
struct pci_devinfo *pci_read_device(device_t pcib, device_t bus, int d, int b,
int s, int f);
void pci_print_verbose(struct pci_devinfo *dinfo);
int pci_freecfg(struct pci_devinfo *dinfo);
void pci_child_deleted(device_t dev, device_t child);

View File

@ -209,7 +209,6 @@ typedef struct pcicfg {
uint8_t func; /* config space function number */
uint32_t flags; /* flags defined above */
size_t devinfo_size; /* Size of devinfo for this bus type. */
struct pcicfg_bridge bridge; /* Bridges */
struct pcicfg_pp pp; /* Power management */

View File

@ -125,8 +125,8 @@ xlp_pci_attach(device_t dev)
XLP_PCI_DEVSCRATCH_REG0 << 2,
(1 << 8) | irq, 4);
}
dinfo = pci_read_device(pcib, pcib_get_domain(dev),
busno, s, f, sizeof(*dinfo));
dinfo = pci_read_device(pcib, dev, pcib_get_domain(dev),
busno, s, f);
pci_add_child(dev, dinfo);
}
}

View File

@ -59,6 +59,7 @@ typedef uint32_t ofw_pci_intr_t;
/* Methods */
static device_probe_t ofw_pcibus_probe;
static device_attach_t ofw_pcibus_attach;
static pci_alloc_devinfo_t ofw_pcibus_alloc_devinfo;
static pci_assign_interrupt_t ofw_pcibus_assign_interrupt;
static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo;
static bus_child_deleted_t ofw_pcibus_child_deleted;
@ -78,6 +79,7 @@ static device_method_t ofw_pcibus_methods[] = {
DEVMETHOD(bus_child_pnpinfo_str, ofw_pcibus_child_pnpinfo_str_method),
/* PCI interface */
DEVMETHOD(pci_alloc_devinfo, ofw_pcibus_alloc_devinfo),
DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt),
/* ofw_bus interface */
@ -144,6 +146,15 @@ ofw_pcibus_attach(device_t dev)
return (bus_generic_attach(dev));
}
struct pci_devinfo *
ofw_pcibus_alloc_devinfo(device_t dev)
{
struct ofw_pcibus_devinfo *dinfo;
dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
return (&dinfo->opd_dinfo);
}
static void
ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
{
@ -185,8 +196,8 @@ ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
* to the PCI bus.
*/
dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
domain, busno, slot, func, sizeof(*dinfo));
dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, dev,
domain, busno, slot, func);
if (dinfo == NULL)
continue;
if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
@ -244,7 +255,7 @@ ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno)
continue;
dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(
pcib, domain, busno, s, f, sizeof(*dinfo));
pcib, dev, domain, busno, s, f);
if (dinfo == NULL)
continue;

View File

@ -70,6 +70,7 @@ static bus_child_pnpinfo_str_t ofw_pcibus_pnpinfo_str;
static device_attach_t ofw_pcibus_attach;
static device_probe_t ofw_pcibus_probe;
static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo;
static pci_alloc_devinfo_t ofw_pcibus_alloc_devinfo;
static pci_assign_interrupt_t ofw_pcibus_assign_interrupt;
static device_method_t ofw_pcibus_methods[] = {
@ -82,6 +83,7 @@ static device_method_t ofw_pcibus_methods[] = {
DEVMETHOD(bus_child_pnpinfo_str, ofw_pcibus_pnpinfo_str),
/* PCI interface */
DEVMETHOD(pci_alloc_devinfo, ofw_pcibus_alloc_devinfo),
DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt),
/* ofw_bus interface */
@ -250,8 +252,8 @@ ofw_pcibus_attach(device_t dev)
if (strcmp(device_get_name(device_get_parent(pcib)), "nexus") == 0 &&
ofw_bus_get_type(pcib) != NULL &&
strcmp(ofw_bus_get_type(pcib), OFW_TYPE_PCIE) != 0 &&
(dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
domain, busno, 0, 0, sizeof(*dinfo))) != NULL) {
(dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, dev,
domain, busno, 0, 0)) != NULL) {
if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0)
pci_freecfg((struct pci_devinfo *)dinfo);
else
@ -270,8 +272,8 @@ ofw_pcibus_attach(device_t dev)
if (pci_find_dbsf(domain, busno, slot, func) != NULL)
continue;
ofw_pcibus_setup_device(pcib, clock, busno, slot, func);
dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
domain, busno, slot, func, sizeof(*dinfo));
dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, dev,
domain, busno, slot, func);
if (dinfo == NULL)
continue;
if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
@ -286,6 +288,15 @@ ofw_pcibus_attach(device_t dev)
return (bus_generic_attach(dev));
}
struct pci_devinfo *
ofw_pcibus_alloc_devinfo(device_t dev)
{
struct ofw_pcibus_devinfo *dinfo;
dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
return (&dinfo->opd_dinfo);
}
static int
ofw_pcibus_assign_interrupt(device_t dev, device_t child)
{