aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-04-30 18:55:58 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-04-30 18:55:58 -0400
commit29473ec23aa79d401ffe06ec3f3ad3755382be13 (patch)
tree67b136cee8c5f407db94a73cb950ca421fba5759 /drivers/pci
parent977f857ca566a1e68045fcbb7cfc9c4acb077cf0 (diff)
parentc57ca65a6ea3171370cbb3010e5a3aea7399a5e1 (diff)
Merge branch 'topic/yinghai-hostbridge-cleanup' into next
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/host-bridge.c96
-rw-r--r--drivers/pci/probe.c146
3 files changed, 133 insertions, 111 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 083a49fee56a..2c224edae1ac 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the PCI bus specific drivers. 2# Makefile for the PCI bus specific drivers.
3# 3#
4 4
5obj-y += access.o bus.o probe.o remove.o pci.o \ 5obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
6 pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ 6 pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
7 irq.o vpd.o 7 irq.o vpd.o
8obj-$(CONFIG_PROC_FS) += proc.o 8obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
new file mode 100644
index 000000000000..a68dc613a5be
--- /dev/null
+++ b/drivers/pci/host-bridge.c
@@ -0,0 +1,96 @@
1/*
2 * host bridge related code
3 */
4
5#include <linux/kernel.h>
6#include <linux/init.h>
7#include <linux/pci.h>
8#include <linux/module.h>
9
10#include "pci.h"
11
12static struct pci_bus *find_pci_root_bus(struct pci_dev *dev)
13{
14 struct pci_bus *bus;
15
16 bus = dev->bus;
17 while (bus->parent)
18 bus = bus->parent;
19
20 return bus;
21}
22
23static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev)
24{
25 struct pci_bus *bus = find_pci_root_bus(dev);
26
27 return to_pci_host_bridge(bus->bridge);
28}
29
30void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
31 void (*release_fn)(struct pci_host_bridge *),
32 void *release_data)
33{
34 bridge->release_fn = release_fn;
35 bridge->release_data = release_data;
36}
37
38static bool resource_contains(struct resource *res1, struct resource *res2)
39{
40 return res1->start <= res2->start && res1->end >= res2->end;
41}
42
43void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
44 struct resource *res)
45{
46 struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
47 struct pci_host_bridge_window *window;
48 resource_size_t offset = 0;
49
50 list_for_each_entry(window, &bridge->windows, list) {
51 if (resource_type(res) != resource_type(window->res))
52 continue;
53
54 if (resource_contains(window->res, res)) {
55 offset = window->offset;
56 break;
57 }
58 }
59
60 region->start = res->start - offset;
61 region->end = res->end - offset;
62}
63EXPORT_SYMBOL(pcibios_resource_to_bus);
64
65static bool region_contains(struct pci_bus_region *region1,
66 struct pci_bus_region *region2)
67{
68 return region1->start <= region2->start && region1->end >= region2->end;
69}
70
71void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
72 struct pci_bus_region *region)
73{
74 struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
75 struct pci_host_bridge_window *window;
76 resource_size_t offset = 0;
77
78 list_for_each_entry(window, &bridge->windows, list) {
79 struct pci_bus_region bus_region;
80
81 if (resource_type(res) != resource_type(window->res))
82 continue;
83
84 bus_region.start = window->res->start - window->offset;
85 bus_region.end = window->res->end - window->offset;
86
87 if (region_contains(&bus_region, region)) {
88 offset = window->offset;
89 break;
90 }
91 }
92
93 res->start = region->start + offset;
94 res->end = region->end + offset;
95}
96EXPORT_SYMBOL(pcibios_bus_to_resource);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5e1ca3c58a7d..4c2f22668ea7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -15,13 +15,10 @@
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
18static LIST_HEAD(pci_host_bridges);
19
20/* Ugh. Need to stop exporting this to modules. */ 18/* Ugh. Need to stop exporting this to modules. */
21LIST_HEAD(pci_root_buses); 19LIST_HEAD(pci_root_buses);
22EXPORT_SYMBOL(pci_root_buses); 20EXPORT_SYMBOL(pci_root_buses);
23 21
24
25static int find_anything(struct device *dev, void *data) 22static int find_anything(struct device *dev, void *data)
26{ 23{
27 return 1; 24 return 1;
@@ -44,82 +41,6 @@ int no_pci_devices(void)
44} 41}
45EXPORT_SYMBOL(no_pci_devices); 42EXPORT_SYMBOL(no_pci_devices);
46 43
47static 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
64static bool resource_contains(struct resource *res1, struct resource *res2)
65{
66 return res1->start <= res2->start && res1->end >= res2->end;
67}
68
69void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
70 struct resource *res)
71{
72 struct pci_host_bridge *bridge = pci_host_bridge(dev);
73 struct pci_host_bridge_window *window;
74 resource_size_t offset = 0;
75
76 list_for_each_entry(window, &bridge->windows, list) {
77 if (resource_type(res) != resource_type(window->res))
78 continue;
79
80 if (resource_contains(window->res, res)) {
81 offset = window->offset;
82 break;
83 }
84 }
85
86 region->start = res->start - offset;
87 region->end = res->end - offset;
88}
89EXPORT_SYMBOL(pcibios_resource_to_bus);
90
91static bool region_contains(struct pci_bus_region *region1,
92 struct pci_bus_region *region2)
93{
94 return region1->start <= region2->start && region1->end >= region2->end;
95}
96
97void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
98 struct pci_bus_region *region)
99{
100 struct pci_host_bridge *bridge = pci_host_bridge(dev);
101 struct pci_host_bridge_window *window;
102 struct pci_bus_region bus_region;
103 resource_size_t offset = 0;
104
105 list_for_each_entry(window, &bridge->windows, list) {
106 if (resource_type(res) != resource_type(window->res))
107 continue;
108
109 bus_region.start = window->res->start - window->offset;
110 bus_region.end = window->res->end - window->offset;
111
112 if (region_contains(&bus_region, region)) {
113 offset = window->offset;
114 break;
115 }
116 }
117
118 res->start = region->start + offset;
119 res->end = region->end + offset;
120}
121EXPORT_SYMBOL(pcibios_bus_to_resource);
122
123/* 44/*
124 * PCI Bus Class 45 * PCI Bus Class
125 */ 46 */
@@ -501,6 +422,19 @@ static struct pci_bus * pci_alloc_bus(void)
501 return b; 422 return b;
502} 423}
503 424
425static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
426{
427 struct pci_host_bridge *bridge;
428
429 bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
430 if (bridge) {
431 INIT_LIST_HEAD(&bridge->windows);
432 bridge->bus = b;
433 }
434
435 return bridge;
436}
437
504static unsigned char pcix_bus_speed[] = { 438static unsigned char pcix_bus_speed[] = {
505 PCI_SPEED_UNKNOWN, /* 0 */ 439 PCI_SPEED_UNKNOWN, /* 0 */
506 PCI_SPEED_66MHz_PCIX, /* 1 */ 440 PCI_SPEED_66MHz_PCIX, /* 1 */
@@ -1201,7 +1135,14 @@ int pci_cfg_space_size(struct pci_dev *dev)
1201 1135
1202static void pci_release_bus_bridge_dev(struct device *dev) 1136static void pci_release_bus_bridge_dev(struct device *dev)
1203{ 1137{
1204 kfree(dev); 1138 struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
1139
1140 if (bridge->release_fn)
1141 bridge->release_fn(bridge);
1142
1143 pci_free_resource_list(&bridge->windows);
1144
1145 kfree(bridge);
1205} 1146}
1206 1147
1207struct pci_dev *alloc_pci_dev(void) 1148struct pci_dev *alloc_pci_dev(void)
@@ -1650,28 +1591,19 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
1650 int error; 1591 int error;
1651 struct pci_host_bridge *bridge; 1592 struct pci_host_bridge *bridge;
1652 struct pci_bus *b, *b2; 1593 struct pci_bus *b, *b2;
1653 struct device *dev;
1654 struct pci_host_bridge_window *window, *n; 1594 struct pci_host_bridge_window *window, *n;
1655 struct resource *res; 1595 struct resource *res;
1656 resource_size_t offset; 1596 resource_size_t offset;
1657 char bus_addr[64]; 1597 char bus_addr[64];
1658 char *fmt; 1598 char *fmt;
1659 1599
1660 bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
1661 if (!bridge)
1662 return NULL;
1663 1600
1664 b = pci_alloc_bus(); 1601 b = pci_alloc_bus();
1665 if (!b) 1602 if (!b)
1666 goto err_bus; 1603 return NULL;
1667
1668 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1669 if (!dev)
1670 goto err_dev;
1671 1604
1672 b->sysdata = sysdata; 1605 b->sysdata = sysdata;
1673 b->ops = ops; 1606 b->ops = ops;
1674
1675 b2 = pci_find_bus(pci_domain_nr(b), bus); 1607 b2 = pci_find_bus(pci_domain_nr(b), bus);
1676 if (b2) { 1608 if (b2) {
1677 /* If we already got to this bus through a different bridge, ignore it */ 1609 /* If we already got to this bus through a different bridge, ignore it */
@@ -1679,13 +1611,17 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
1679 goto err_out; 1611 goto err_out;
1680 } 1612 }
1681 1613
1682 dev->parent = parent; 1614 bridge = pci_alloc_host_bridge(b);
1683 dev->release = pci_release_bus_bridge_dev; 1615 if (!bridge)
1684 dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus); 1616 goto err_out;
1685 error = device_register(dev); 1617
1618 bridge->dev.parent = parent;
1619 bridge->dev.release = pci_release_bus_bridge_dev;
1620 dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
1621 error = device_register(&bridge->dev);
1686 if (error) 1622 if (error)
1687 goto dev_reg_err; 1623 goto bridge_dev_reg_err;
1688 b->bridge = get_device(dev); 1624 b->bridge = get_device(&bridge->dev);
1689 device_enable_async_suspend(b->bridge); 1625 device_enable_async_suspend(b->bridge);
1690 pci_set_bus_of_node(b); 1626 pci_set_bus_of_node(b);
1691 1627
@@ -1704,9 +1640,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
1704 1640
1705 b->number = b->secondary = bus; 1641 b->number = b->secondary = bus;
1706 1642
1707 bridge->bus = b;
1708 INIT_LIST_HEAD(&bridge->windows);
1709
1710 if (parent) 1643 if (parent)
1711 dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); 1644 dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
1712 else 1645 else
@@ -1732,25 +1665,18 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
1732 } 1665 }
1733 1666
1734 down_write(&pci_bus_sem); 1667 down_write(&pci_bus_sem);
1735 list_add_tail(&bridge->list, &pci_host_bridges);
1736 list_add_tail(&b->node, &pci_root_buses); 1668 list_add_tail(&b->node, &pci_root_buses);
1737 up_write(&pci_bus_sem); 1669 up_write(&pci_bus_sem);
1738 1670
1739 return b; 1671 return b;
1740 1672
1741class_dev_reg_err: 1673class_dev_reg_err:
1742 device_unregister(dev); 1674 put_device(&bridge->dev);
1743dev_reg_err: 1675 device_unregister(&bridge->dev);
1744 down_write(&pci_bus_sem); 1676bridge_dev_reg_err:
1745 list_del(&bridge->list); 1677 kfree(bridge);
1746 list_del(&b->node);
1747 up_write(&pci_bus_sem);
1748err_out: 1678err_out:
1749 kfree(dev);
1750err_dev:
1751 kfree(b); 1679 kfree(b);
1752err_bus:
1753 kfree(bridge);
1754 return NULL; 1680 return NULL;
1755} 1681}
1756 1682