Skip to content

Commit

Permalink
[PATCH] PCI: clean up dynamic pci id logic
Browse files Browse the repository at this point in the history
The dynamic pci id logic has been bothering me for a while, and now that
I started to look into how to move some of this to the driver core, I
thought it was time to clean it all up.

It ends up making the code smaller, and easier to follow, and fixes a
few bugs at the same time (dynamic ids were not being matched
everywhere, and so could be missed on some call paths for new devices,
semaphore not needed to be grabbed when adding a new id and calling the
driver core, etc.)

I also renamed the function pci_match_device() to pci_match_id() as
that's what it really does.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Greg Kroah-Hartman committed Jul 1, 2005
1 parent 299de03 commit 7586585
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 150 deletions.
2 changes: 1 addition & 1 deletion arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ static __init struct pci_dev *gx_detect_chipset(void)

/* detect which companion chip is used */
while ((gx_pci = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) {
if ((pci_match_device (gx_chipset_tbl, gx_pci)) != NULL) {
if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL) {
return gx_pci;
}
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/hw_random.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ static int __init rng_init (void)

/* Probe for Intel, AMD RNGs */
for_each_pci_dev(pdev) {
ent = pci_match_device (rng_pci_tbl, pdev);
ent = pci_match_id(rng_pci_tbl, pdev);
if (ent) {
rng_ops = &rng_vendor_ops[ent->driver_data];
goto match;
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/watchdog/i8xx_tco.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
*/

while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (pci_match_device(i8xx_tco_pci_tbl, dev)) {
if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
i8xx_tco_pci = dev;
break;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/ide/setup-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev)
d = list_entry(l, struct pci_driver, node);
if(d->id_table)
{
const struct pci_device_id *id = pci_match_device(d->id_table, dev);
const struct pci_device_id *id = pci_match_id(d->id_table, dev);
if(id != NULL)
{
if(d->probe(dev, id) >= 0)
Expand Down
2 changes: 1 addition & 1 deletion drivers/parport/parport_pc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3008,7 +3008,7 @@ static int __init parport_pc_init_superio (int autoirq, int autodma)
int ret = 0;

while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
id = pci_match_device (parport_pc_pci_tbl, pdev);
id = pci_match_id(parport_pc_pci_tbl, pdev);
if (id == NULL || id->driver_data >= last_sio)
continue;

Expand Down
196 changes: 71 additions & 125 deletions drivers/pci/pci-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/pci-dynids.h>
#include "pci.h"

/*
Expand All @@ -19,35 +18,11 @@
*/

#ifdef CONFIG_HOTPLUG
/**
* pci_device_probe_dynamic()
*
* Walk the dynamic ID list looking for a match.
* returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
*/
static int
pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
{
int error = -ENODEV;
struct list_head *pos;
struct dynid *dynid;

spin_lock(&drv->dynids.lock);
list_for_each(pos, &drv->dynids.list) {
dynid = list_entry(pos, struct dynid, node);
if (pci_match_one_device(&dynid->id, pci_dev)) {
spin_unlock(&drv->dynids.lock);
error = drv->probe(pci_dev, &dynid->id);
if (error >= 0) {
pci_dev->driver = drv;
return 0;
}
return error;
}
}
spin_unlock(&drv->dynids.lock);
return error;
}
struct pci_dynid {
struct list_head node;
struct pci_device_id id;
};

/**
* store_new_id
Expand All @@ -58,8 +33,7 @@ pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
static inline ssize_t
store_new_id(struct device_driver *driver, const char *buf, size_t count)
{
struct dynid *dynid;
struct bus_type * bus;
struct pci_dynid *dynid;
struct pci_driver *pdrv = to_pci_driver(driver);
__u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID,
subdevice=PCI_ANY_ID, class=0, class_mask=0;
Expand Down Expand Up @@ -91,37 +65,22 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
list_add_tail(&pdrv->dynids.list, &dynid->node);
spin_unlock(&pdrv->dynids.lock);

bus = get_bus(pdrv->driver.bus);
if (bus) {
if (get_driver(&pdrv->driver)) {
down_write(&bus->subsys.rwsem);
driver_attach(&pdrv->driver);
up_write(&bus->subsys.rwsem);
put_driver(&pdrv->driver);
}
put_bus(bus);
if (get_driver(&pdrv->driver)) {
driver_attach(&pdrv->driver);
put_driver(&pdrv->driver);
}

return count;
}

static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
static inline void
pci_init_dynids(struct pci_dynids *dynids)
{
spin_lock_init(&dynids->lock);
INIT_LIST_HEAD(&dynids->list);
}

static void
pci_free_dynids(struct pci_driver *drv)
{
struct list_head *pos, *n;
struct dynid *dynid;
struct pci_dynid *dynid, *n;

spin_lock(&drv->dynids.lock);
list_for_each_safe(pos, n, &drv->dynids.list) {
dynid = list_entry(pos, struct dynid, node);
list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
Expand All @@ -138,83 +97,70 @@ pci_create_newid_file(struct pci_driver *drv)
return error;
}

static int
pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
{
struct list_head *pos;
struct dynid *dynid;

spin_lock(&pci_drv->dynids.lock);
list_for_each(pos, &pci_drv->dynids.list) {
dynid = list_entry(pos, struct dynid, node);
if (pci_match_one_device(&dynid->id, pci_dev)) {
spin_unlock(&pci_drv->dynids.lock);
return 1;
}
}
spin_unlock(&pci_drv->dynids.lock);
return 0;
}

#else /* !CONFIG_HOTPLUG */
static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
{
return -ENODEV;
}
static inline void pci_init_dynids(struct pci_dynids *dynids) {}
static inline void pci_free_dynids(struct pci_driver *drv) {}
static inline int pci_create_newid_file(struct pci_driver *drv)
{
return 0;
}
static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
{
return 0;
}
#endif

/**
* pci_match_device - Tell if a PCI device structure has a matching
* PCI device id structure
* pci_match_id - See if a pci device matches a given pci_id table
* @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against
*
* @dev: the PCI device structure to match against.
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices.Returns the matching
* system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
*
* Depreciated, don't use this as it will not catch any dynamic ids
* that a driver might want to check for.
*/
const struct pci_device_id *
pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
struct pci_dev *dev)
{
while (ids->vendor || ids->subvendor || ids->class_mask) {
if (pci_match_one_device(ids, dev))
return ids;
ids++;
if (ids) {
while (ids->vendor || ids->subvendor || ids->class_mask) {
if (pci_match_one_device(ids, dev))
return ids;
ids++;
}
}
return NULL;
}

/**
* pci_device_probe_static()
*
* returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
* pci_match_device - Tell if a PCI device structure has a matching
* PCI device id structure
* @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against
* @drv: the PCI driver to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
static int
pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev)
{
int error = -ENODEV;
const struct pci_device_id *pci_match_device(struct pci_driver *drv,
struct pci_dev *dev)
{
const struct pci_device_id *id;
struct pci_dynid *dynid;

if (!drv->id_table)
return error;
id = pci_match_device(drv->id_table, pci_dev);
id = pci_match_id(drv->id_table, dev);
if (id)
error = drv->probe(pci_dev, id);
if (error >= 0) {
pci_dev->driver = drv;
error = 0;
return id;

/* static ids didn't match, lets look at the dynamic ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (pci_match_one_device(&dynid->id, dev)) {
spin_unlock(&drv->dynids.lock);
return &dynid->id;
}
}
return error;
spin_unlock(&drv->dynids.lock);
return NULL;
}

/**
Expand All @@ -225,13 +171,20 @@ pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev)
*/
static int
__pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
{
{
const struct pci_device_id *id;
int error = 0;

if (!pci_dev->driver && drv->probe) {
error = pci_device_probe_static(drv, pci_dev);
if (error == -ENODEV)
error = pci_device_probe_dynamic(drv, pci_dev);
error = -ENODEV;

id = pci_match_device(drv, pci_dev);
if (id)
error = drv->probe(pci_dev, id);
if (error >= 0) {
pci_dev->driver = drv;
error = 0;
}
}
return error;
}
Expand Down Expand Up @@ -371,12 +324,6 @@ static struct kobj_type pci_driver_kobj_type = {
.sysfs_ops = &pci_driver_sysfs_ops,
};

static int
pci_populate_driver_dir(struct pci_driver *drv)
{
return pci_create_newid_file(drv);
}

/**
* pci_register_driver - register a new pci driver
* @drv: the driver structure to register
Expand All @@ -401,13 +348,15 @@ int pci_register_driver(struct pci_driver *drv)
drv->driver.shutdown = pci_device_shutdown;
drv->driver.owner = drv->owner;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
pci_init_dynids(&drv->dynids);

spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list);

/* register with core */
error = driver_register(&drv->driver);

if (!error)
pci_populate_driver_dir(drv);
error = pci_create_newid_file(drv);

return error;
}
Expand Down Expand Up @@ -463,21 +412,17 @@ pci_dev_driver(const struct pci_dev *dev)
* system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
static int pci_bus_match(struct device * dev, struct device_driver * drv)
static int pci_bus_match(struct device *dev, struct device_driver *drv)
{
const struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * pci_drv = to_pci_driver(drv);
const struct pci_device_id * ids = pci_drv->id_table;
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *pci_drv = to_pci_driver(drv);
const struct pci_device_id *found_id;

if (!ids)
return 0;

found_id = pci_match_device(ids, pci_dev);
found_id = pci_match_device(pci_drv, pci_dev);
if (found_id)
return 1;

return pci_bus_match_dynids(pci_dev, pci_drv);
return 0;
}

/**
Expand Down Expand Up @@ -536,6 +481,7 @@ static int __init pci_driver_init(void)

postcore_initcall(pci_driver_init);

EXPORT_SYMBOL(pci_match_id);
EXPORT_SYMBOL(pci_match_device);
EXPORT_SYMBOL(pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver);
Expand Down
18 changes: 0 additions & 18 deletions include/linux/pci-dynids.h

This file was deleted.

3 changes: 2 additions & 1 deletion include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,8 @@ int pci_register_driver(struct pci_driver *);
void pci_unregister_driver(struct pci_driver *);
void pci_remove_behind_bridge(struct pci_dev *);
struct pci_driver *pci_dev_driver(const struct pci_dev *);
const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev);
const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev);
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);

/* kmem_cache style wrapper around pci_alloc_consistent() */
Expand Down
2 changes: 1 addition & 1 deletion sound/pci/bt87x.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
int i;
const struct pci_device_id *supported;

supported = pci_match_device(snd_bt87x_ids, pci);
supported = pci_match_device(driver, pci);
if (supported)
return supported->driver_data;

Expand Down

0 comments on commit 7586585

Please sign in to comment.