diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-02-23 22:18:59 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-02-23 22:18:59 -0500 |
commit | 5a21d70dbd33d20713fb735ad9381711b0ae2c9b (patch) | |
tree | f3c6c65295f1356f62389fafad777d7be047aca5 | |
parent | a5390aa6dc3646b08bed421944cef0daf78ab994 (diff) |
PCI: add struct pci_host_bridge and a list of all bridges found
This adds a list of all PCI host bridges we find and a way to look up
the host bridge from a pci_dev.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r-- | drivers/pci/probe.c | 39 | ||||
-rw-r--r-- | include/linux/pci.h | 5 |
2 files changed, 39 insertions, 5 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e4c0d1c6324d..3a30023a123c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -15,6 +15,8 @@ | |||
15 | #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ | 15 | #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ |
16 | #define CARDBUS_RESERVE_BUSNR 3 | 16 | #define CARDBUS_RESERVE_BUSNR 3 |
17 | 17 | ||
18 | static LIST_HEAD(pci_host_bridges); | ||
19 | |||
18 | /* Ugh. Need to stop exporting this to modules. */ | 20 | /* Ugh. Need to stop exporting this to modules. */ |
19 | LIST_HEAD(pci_root_buses); | 21 | LIST_HEAD(pci_root_buses); |
20 | EXPORT_SYMBOL(pci_root_buses); | 22 | EXPORT_SYMBOL(pci_root_buses); |
@@ -42,6 +44,23 @@ int no_pci_devices(void) | |||
42 | } | 44 | } |
43 | EXPORT_SYMBOL(no_pci_devices); | 45 | EXPORT_SYMBOL(no_pci_devices); |
44 | 46 | ||
47 | static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev) | ||
48 | { | ||
49 | struct pci_bus *bus; | ||
50 | struct pci_host_bridge *bridge; | ||
51 | |||
52 | bus = dev->bus; | ||
53 | while (bus->parent) | ||
54 | bus = bus->parent; | ||
55 | |||
56 | list_for_each_entry(bridge, &pci_host_bridges, list) { | ||
57 | if (bridge->bus == bus) | ||
58 | return bridge; | ||
59 | } | ||
60 | |||
61 | return NULL; | ||
62 | } | ||
63 | |||
45 | /* | 64 | /* |
46 | * PCI Bus Class | 65 | * PCI Bus Class |
47 | */ | 66 | */ |
@@ -1544,20 +1563,23 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1544 | struct pci_ops *ops, void *sysdata, struct list_head *resources) | 1563 | struct pci_ops *ops, void *sysdata, struct list_head *resources) |
1545 | { | 1564 | { |
1546 | int error, i; | 1565 | int error, i; |
1566 | struct pci_host_bridge *bridge; | ||
1547 | struct pci_bus *b, *b2; | 1567 | struct pci_bus *b, *b2; |
1548 | struct device *dev; | 1568 | struct device *dev; |
1549 | struct pci_bus_resource *bus_res, *n; | 1569 | struct pci_bus_resource *bus_res, *n; |
1550 | struct resource *res; | 1570 | struct resource *res; |
1551 | 1571 | ||
1572 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); | ||
1573 | if (!bridge) | ||
1574 | return NULL; | ||
1575 | |||
1552 | b = pci_alloc_bus(); | 1576 | b = pci_alloc_bus(); |
1553 | if (!b) | 1577 | if (!b) |
1554 | return NULL; | 1578 | goto err_bus; |
1555 | 1579 | ||
1556 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 1580 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
1557 | if (!dev) { | 1581 | if (!dev) |
1558 | kfree(b); | 1582 | goto err_dev; |
1559 | return NULL; | ||
1560 | } | ||
1561 | 1583 | ||
1562 | b->sysdata = sysdata; | 1584 | b->sysdata = sysdata; |
1563 | b->ops = ops; | 1585 | b->ops = ops; |
@@ -1594,6 +1616,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1594 | 1616 | ||
1595 | b->number = b->secondary = bus; | 1617 | b->number = b->secondary = bus; |
1596 | 1618 | ||
1619 | bridge->bus = b; | ||
1620 | |||
1597 | /* Add initial resources to the bus */ | 1621 | /* Add initial resources to the bus */ |
1598 | list_for_each_entry_safe(bus_res, n, resources, list) | 1622 | list_for_each_entry_safe(bus_res, n, resources, list) |
1599 | list_move_tail(&bus_res->list, &b->resources); | 1623 | list_move_tail(&bus_res->list, &b->resources); |
@@ -1609,6 +1633,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1609 | } | 1633 | } |
1610 | 1634 | ||
1611 | down_write(&pci_bus_sem); | 1635 | down_write(&pci_bus_sem); |
1636 | list_add_tail(&bridge->list, &pci_host_bridges); | ||
1612 | list_add_tail(&b->node, &pci_root_buses); | 1637 | list_add_tail(&b->node, &pci_root_buses); |
1613 | up_write(&pci_bus_sem); | 1638 | up_write(&pci_bus_sem); |
1614 | 1639 | ||
@@ -1618,11 +1643,15 @@ class_dev_reg_err: | |||
1618 | device_unregister(dev); | 1643 | device_unregister(dev); |
1619 | dev_reg_err: | 1644 | dev_reg_err: |
1620 | down_write(&pci_bus_sem); | 1645 | down_write(&pci_bus_sem); |
1646 | list_del(&bridge->list); | ||
1621 | list_del(&b->node); | 1647 | list_del(&b->node); |
1622 | up_write(&pci_bus_sem); | 1648 | up_write(&pci_bus_sem); |
1623 | err_out: | 1649 | err_out: |
1624 | kfree(dev); | 1650 | kfree(dev); |
1651 | err_dev: | ||
1625 | kfree(b); | 1652 | kfree(b); |
1653 | err_bus: | ||
1654 | kfree(bridge); | ||
1626 | return NULL; | 1655 | return NULL; |
1627 | } | 1656 | } |
1628 | 1657 | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index bcaa51ca7858..2c946b3bbf77 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -368,6 +368,11 @@ static inline int pci_channel_offline(struct pci_dev *pdev) | |||
368 | return (pdev->error_state != pci_channel_io_normal); | 368 | return (pdev->error_state != pci_channel_io_normal); |
369 | } | 369 | } |
370 | 370 | ||
371 | struct pci_host_bridge { | ||
372 | struct list_head list; | ||
373 | struct pci_bus *bus; /* root bus */ | ||
374 | }; | ||
375 | |||
371 | /* | 376 | /* |
372 | * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond | 377 | * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond |
373 | * to P2P or CardBus bridge windows) go in a table. Additional ones (for | 378 | * to P2P or CardBus bridge windows) go in a table. Additional ones (for |