diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-04-02 21:31:54 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-04-30 16:52:43 -0400 |
commit | d28e5ac2a07e27638cf5ac061721b7969e17fe78 (patch) | |
tree | 4ae91ae8d95f3ef23d8fa9be5f1d02b8cdc53715 /arch/x86/pci | |
parent | 35cb05e5bdac209cfdfafbe50d89ee7069cb6237 (diff) |
x86/PCI: dynamically allocate pci_root_info for native host bridge drivers
This dynamically allocates struct pci_root_info instead of using a
static array.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/amd_bus.c | 76 | ||||
-rw-r--r-- | arch/x86/pci/broadcom_bus.c | 12 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.c | 69 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.h | 18 |
4 files changed, 88 insertions, 87 deletions
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 0567df3890e1..459a7316375c 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
@@ -32,6 +32,18 @@ static struct pci_hostbridge_probe pci_probes[] __initdata = { | |||
32 | 32 | ||
33 | #define RANGE_NUM 16 | 33 | #define RANGE_NUM 16 |
34 | 34 | ||
35 | static struct pci_root_info __init *find_pci_root_info(int node, int link) | ||
36 | { | ||
37 | struct pci_root_info *info; | ||
38 | |||
39 | /* find the position */ | ||
40 | list_for_each_entry(info, &pci_root_infos, list) | ||
41 | if (info->node == node && info->link == link) | ||
42 | return info; | ||
43 | |||
44 | return NULL; | ||
45 | } | ||
46 | |||
35 | /** | 47 | /** |
36 | * early_fill_mp_bus_to_node() | 48 | * early_fill_mp_bus_to_node() |
37 | * called before pcibios_scan_root and pci_scan_bus | 49 | * called before pcibios_scan_root and pci_scan_bus |
@@ -50,7 +62,6 @@ static int __init early_fill_mp_bus_info(void) | |||
50 | int def_link; | 62 | int def_link; |
51 | struct pci_root_info *info; | 63 | struct pci_root_info *info; |
52 | u32 reg; | 64 | u32 reg; |
53 | struct resource *res; | ||
54 | u64 start; | 65 | u64 start; |
55 | u64 end; | 66 | u64 end; |
56 | struct range range[RANGE_NUM]; | 67 | struct range range[RANGE_NUM]; |
@@ -86,7 +97,6 @@ static int __init early_fill_mp_bus_info(void) | |||
86 | if (!found) | 97 | if (!found) |
87 | return 0; | 98 | return 0; |
88 | 99 | ||
89 | pci_root_num = 0; | ||
90 | for (i = 0; i < 4; i++) { | 100 | for (i = 0; i < 4; i++) { |
91 | int min_bus; | 101 | int min_bus; |
92 | int max_bus; | 102 | int max_bus; |
@@ -105,13 +115,8 @@ static int __init early_fill_mp_bus_info(void) | |||
105 | #endif | 115 | #endif |
106 | link = (reg >> 8) & 0x03; | 116 | link = (reg >> 8) & 0x03; |
107 | 117 | ||
108 | info = &pci_root_info[pci_root_num]; | 118 | info = alloc_pci_root_info(min_bus, max_bus, node, link); |
109 | info->bus_min = min_bus; | ||
110 | info->bus_max = max_bus; | ||
111 | info->node = node; | ||
112 | info->link = link; | ||
113 | sprintf(info->name, "PCI Bus #%02x", min_bus); | 119 | sprintf(info->name, "PCI Bus #%02x", min_bus); |
114 | pci_root_num++; | ||
115 | } | 120 | } |
116 | 121 | ||
117 | /* get the default node and link for left over res */ | 122 | /* get the default node and link for left over res */ |
@@ -134,16 +139,10 @@ static int __init early_fill_mp_bus_info(void) | |||
134 | link = (reg >> 4) & 0x03; | 139 | link = (reg >> 4) & 0x03; |
135 | end = (reg & 0xfff000) | 0xfff; | 140 | end = (reg & 0xfff000) | 0xfff; |
136 | 141 | ||
137 | /* find the position */ | 142 | info = find_pci_root_info(node, link); |
138 | for (j = 0; j < pci_root_num; j++) { | 143 | if (!info) |
139 | info = &pci_root_info[j]; | ||
140 | if (info->node == node && info->link == link) | ||
141 | break; | ||
142 | } | ||
143 | if (j == pci_root_num) | ||
144 | continue; /* not found */ | 144 | continue; /* not found */ |
145 | 145 | ||
146 | info = &pci_root_info[j]; | ||
147 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", | 146 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", |
148 | node, link, start, end); | 147 | node, link, start, end); |
149 | 148 | ||
@@ -155,13 +154,8 @@ static int __init early_fill_mp_bus_info(void) | |||
155 | } | 154 | } |
156 | /* add left over io port range to def node/link, [0, 0xffff] */ | 155 | /* add left over io port range to def node/link, [0, 0xffff] */ |
157 | /* find the position */ | 156 | /* find the position */ |
158 | for (j = 0; j < pci_root_num; j++) { | 157 | info = find_pci_root_info(def_node, def_link); |
159 | info = &pci_root_info[j]; | 158 | if (info) { |
160 | if (info->node == def_node && info->link == def_link) | ||
161 | break; | ||
162 | } | ||
163 | if (j < pci_root_num) { | ||
164 | info = &pci_root_info[j]; | ||
165 | for (i = 0; i < RANGE_NUM; i++) { | 159 | for (i = 0; i < RANGE_NUM; i++) { |
166 | if (!range[i].end) | 160 | if (!range[i].end) |
167 | continue; | 161 | continue; |
@@ -214,16 +208,10 @@ static int __init early_fill_mp_bus_info(void) | |||
214 | end <<= 8; | 208 | end <<= 8; |
215 | end |= 0xffff; | 209 | end |= 0xffff; |
216 | 210 | ||
217 | /* find the position */ | 211 | info = find_pci_root_info(node, link); |
218 | for (j = 0; j < pci_root_num; j++) { | ||
219 | info = &pci_root_info[j]; | ||
220 | if (info->node == node && info->link == link) | ||
221 | break; | ||
222 | } | ||
223 | if (j == pci_root_num) | ||
224 | continue; /* not found */ | ||
225 | 212 | ||
226 | info = &pci_root_info[j]; | 213 | if (!info) |
214 | continue; | ||
227 | 215 | ||
228 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", | 216 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", |
229 | node, link, start, end); | 217 | node, link, start, end); |
@@ -291,14 +279,8 @@ static int __init early_fill_mp_bus_info(void) | |||
291 | * add left over mmio range to def node/link ? | 279 | * add left over mmio range to def node/link ? |
292 | * that is tricky, just record range in from start_min to 4G | 280 | * that is tricky, just record range in from start_min to 4G |
293 | */ | 281 | */ |
294 | for (j = 0; j < pci_root_num; j++) { | 282 | info = find_pci_root_info(def_node, def_link); |
295 | info = &pci_root_info[j]; | 283 | if (info) { |
296 | if (info->node == def_node && info->link == def_link) | ||
297 | break; | ||
298 | } | ||
299 | if (j < pci_root_num) { | ||
300 | info = &pci_root_info[j]; | ||
301 | |||
302 | for (i = 0; i < RANGE_NUM; i++) { | 284 | for (i = 0; i < RANGE_NUM; i++) { |
303 | if (!range[i].end) | 285 | if (!range[i].end) |
304 | continue; | 286 | continue; |
@@ -309,20 +291,16 @@ static int __init early_fill_mp_bus_info(void) | |||
309 | } | 291 | } |
310 | } | 292 | } |
311 | 293 | ||
312 | for (i = 0; i < pci_root_num; i++) { | 294 | list_for_each_entry(info, &pci_root_infos, list) { |
313 | int res_num; | ||
314 | int busnum; | 295 | int busnum; |
296 | struct pci_root_res *root_res; | ||
315 | 297 | ||
316 | info = &pci_root_info[i]; | ||
317 | res_num = info->res_num; | ||
318 | busnum = info->bus_min; | 298 | busnum = info->bus_min; |
319 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", | 299 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", |
320 | info->bus_min, info->bus_max, info->node, info->link); | 300 | info->bus_min, info->bus_max, info->node, info->link); |
321 | for (j = 0; j < res_num; j++) { | 301 | list_for_each_entry(root_res, &info->resources, list) |
322 | res = &info->res[j]; | 302 | printk(KERN_DEBUG "bus: %02x %pR\n", |
323 | printk(KERN_DEBUG "bus: %02x index %x %pR\n", | 303 | busnum, &root_res->res); |
324 | busnum, j, res); | ||
325 | } | ||
326 | } | 304 | } |
327 | 305 | ||
328 | return 0; | 306 | return 0; |
diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c index f3a7c569a403..614392ced7d6 100644 --- a/arch/x86/pci/broadcom_bus.c +++ b/arch/x86/pci/broadcom_bus.c | |||
@@ -22,19 +22,15 @@ | |||
22 | static void __init cnb20le_res(u8 bus, u8 slot, u8 func) | 22 | static void __init cnb20le_res(u8 bus, u8 slot, u8 func) |
23 | { | 23 | { |
24 | struct pci_root_info *info; | 24 | struct pci_root_info *info; |
25 | struct pci_root_res *root_res; | ||
25 | struct resource res; | 26 | struct resource res; |
26 | u16 word1, word2; | 27 | u16 word1, word2; |
27 | u8 fbus, lbus; | 28 | u8 fbus, lbus; |
28 | int i; | ||
29 | |||
30 | info = &pci_root_info[pci_root_num]; | ||
31 | pci_root_num++; | ||
32 | 29 | ||
33 | /* read the PCI bus numbers */ | 30 | /* read the PCI bus numbers */ |
34 | fbus = read_pci_config_byte(bus, slot, func, 0x44); | 31 | fbus = read_pci_config_byte(bus, slot, func, 0x44); |
35 | lbus = read_pci_config_byte(bus, slot, func, 0x45); | 32 | lbus = read_pci_config_byte(bus, slot, func, 0x45); |
36 | info->bus_min = fbus; | 33 | info = alloc_pci_root_info(fbus, lbus, 0, 0); |
37 | info->bus_max = lbus; | ||
38 | 34 | ||
39 | /* | 35 | /* |
40 | * Add the legacy IDE ports on bus 0 | 36 | * Add the legacy IDE ports on bus 0 |
@@ -86,8 +82,8 @@ static void __init cnb20le_res(u8 bus, u8 slot, u8 func) | |||
86 | res.flags = IORESOURCE_BUS; | 82 | res.flags = IORESOURCE_BUS; |
87 | printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res); | 83 | printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res); |
88 | 84 | ||
89 | for (i = 0; i < info->res_num; i++) | 85 | list_for_each_entry(root_res, &info->resources, list) |
90 | printk(KERN_INFO "host bridge window %pR\n", &info->res[i]); | 86 | printk(KERN_INFO "host bridge window %pR\n", &root_res->res); |
91 | } | 87 | } |
92 | 88 | ||
93 | static int __init broadcom_postcore_init(void) | 89 | static int __init broadcom_postcore_init(void) |
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index fd3f65510e9d..306579f7d0fd 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c | |||
@@ -4,35 +4,38 @@ | |||
4 | 4 | ||
5 | #include "bus_numa.h" | 5 | #include "bus_numa.h" |
6 | 6 | ||
7 | int pci_root_num; | 7 | LIST_HEAD(pci_root_infos); |
8 | struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
9 | 8 | ||
10 | void x86_pci_root_bus_resources(int bus, struct list_head *resources) | 9 | static struct pci_root_info *x86_find_pci_root_info(int bus) |
11 | { | 10 | { |
12 | int i; | ||
13 | int j; | ||
14 | struct pci_root_info *info; | 11 | struct pci_root_info *info; |
15 | 12 | ||
16 | if (!pci_root_num) | 13 | if (list_empty(&pci_root_infos)) |
17 | goto default_resources; | 14 | return NULL; |
18 | 15 | ||
19 | for (i = 0; i < pci_root_num; i++) { | 16 | list_for_each_entry(info, &pci_root_infos, list) |
20 | if (pci_root_info[i].bus_min == bus) | 17 | if (info->bus_min == bus) |
21 | break; | 18 | return info; |
22 | } | 19 | |
20 | return NULL; | ||
21 | } | ||
23 | 22 | ||
24 | if (i == pci_root_num) | 23 | void x86_pci_root_bus_resources(int bus, struct list_head *resources) |
24 | { | ||
25 | struct pci_root_info *info = x86_find_pci_root_info(bus); | ||
26 | struct pci_root_res *root_res; | ||
27 | |||
28 | if (!info) | ||
25 | goto default_resources; | 29 | goto default_resources; |
26 | 30 | ||
27 | printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", | 31 | printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", |
28 | bus); | 32 | bus); |
29 | 33 | ||
30 | info = &pci_root_info[i]; | 34 | list_for_each_entry(root_res, &info->resources, list) { |
31 | for (j = 0; j < info->res_num; j++) { | ||
32 | struct resource *res; | 35 | struct resource *res; |
33 | struct resource *root; | 36 | struct resource *root; |
34 | 37 | ||
35 | res = &info->res[j]; | 38 | res = &root_res->res; |
36 | pci_add_resource(resources, res); | 39 | pci_add_resource(resources, res); |
37 | if (res->flags & IORESOURCE_IO) | 40 | if (res->flags & IORESOURCE_IO) |
38 | root = &ioport_resource; | 41 | root = &ioport_resource; |
@@ -53,11 +56,32 @@ default_resources: | |||
53 | pci_add_resource(resources, &iomem_resource); | 56 | pci_add_resource(resources, &iomem_resource); |
54 | } | 57 | } |
55 | 58 | ||
59 | struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max, | ||
60 | int node, int link) | ||
61 | { | ||
62 | struct pci_root_info *info; | ||
63 | |||
64 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
65 | |||
66 | if (!info) | ||
67 | return info; | ||
68 | |||
69 | INIT_LIST_HEAD(&info->resources); | ||
70 | info->bus_min = bus_min; | ||
71 | info->bus_max = bus_max; | ||
72 | info->node = node; | ||
73 | info->link = link; | ||
74 | |||
75 | list_add_tail(&info->list, &pci_root_infos); | ||
76 | |||
77 | return info; | ||
78 | } | ||
79 | |||
56 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, | 80 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, |
57 | resource_size_t end, unsigned long flags, int merge) | 81 | resource_size_t end, unsigned long flags, int merge) |
58 | { | 82 | { |
59 | int i; | ||
60 | struct resource *res; | 83 | struct resource *res; |
84 | struct pci_root_res *root_res; | ||
61 | 85 | ||
62 | if (start > end) | 86 | if (start > end) |
63 | return; | 87 | return; |
@@ -69,11 +93,11 @@ void __devinit update_res(struct pci_root_info *info, resource_size_t start, | |||
69 | goto addit; | 93 | goto addit; |
70 | 94 | ||
71 | /* try to merge it with old one */ | 95 | /* try to merge it with old one */ |
72 | for (i = 0; i < info->res_num; i++) { | 96 | list_for_each_entry(root_res, &info->resources, list) { |
73 | resource_size_t final_start, final_end; | 97 | resource_size_t final_start, final_end; |
74 | resource_size_t common_start, common_end; | 98 | resource_size_t common_start, common_end; |
75 | 99 | ||
76 | res = &info->res[i]; | 100 | res = &root_res->res; |
77 | if (res->flags != flags) | 101 | if (res->flags != flags) |
78 | continue; | 102 | continue; |
79 | 103 | ||
@@ -93,14 +117,15 @@ void __devinit update_res(struct pci_root_info *info, resource_size_t start, | |||
93 | addit: | 117 | addit: |
94 | 118 | ||
95 | /* need to add that */ | 119 | /* need to add that */ |
96 | if (info->res_num >= RES_NUM) | 120 | root_res = kzalloc(sizeof(*root_res), GFP_KERNEL); |
121 | if (!root_res) | ||
97 | return; | 122 | return; |
98 | 123 | ||
99 | res = &info->res[info->res_num]; | 124 | res = &root_res->res; |
100 | res->name = info->name; | 125 | res->name = info->name; |
101 | res->flags = flags; | 126 | res->flags = flags; |
102 | res->start = start; | 127 | res->start = start; |
103 | res->end = end; | 128 | res->end = end; |
104 | res->child = NULL; | 129 | |
105 | info->res_num++; | 130 | list_add_tail(&root_res->list, &info->resources); |
106 | } | 131 | } |
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h index 804a4b40c31a..226a466b2b2b 100644 --- a/arch/x86/pci/bus_numa.h +++ b/arch/x86/pci/bus_numa.h | |||
@@ -4,22 +4,24 @@ | |||
4 | * sub bus (transparent) will use entres from 3 to store extra from | 4 | * sub bus (transparent) will use entres from 3 to store extra from |
5 | * root, so need to make sure we have enough slot there. | 5 | * root, so need to make sure we have enough slot there. |
6 | */ | 6 | */ |
7 | #define RES_NUM 16 | 7 | struct pci_root_res { |
8 | struct list_head list; | ||
9 | struct resource res; | ||
10 | }; | ||
11 | |||
8 | struct pci_root_info { | 12 | struct pci_root_info { |
13 | struct list_head list; | ||
9 | char name[12]; | 14 | char name[12]; |
10 | unsigned int res_num; | 15 | struct list_head resources; |
11 | struct resource res[RES_NUM]; | ||
12 | int bus_min; | 16 | int bus_min; |
13 | int bus_max; | 17 | int bus_max; |
14 | int node; | 18 | int node; |
15 | int link; | 19 | int link; |
16 | }; | 20 | }; |
17 | 21 | ||
18 | /* 4 at this time, it may become to 32 */ | 22 | extern struct list_head pci_root_infos; |
19 | #define PCI_ROOT_NR 4 | 23 | struct pci_root_info *alloc_pci_root_info(int bus_min, int bus_max, |
20 | extern int pci_root_num; | 24 | int node, int link); |
21 | extern struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
22 | |||
23 | extern void update_res(struct pci_root_info *info, resource_size_t start, | 25 | extern void update_res(struct pci_root_info *info, resource_size_t start, |
24 | resource_size_t end, unsigned long flags, int merge); | 26 | resource_size_t end, unsigned long flags, int merge); |
25 | #endif | 27 | #endif |