diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 14:15:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 14:15:26 -0400 |
commit | 37577505ec6e67d550aa5fb452c7b45a093cc7f3 (patch) | |
tree | 44f22364883679308c51cae6ebb8d164ad3aa5d1 /arch/ia64 | |
parent | 04bbc8e1f68cf4c1aac8024d6aea1a24757e8a5a (diff) | |
parent | c4cbf6b96100bbcd5da6e38b3334901b2eaa25bf (diff) |
Merge tag 'please-pull-root_bus_hotplug' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
Pull ia64 IOH hotplug fixes from Tony Luck:
"Series to fix IOH hotplug in ia64"
* tag 'please-pull-root_bus_hotplug' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux:
PCI: Replace printks with appropriate pr_*()
PCI/IA64: introduce probe_pci_root_info() to manage _CRS resource
PCI/IA64: Add host bridge resource release for _CRS path
PCI/IA64: fix memleak for create pci root bus fail
PCI/IA64: Allocate pci_root_info instead of using stack
PCI/IA64: embed pci hostbridge resources into pci_root_info
PCI/IA64: SN: use normal resource instead of pci_window
PCI/IA64: SN: remove sn_pci_window_fixup()
Diffstat (limited to 'arch/ia64')
-rw-r--r-- | arch/ia64/include/asm/pci.h | 10 | ||||
-rw-r--r-- | arch/ia64/pci/pci.c | 239 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/io_init.c | 109 |
3 files changed, 195 insertions, 163 deletions
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h index 5e04b591e423..80775f55f03f 100644 --- a/arch/ia64/include/asm/pci.h +++ b/arch/ia64/include/asm/pci.h | |||
@@ -89,9 +89,9 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus, | |||
89 | #define pci_legacy_read platform_pci_legacy_read | 89 | #define pci_legacy_read platform_pci_legacy_read |
90 | #define pci_legacy_write platform_pci_legacy_write | 90 | #define pci_legacy_write platform_pci_legacy_write |
91 | 91 | ||
92 | struct pci_window { | 92 | struct iospace_resource { |
93 | struct resource resource; | 93 | struct list_head list; |
94 | u64 offset; | 94 | struct resource res; |
95 | }; | 95 | }; |
96 | 96 | ||
97 | struct pci_controller { | 97 | struct pci_controller { |
@@ -100,12 +100,10 @@ struct pci_controller { | |||
100 | int segment; | 100 | int segment; |
101 | int node; /* nearest node with memory or -1 for global allocation */ | 101 | int node; /* nearest node with memory or -1 for global allocation */ |
102 | 102 | ||
103 | unsigned int windows; | ||
104 | struct pci_window *window; | ||
105 | |||
106 | void *platform_data; | 103 | void *platform_data; |
107 | }; | 104 | }; |
108 | 105 | ||
106 | |||
109 | #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata) | 107 | #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata) |
110 | #define pci_domain_nr(busdev) (PCI_CONTROLLER(busdev)->segment) | 108 | #define pci_domain_nr(busdev) (PCI_CONTROLLER(busdev)->segment) |
111 | 109 | ||
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index de1474ff0bc5..2326790b7d8b 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -134,6 +134,10 @@ struct pci_root_info { | |||
134 | struct acpi_device *bridge; | 134 | struct acpi_device *bridge; |
135 | struct pci_controller *controller; | 135 | struct pci_controller *controller; |
136 | struct list_head resources; | 136 | struct list_head resources; |
137 | struct resource *res; | ||
138 | resource_size_t *res_offset; | ||
139 | unsigned int res_num; | ||
140 | struct list_head io_resources; | ||
137 | char *name; | 141 | char *name; |
138 | }; | 142 | }; |
139 | 143 | ||
@@ -153,7 +157,7 @@ new_space (u64 phys_base, int sparse) | |||
153 | return i; | 157 | return i; |
154 | 158 | ||
155 | if (num_io_spaces == MAX_IO_SPACES) { | 159 | if (num_io_spaces == MAX_IO_SPACES) { |
156 | printk(KERN_ERR "PCI: Too many IO port spaces " | 160 | pr_err("PCI: Too many IO port spaces " |
157 | "(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES); | 161 | "(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES); |
158 | return ~0; | 162 | return ~0; |
159 | } | 163 | } |
@@ -168,25 +172,22 @@ new_space (u64 phys_base, int sparse) | |||
168 | static u64 add_io_space(struct pci_root_info *info, | 172 | static u64 add_io_space(struct pci_root_info *info, |
169 | struct acpi_resource_address64 *addr) | 173 | struct acpi_resource_address64 *addr) |
170 | { | 174 | { |
175 | struct iospace_resource *iospace; | ||
171 | struct resource *resource; | 176 | struct resource *resource; |
172 | char *name; | 177 | char *name; |
173 | unsigned long base, min, max, base_port; | 178 | unsigned long base, min, max, base_port; |
174 | unsigned int sparse = 0, space_nr, len; | 179 | unsigned int sparse = 0, space_nr, len; |
175 | 180 | ||
176 | resource = kzalloc(sizeof(*resource), GFP_KERNEL); | 181 | len = strlen(info->name) + 32; |
177 | if (!resource) { | 182 | iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL); |
178 | printk(KERN_ERR "PCI: No memory for %s I/O port space\n", | 183 | if (!iospace) { |
179 | info->name); | 184 | dev_err(&info->bridge->dev, |
185 | "PCI: No memory for %s I/O port space\n", | ||
186 | info->name); | ||
180 | goto out; | 187 | goto out; |
181 | } | 188 | } |
182 | 189 | ||
183 | len = strlen(info->name) + 32; | 190 | name = (char *)(iospace + 1); |
184 | name = kzalloc(len, GFP_KERNEL); | ||
185 | if (!name) { | ||
186 | printk(KERN_ERR "PCI: No memory for %s I/O port space name\n", | ||
187 | info->name); | ||
188 | goto free_resource; | ||
189 | } | ||
190 | 191 | ||
191 | min = addr->minimum; | 192 | min = addr->minimum; |
192 | max = min + addr->address_length - 1; | 193 | max = min + addr->address_length - 1; |
@@ -195,7 +196,7 @@ static u64 add_io_space(struct pci_root_info *info, | |||
195 | 196 | ||
196 | space_nr = new_space(addr->translation_offset, sparse); | 197 | space_nr = new_space(addr->translation_offset, sparse); |
197 | if (space_nr == ~0) | 198 | if (space_nr == ~0) |
198 | goto free_name; | 199 | goto free_resource; |
199 | 200 | ||
200 | base = __pa(io_space[space_nr].mmio_base); | 201 | base = __pa(io_space[space_nr].mmio_base); |
201 | base_port = IO_SPACE_BASE(space_nr); | 202 | base_port = IO_SPACE_BASE(space_nr); |
@@ -210,18 +211,23 @@ static u64 add_io_space(struct pci_root_info *info, | |||
210 | if (space_nr == 0) | 211 | if (space_nr == 0) |
211 | sparse = 1; | 212 | sparse = 1; |
212 | 213 | ||
214 | resource = &iospace->res; | ||
213 | resource->name = name; | 215 | resource->name = name; |
214 | resource->flags = IORESOURCE_MEM; | 216 | resource->flags = IORESOURCE_MEM; |
215 | resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); | 217 | resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); |
216 | resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); | 218 | resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); |
217 | insert_resource(&iomem_resource, resource); | 219 | if (insert_resource(&iomem_resource, resource)) { |
220 | dev_err(&info->bridge->dev, | ||
221 | "can't allocate host bridge io space resource %pR\n", | ||
222 | resource); | ||
223 | goto free_resource; | ||
224 | } | ||
218 | 225 | ||
226 | list_add_tail(&iospace->list, &info->io_resources); | ||
219 | return base_port; | 227 | return base_port; |
220 | 228 | ||
221 | free_name: | ||
222 | kfree(name); | ||
223 | free_resource: | 229 | free_resource: |
224 | kfree(resource); | 230 | kfree(iospace); |
225 | out: | 231 | out: |
226 | return ~0; | 232 | return ~0; |
227 | } | 233 | } |
@@ -265,7 +271,7 @@ static acpi_status count_window(struct acpi_resource *resource, void *data) | |||
265 | static acpi_status add_window(struct acpi_resource *res, void *data) | 271 | static acpi_status add_window(struct acpi_resource *res, void *data) |
266 | { | 272 | { |
267 | struct pci_root_info *info = data; | 273 | struct pci_root_info *info = data; |
268 | struct pci_window *window; | 274 | struct resource *resource; |
269 | struct acpi_resource_address64 addr; | 275 | struct acpi_resource_address64 addr; |
270 | acpi_status status; | 276 | acpi_status status; |
271 | unsigned long flags, offset = 0; | 277 | unsigned long flags, offset = 0; |
@@ -289,55 +295,146 @@ static acpi_status add_window(struct acpi_resource *res, void *data) | |||
289 | } else | 295 | } else |
290 | return AE_OK; | 296 | return AE_OK; |
291 | 297 | ||
292 | window = &info->controller->window[info->controller->windows++]; | 298 | resource = &info->res[info->res_num]; |
293 | window->resource.name = info->name; | 299 | resource->name = info->name; |
294 | window->resource.flags = flags; | 300 | resource->flags = flags; |
295 | window->resource.start = addr.minimum + offset; | 301 | resource->start = addr.minimum + offset; |
296 | window->resource.end = window->resource.start + addr.address_length - 1; | 302 | resource->end = resource->start + addr.address_length - 1; |
297 | window->offset = offset; | 303 | info->res_offset[info->res_num] = offset; |
298 | 304 | ||
299 | if (insert_resource(root, &window->resource)) { | 305 | if (insert_resource(root, resource)) { |
300 | dev_err(&info->bridge->dev, | 306 | dev_err(&info->bridge->dev, |
301 | "can't allocate host bridge window %pR\n", | 307 | "can't allocate host bridge window %pR\n", |
302 | &window->resource); | 308 | resource); |
303 | } else { | 309 | } else { |
304 | if (offset) | 310 | if (offset) |
305 | dev_info(&info->bridge->dev, "host bridge window %pR " | 311 | dev_info(&info->bridge->dev, "host bridge window %pR " |
306 | "(PCI address [%#llx-%#llx])\n", | 312 | "(PCI address [%#llx-%#llx])\n", |
307 | &window->resource, | 313 | resource, |
308 | window->resource.start - offset, | 314 | resource->start - offset, |
309 | window->resource.end - offset); | 315 | resource->end - offset); |
310 | else | 316 | else |
311 | dev_info(&info->bridge->dev, | 317 | dev_info(&info->bridge->dev, |
312 | "host bridge window %pR\n", | 318 | "host bridge window %pR\n", resource); |
313 | &window->resource); | ||
314 | } | 319 | } |
315 | |||
316 | /* HP's firmware has a hack to work around a Windows bug. | 320 | /* HP's firmware has a hack to work around a Windows bug. |
317 | * Ignore these tiny memory ranges */ | 321 | * Ignore these tiny memory ranges */ |
318 | if (!((window->resource.flags & IORESOURCE_MEM) && | 322 | if (!((resource->flags & IORESOURCE_MEM) && |
319 | (window->resource.end - window->resource.start < 16))) | 323 | (resource->end - resource->start < 16))) |
320 | pci_add_resource_offset(&info->resources, &window->resource, | 324 | pci_add_resource_offset(&info->resources, resource, |
321 | window->offset); | 325 | info->res_offset[info->res_num]); |
322 | 326 | ||
327 | info->res_num++; | ||
323 | return AE_OK; | 328 | return AE_OK; |
324 | } | 329 | } |
325 | 330 | ||
331 | static void free_pci_root_info_res(struct pci_root_info *info) | ||
332 | { | ||
333 | struct iospace_resource *iospace, *tmp; | ||
334 | |||
335 | list_for_each_entry_safe(iospace, tmp, &info->io_resources, list) | ||
336 | kfree(iospace); | ||
337 | |||
338 | kfree(info->name); | ||
339 | kfree(info->res); | ||
340 | info->res = NULL; | ||
341 | kfree(info->res_offset); | ||
342 | info->res_offset = NULL; | ||
343 | info->res_num = 0; | ||
344 | kfree(info->controller); | ||
345 | info->controller = NULL; | ||
346 | } | ||
347 | |||
348 | static void __release_pci_root_info(struct pci_root_info *info) | ||
349 | { | ||
350 | int i; | ||
351 | struct resource *res; | ||
352 | struct iospace_resource *iospace; | ||
353 | |||
354 | list_for_each_entry(iospace, &info->io_resources, list) | ||
355 | release_resource(&iospace->res); | ||
356 | |||
357 | for (i = 0; i < info->res_num; i++) { | ||
358 | res = &info->res[i]; | ||
359 | |||
360 | if (!res->parent) | ||
361 | continue; | ||
362 | |||
363 | if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
364 | continue; | ||
365 | |||
366 | release_resource(res); | ||
367 | } | ||
368 | |||
369 | free_pci_root_info_res(info); | ||
370 | kfree(info); | ||
371 | } | ||
372 | |||
373 | static void release_pci_root_info(struct pci_host_bridge *bridge) | ||
374 | { | ||
375 | struct pci_root_info *info = bridge->release_data; | ||
376 | |||
377 | __release_pci_root_info(info); | ||
378 | } | ||
379 | |||
380 | static int | ||
381 | probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, | ||
382 | int busnum, int domain) | ||
383 | { | ||
384 | char *name; | ||
385 | |||
386 | name = kmalloc(16, GFP_KERNEL); | ||
387 | if (!name) | ||
388 | return -ENOMEM; | ||
389 | |||
390 | sprintf(name, "PCI Bus %04x:%02x", domain, busnum); | ||
391 | info->bridge = device; | ||
392 | info->name = name; | ||
393 | |||
394 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, | ||
395 | &info->res_num); | ||
396 | if (info->res_num) { | ||
397 | info->res = | ||
398 | kzalloc_node(sizeof(*info->res) * info->res_num, | ||
399 | GFP_KERNEL, info->controller->node); | ||
400 | if (!info->res) { | ||
401 | kfree(name); | ||
402 | return -ENOMEM; | ||
403 | } | ||
404 | |||
405 | info->res_offset = | ||
406 | kzalloc_node(sizeof(*info->res_offset) * info->res_num, | ||
407 | GFP_KERNEL, info->controller->node); | ||
408 | if (!info->res_offset) { | ||
409 | kfree(name); | ||
410 | kfree(info->res); | ||
411 | info->res = NULL; | ||
412 | return -ENOMEM; | ||
413 | } | ||
414 | |||
415 | info->res_num = 0; | ||
416 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, | ||
417 | add_window, info); | ||
418 | } else | ||
419 | kfree(name); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
326 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 424 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) |
327 | { | 425 | { |
328 | struct acpi_device *device = root->device; | 426 | struct acpi_device *device = root->device; |
329 | int domain = root->segment; | 427 | int domain = root->segment; |
330 | int bus = root->secondary.start; | 428 | int bus = root->secondary.start; |
331 | struct pci_controller *controller; | 429 | struct pci_controller *controller; |
332 | unsigned int windows = 0; | 430 | struct pci_root_info *info = NULL; |
333 | struct pci_root_info info; | 431 | int busnum = root->secondary.start; |
334 | struct pci_bus *pbus; | 432 | struct pci_bus *pbus; |
335 | char *name; | 433 | int pxm, ret; |
336 | int pxm; | ||
337 | 434 | ||
338 | controller = alloc_pci_controller(domain); | 435 | controller = alloc_pci_controller(domain); |
339 | if (!controller) | 436 | if (!controller) |
340 | goto out1; | 437 | return NULL; |
341 | 438 | ||
342 | controller->acpi_handle = device->handle; | 439 | controller->acpi_handle = device->handle; |
343 | 440 | ||
@@ -347,29 +444,27 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
347 | controller->node = pxm_to_node(pxm); | 444 | controller->node = pxm_to_node(pxm); |
348 | #endif | 445 | #endif |
349 | 446 | ||
350 | INIT_LIST_HEAD(&info.resources); | 447 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
351 | /* insert busn resource at first */ | 448 | if (!info) { |
352 | pci_add_resource(&info.resources, &root->secondary); | 449 | dev_err(&device->dev, |
353 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, | 450 | "pci_bus %04x:%02x: ignored (out of memory)\n", |
354 | &windows); | 451 | domain, busnum); |
355 | if (windows) { | 452 | kfree(controller); |
356 | controller->window = | 453 | return NULL; |
357 | kzalloc_node(sizeof(*controller->window) * windows, | ||
358 | GFP_KERNEL, controller->node); | ||
359 | if (!controller->window) | ||
360 | goto out2; | ||
361 | |||
362 | name = kmalloc(16, GFP_KERNEL); | ||
363 | if (!name) | ||
364 | goto out3; | ||
365 | |||
366 | sprintf(name, "PCI Bus %04x:%02x", domain, bus); | ||
367 | info.bridge = device; | ||
368 | info.controller = controller; | ||
369 | info.name = name; | ||
370 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, | ||
371 | add_window, &info); | ||
372 | } | 454 | } |
455 | |||
456 | info->controller = controller; | ||
457 | INIT_LIST_HEAD(&info->io_resources); | ||
458 | INIT_LIST_HEAD(&info->resources); | ||
459 | |||
460 | ret = probe_pci_root_info(info, device, busnum, domain); | ||
461 | if (ret) { | ||
462 | kfree(info->controller); | ||
463 | kfree(info); | ||
464 | return NULL; | ||
465 | } | ||
466 | /* insert busn resource at first */ | ||
467 | pci_add_resource(&info->resources, &root->secondary); | ||
373 | /* | 468 | /* |
374 | * See arch/x86/pci/acpi.c. | 469 | * See arch/x86/pci/acpi.c. |
375 | * The desired pci bus might already be scanned in a quirk. We | 470 | * The desired pci bus might already be scanned in a quirk. We |
@@ -377,21 +472,17 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
377 | * such quirk. So we just ignore the case now. | 472 | * such quirk. So we just ignore the case now. |
378 | */ | 473 | */ |
379 | pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller, | 474 | pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller, |
380 | &info.resources); | 475 | &info->resources); |
381 | if (!pbus) { | 476 | if (!pbus) { |
382 | pci_free_resource_list(&info.resources); | 477 | pci_free_resource_list(&info->resources); |
478 | __release_pci_root_info(info); | ||
383 | return NULL; | 479 | return NULL; |
384 | } | 480 | } |
385 | 481 | ||
482 | pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge), | ||
483 | release_pci_root_info, info); | ||
386 | pci_scan_child_bus(pbus); | 484 | pci_scan_child_bus(pbus); |
387 | return pbus; | 485 | return pbus; |
388 | |||
389 | out3: | ||
390 | kfree(controller->window); | ||
391 | out2: | ||
392 | kfree(controller); | ||
393 | out1: | ||
394 | return NULL; | ||
395 | } | 486 | } |
396 | 487 | ||
397 | int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) | 488 | int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) |
@@ -691,7 +782,7 @@ static void __init set_pci_dfl_cacheline_size(void) | |||
691 | 782 | ||
692 | status = ia64_pal_cache_summary(&levels, &unique_caches); | 783 | status = ia64_pal_cache_summary(&levels, &unique_caches); |
693 | if (status != 0) { | 784 | if (status != 0) { |
694 | printk(KERN_ERR "%s: ia64_pal_cache_summary() failed " | 785 | pr_err("%s: ia64_pal_cache_summary() failed " |
695 | "(status=%ld)\n", __func__, status); | 786 | "(status=%ld)\n", __func__, status); |
696 | return; | 787 | return; |
697 | } | 788 | } |
@@ -699,7 +790,7 @@ static void __init set_pci_dfl_cacheline_size(void) | |||
699 | status = ia64_pal_cache_config_info(levels - 1, | 790 | status = ia64_pal_cache_config_info(levels - 1, |
700 | /* cache_type (data_or_unified)= */ 2, &cci); | 791 | /* cache_type (data_or_unified)= */ 2, &cci); |
701 | if (status != 0) { | 792 | if (status != 0) { |
702 | printk(KERN_ERR "%s: ia64_pal_cache_config_info() failed " | 793 | pr_err("%s: ia64_pal_cache_config_info() failed " |
703 | "(status=%ld)\n", __func__, status); | 794 | "(status=%ld)\n", __func__, status); |
704 | return; | 795 | return; |
705 | } | 796 | } |
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 238e2c511d94..2b00adedc45e 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
@@ -118,76 +118,26 @@ static void __init sn_fixup_ionodes(void) | |||
118 | } | 118 | } |
119 | 119 | ||
120 | /* | 120 | /* |
121 | * sn_pci_legacy_window_fixup - Create PCI controller windows for | 121 | * sn_pci_legacy_window_fixup - Setup PCI resources for |
122 | * legacy IO and MEM space. This needs to | 122 | * legacy IO and MEM space. This needs to |
123 | * be done here, as the PROM does not have | 123 | * be done here, as the PROM does not have |
124 | * ACPI support defining the root buses | 124 | * ACPI support defining the root buses |
125 | * and their resources (_CRS), | 125 | * and their resources (_CRS), |
126 | */ | 126 | */ |
127 | static void | 127 | static void |
128 | sn_legacy_pci_window_fixup(struct pci_controller *controller, | 128 | sn_legacy_pci_window_fixup(struct resource *res, |
129 | u64 legacy_io, u64 legacy_mem) | 129 | u64 legacy_io, u64 legacy_mem) |
130 | { | 130 | { |
131 | controller->window = kcalloc(2, sizeof(struct pci_window), | 131 | res[0].name = "legacy_io"; |
132 | GFP_KERNEL); | 132 | res[0].flags = IORESOURCE_IO; |
133 | BUG_ON(controller->window == NULL); | 133 | res[0].start = legacy_io; |
134 | controller->window[0].offset = legacy_io; | 134 | res[0].end = res[0].start + 0xffff; |
135 | controller->window[0].resource.name = "legacy_io"; | 135 | res[0].parent = &ioport_resource; |
136 | controller->window[0].resource.flags = IORESOURCE_IO; | 136 | res[1].name = "legacy_mem"; |
137 | controller->window[0].resource.start = legacy_io; | 137 | res[1].flags = IORESOURCE_MEM; |
138 | controller->window[0].resource.end = | 138 | res[1].start = legacy_mem; |
139 | controller->window[0].resource.start + 0xffff; | 139 | res[1].end = res[1].start + (1024 * 1024) - 1; |
140 | controller->window[0].resource.parent = &ioport_resource; | 140 | res[1].parent = &iomem_resource; |
141 | controller->window[1].offset = legacy_mem; | ||
142 | controller->window[1].resource.name = "legacy_mem"; | ||
143 | controller->window[1].resource.flags = IORESOURCE_MEM; | ||
144 | controller->window[1].resource.start = legacy_mem; | ||
145 | controller->window[1].resource.end = | ||
146 | controller->window[1].resource.start + (1024 * 1024) - 1; | ||
147 | controller->window[1].resource.parent = &iomem_resource; | ||
148 | controller->windows = 2; | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * sn_pci_window_fixup() - Create a pci_window for each device resource. | ||
153 | * It will setup pci_windows for use by | ||
154 | * pcibios_bus_to_resource(), pcibios_resource_to_bus(), | ||
155 | * etc. | ||
156 | */ | ||
157 | static void | ||
158 | sn_pci_window_fixup(struct pci_dev *dev, unsigned int count, | ||
159 | s64 * pci_addrs) | ||
160 | { | ||
161 | struct pci_controller *controller = PCI_CONTROLLER(dev->bus); | ||
162 | unsigned int i; | ||
163 | unsigned int idx; | ||
164 | unsigned int new_count; | ||
165 | struct pci_window *new_window; | ||
166 | |||
167 | if (count == 0) | ||
168 | return; | ||
169 | idx = controller->windows; | ||
170 | new_count = controller->windows + count; | ||
171 | new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL); | ||
172 | BUG_ON(new_window == NULL); | ||
173 | if (controller->window) { | ||
174 | memcpy(new_window, controller->window, | ||
175 | sizeof(struct pci_window) * controller->windows); | ||
176 | kfree(controller->window); | ||
177 | } | ||
178 | |||
179 | /* Setup a pci_window for each device resource. */ | ||
180 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
181 | if (pci_addrs[i] == -1) | ||
182 | continue; | ||
183 | |||
184 | new_window[idx].offset = dev->resource[i].start - pci_addrs[i]; | ||
185 | new_window[idx].resource = dev->resource[i]; | ||
186 | idx++; | ||
187 | } | ||
188 | |||
189 | controller->windows = new_count; | ||
190 | controller->window = new_window; | ||
191 | } | 141 | } |
192 | 142 | ||
193 | /* | 143 | /* |
@@ -199,9 +149,7 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count, | |||
199 | void | 149 | void |
200 | sn_io_slot_fixup(struct pci_dev *dev) | 150 | sn_io_slot_fixup(struct pci_dev *dev) |
201 | { | 151 | { |
202 | unsigned int count = 0; | ||
203 | int idx; | 152 | int idx; |
204 | s64 pci_addrs[PCI_ROM_RESOURCE + 1]; | ||
205 | unsigned long addr, end, size, start; | 153 | unsigned long addr, end, size, start; |
206 | struct pcidev_info *pcidev_info; | 154 | struct pcidev_info *pcidev_info; |
207 | struct sn_irq_info *sn_irq_info; | 155 | struct sn_irq_info *sn_irq_info; |
@@ -229,7 +177,6 @@ sn_io_slot_fixup(struct pci_dev *dev) | |||
229 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { | 177 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { |
230 | 178 | ||
231 | if (!pcidev_info->pdi_pio_mapped_addr[idx]) { | 179 | if (!pcidev_info->pdi_pio_mapped_addr[idx]) { |
232 | pci_addrs[idx] = -1; | ||
233 | continue; | 180 | continue; |
234 | } | 181 | } |
235 | 182 | ||
@@ -237,11 +184,8 @@ sn_io_slot_fixup(struct pci_dev *dev) | |||
237 | end = dev->resource[idx].end; | 184 | end = dev->resource[idx].end; |
238 | size = end - start; | 185 | size = end - start; |
239 | if (size == 0) { | 186 | if (size == 0) { |
240 | pci_addrs[idx] = -1; | ||
241 | continue; | 187 | continue; |
242 | } | 188 | } |
243 | pci_addrs[idx] = start; | ||
244 | count++; | ||
245 | addr = pcidev_info->pdi_pio_mapped_addr[idx]; | 189 | addr = pcidev_info->pdi_pio_mapped_addr[idx]; |
246 | addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET; | 190 | addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET; |
247 | dev->resource[idx].start = addr; | 191 | dev->resource[idx].start = addr; |
@@ -276,11 +220,6 @@ sn_io_slot_fixup(struct pci_dev *dev) | |||
276 | IORESOURCE_ROM_BIOS_COPY; | 220 | IORESOURCE_ROM_BIOS_COPY; |
277 | } | 221 | } |
278 | } | 222 | } |
279 | /* Create a pci_window in the pci_controller struct for | ||
280 | * each device resource. | ||
281 | */ | ||
282 | if (count > 0) | ||
283 | sn_pci_window_fixup(dev, count, pci_addrs); | ||
284 | 223 | ||
285 | sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); | 224 | sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); |
286 | } | 225 | } |
@@ -297,8 +236,8 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
297 | s64 status = 0; | 236 | s64 status = 0; |
298 | struct pci_controller *controller; | 237 | struct pci_controller *controller; |
299 | struct pcibus_bussoft *prom_bussoft_ptr; | 238 | struct pcibus_bussoft *prom_bussoft_ptr; |
239 | struct resource *res; | ||
300 | LIST_HEAD(resources); | 240 | LIST_HEAD(resources); |
301 | int i; | ||
302 | 241 | ||
303 | status = sal_get_pcibus_info((u64) segment, (u64) busnum, | 242 | status = sal_get_pcibus_info((u64) segment, (u64) busnum, |
304 | (u64) ia64_tpa(&prom_bussoft_ptr)); | 243 | (u64) ia64_tpa(&prom_bussoft_ptr)); |
@@ -310,19 +249,23 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
310 | BUG_ON(!controller); | 249 | BUG_ON(!controller); |
311 | controller->segment = segment; | 250 | controller->segment = segment; |
312 | 251 | ||
252 | res = kcalloc(2, sizeof(struct resource), GFP_KERNEL); | ||
253 | BUG_ON(!res); | ||
254 | |||
313 | /* | 255 | /* |
314 | * Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup(). | 256 | * Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup(). |
315 | * (platform_data will be overwritten later in sn_common_bus_fixup()) | 257 | * (platform_data will be overwritten later in sn_common_bus_fixup()) |
316 | */ | 258 | */ |
317 | controller->platform_data = prom_bussoft_ptr; | 259 | controller->platform_data = prom_bussoft_ptr; |
318 | 260 | ||
319 | sn_legacy_pci_window_fixup(controller, | 261 | sn_legacy_pci_window_fixup(res, |
320 | prom_bussoft_ptr->bs_legacy_io, | 262 | prom_bussoft_ptr->bs_legacy_io, |
321 | prom_bussoft_ptr->bs_legacy_mem); | 263 | prom_bussoft_ptr->bs_legacy_mem); |
322 | for (i = 0; i < controller->windows; i++) | 264 | pci_add_resource_offset(&resources, &res[0], |
323 | pci_add_resource_offset(&resources, | 265 | prom_bussoft_ptr->bs_legacy_io); |
324 | &controller->window[i].resource, | 266 | pci_add_resource_offset(&resources, &res[1], |
325 | controller->window[i].offset); | 267 | prom_bussoft_ptr->bs_legacy_mem); |
268 | |||
326 | bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller, | 269 | bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller, |
327 | &resources); | 270 | &resources); |
328 | if (bus == NULL) | 271 | if (bus == NULL) |
@@ -333,7 +276,7 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
333 | return; | 276 | return; |
334 | 277 | ||
335 | error_return: | 278 | error_return: |
336 | 279 | kfree(res); | |
337 | kfree(controller); | 280 | kfree(controller); |
338 | return; | 281 | return; |
339 | } | 282 | } |