diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /arch/ia64/pci | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'arch/ia64/pci')
-rw-r--r-- | arch/ia64/pci/fixup.c | 6 | ||||
-rw-r--r-- | arch/ia64/pci/pci.c | 147 |
2 files changed, 114 insertions, 39 deletions
diff --git a/arch/ia64/pci/fixup.c b/arch/ia64/pci/fixup.c index 5dc969dd4ac..f5959c0c181 100644 --- a/arch/ia64/pci/fixup.c +++ b/arch/ia64/pci/fixup.c | |||
@@ -24,14 +24,14 @@ | |||
24 | * video device at this point. | 24 | * video device at this point. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | static void pci_fixup_video(struct pci_dev *pdev) | 27 | static void __devinit pci_fixup_video(struct pci_dev *pdev) |
28 | { | 28 | { |
29 | struct pci_dev *bridge; | 29 | struct pci_dev *bridge; |
30 | struct pci_bus *bus; | 30 | struct pci_bus *bus; |
31 | u16 config; | 31 | u16 config; |
32 | 32 | ||
33 | if ((strcmp(ia64_platform_name, "dig") != 0) | 33 | if ((strcmp(platform_name, "dig") != 0) |
34 | && (strcmp(ia64_platform_name, "hpzx1") != 0)) | 34 | && (strcmp(platform_name, "hpzx1") != 0)) |
35 | return; | 35 | return; |
36 | /* Maybe, this machine supports legacy memory map. */ | 36 | /* Maybe, this machine supports legacy memory map. */ |
37 | 37 | ||
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 55b72ad5732..aa2533ae7e9 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -20,10 +20,10 @@ | |||
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
22 | #include <linux/bootmem.h> | 22 | #include <linux/bootmem.h> |
23 | #include <linux/export.h> | ||
24 | 23 | ||
25 | #include <asm/machvec.h> | 24 | #include <asm/machvec.h> |
26 | #include <asm/page.h> | 25 | #include <asm/page.h> |
26 | #include <asm/system.h> | ||
27 | #include <asm/io.h> | 27 | #include <asm/io.h> |
28 | #include <asm/sal.h> | 28 | #include <asm/sal.h> |
29 | #include <asm/smp.h> | 29 | #include <asm/smp.h> |
@@ -116,7 +116,8 @@ struct pci_ops pci_root_ops = { | |||
116 | 116 | ||
117 | /* Called by ACPI when it finds a new root bus. */ | 117 | /* Called by ACPI when it finds a new root bus. */ |
118 | 118 | ||
119 | static struct pci_controller *alloc_pci_controller(int seg) | 119 | static struct pci_controller * __devinit |
120 | alloc_pci_controller (int seg) | ||
120 | { | 121 | { |
121 | struct pci_controller *controller; | 122 | struct pci_controller *controller; |
122 | 123 | ||
@@ -132,7 +133,6 @@ static struct pci_controller *alloc_pci_controller(int seg) | |||
132 | struct pci_root_info { | 133 | struct pci_root_info { |
133 | struct acpi_device *bridge; | 134 | struct acpi_device *bridge; |
134 | struct pci_controller *controller; | 135 | struct pci_controller *controller; |
135 | struct list_head resources; | ||
136 | char *name; | 136 | char *name; |
137 | }; | 137 | }; |
138 | 138 | ||
@@ -164,8 +164,8 @@ new_space (u64 phys_base, int sparse) | |||
164 | return i; | 164 | return i; |
165 | } | 165 | } |
166 | 166 | ||
167 | static u64 add_io_space(struct pci_root_info *info, | 167 | static u64 __devinit |
168 | struct acpi_resource_address64 *addr) | 168 | add_io_space (struct pci_root_info *info, struct acpi_resource_address64 *addr) |
169 | { | 169 | { |
170 | struct resource *resource; | 170 | struct resource *resource; |
171 | char *name; | 171 | char *name; |
@@ -225,8 +225,8 @@ out: | |||
225 | return ~0; | 225 | return ~0; |
226 | } | 226 | } |
227 | 227 | ||
228 | static acpi_status resource_to_window(struct acpi_resource *resource, | 228 | static acpi_status __devinit resource_to_window(struct acpi_resource *resource, |
229 | struct acpi_resource_address64 *addr) | 229 | struct acpi_resource_address64 *addr) |
230 | { | 230 | { |
231 | acpi_status status; | 231 | acpi_status status; |
232 | 232 | ||
@@ -248,7 +248,8 @@ static acpi_status resource_to_window(struct acpi_resource *resource, | |||
248 | return AE_ERROR; | 248 | return AE_ERROR; |
249 | } | 249 | } |
250 | 250 | ||
251 | static acpi_status count_window(struct acpi_resource *resource, void *data) | 251 | static acpi_status __devinit |
252 | count_window (struct acpi_resource *resource, void *data) | ||
252 | { | 253 | { |
253 | unsigned int *windows = (unsigned int *) data; | 254 | unsigned int *windows = (unsigned int *) data; |
254 | struct acpi_resource_address64 addr; | 255 | struct acpi_resource_address64 addr; |
@@ -261,7 +262,7 @@ static acpi_status count_window(struct acpi_resource *resource, void *data) | |||
261 | return AE_OK; | 262 | return AE_OK; |
262 | } | 263 | } |
263 | 264 | ||
264 | static acpi_status add_window(struct acpi_resource *res, void *data) | 265 | static __devinit acpi_status add_window(struct acpi_resource *res, void *data) |
265 | { | 266 | { |
266 | struct pci_root_info *info = data; | 267 | struct pci_root_info *info = data; |
267 | struct pci_window *window; | 268 | struct pci_window *window; |
@@ -293,6 +294,7 @@ static acpi_status add_window(struct acpi_resource *res, void *data) | |||
293 | window->resource.flags = flags; | 294 | window->resource.flags = flags; |
294 | window->resource.start = addr.minimum + offset; | 295 | window->resource.start = addr.minimum + offset; |
295 | window->resource.end = window->resource.start + addr.address_length - 1; | 296 | window->resource.end = window->resource.start + addr.address_length - 1; |
297 | window->resource.child = NULL; | ||
296 | window->offset = offset; | 298 | window->offset = offset; |
297 | 299 | ||
298 | if (insert_resource(root, &window->resource)) { | 300 | if (insert_resource(root, &window->resource)) { |
@@ -312,24 +314,34 @@ static acpi_status add_window(struct acpi_resource *res, void *data) | |||
312 | &window->resource); | 314 | &window->resource); |
313 | } | 315 | } |
314 | 316 | ||
315 | /* HP's firmware has a hack to work around a Windows bug. | ||
316 | * Ignore these tiny memory ranges */ | ||
317 | if (!((window->resource.flags & IORESOURCE_MEM) && | ||
318 | (window->resource.end - window->resource.start < 16))) | ||
319 | pci_add_resource_offset(&info->resources, &window->resource, | ||
320 | window->offset); | ||
321 | |||
322 | return AE_OK; | 317 | return AE_OK; |
323 | } | 318 | } |
324 | 319 | ||
325 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 320 | static void __devinit |
321 | pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl) | ||
322 | { | ||
323 | int i; | ||
324 | |||
325 | pci_bus_remove_resources(bus); | ||
326 | for (i = 0; i < ctrl->windows; i++) { | ||
327 | struct resource *res = &ctrl->window[i].resource; | ||
328 | /* HP's firmware has a hack to work around a Windows bug. | ||
329 | * Ignore these tiny memory ranges */ | ||
330 | if ((res->flags & IORESOURCE_MEM) && | ||
331 | (res->end - res->start < 16)) | ||
332 | continue; | ||
333 | pci_bus_add_resource(bus, res, 0); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | struct pci_bus * __devinit | ||
338 | pci_acpi_scan_root(struct acpi_pci_root *root) | ||
326 | { | 339 | { |
327 | struct acpi_device *device = root->device; | 340 | struct acpi_device *device = root->device; |
328 | int domain = root->segment; | 341 | int domain = root->segment; |
329 | int bus = root->secondary.start; | 342 | int bus = root->secondary.start; |
330 | struct pci_controller *controller; | 343 | struct pci_controller *controller; |
331 | unsigned int windows = 0; | 344 | unsigned int windows = 0; |
332 | struct pci_root_info info; | ||
333 | struct pci_bus *pbus; | 345 | struct pci_bus *pbus; |
334 | char *name; | 346 | char *name; |
335 | int pxm; | 347 | int pxm; |
@@ -346,14 +358,13 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
346 | controller->node = pxm_to_node(pxm); | 358 | controller->node = pxm_to_node(pxm); |
347 | #endif | 359 | #endif |
348 | 360 | ||
349 | INIT_LIST_HEAD(&info.resources); | ||
350 | /* insert busn resource at first */ | ||
351 | pci_add_resource(&info.resources, &root->secondary); | ||
352 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, | 361 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, |
353 | &windows); | 362 | &windows); |
354 | if (windows) { | 363 | if (windows) { |
364 | struct pci_root_info info; | ||
365 | |||
355 | controller->window = | 366 | controller->window = |
356 | kzalloc_node(sizeof(*controller->window) * windows, | 367 | kmalloc_node(sizeof(*controller->window) * windows, |
357 | GFP_KERNEL, controller->node); | 368 | GFP_KERNEL, controller->node); |
358 | if (!controller->window) | 369 | if (!controller->window) |
359 | goto out2; | 370 | goto out2; |
@@ -375,14 +386,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
375 | * should handle the case here, but it appears that IA64 hasn't | 386 | * should handle the case here, but it appears that IA64 hasn't |
376 | * such quirk. So we just ignore the case now. | 387 | * such quirk. So we just ignore the case now. |
377 | */ | 388 | */ |
378 | pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller, | 389 | pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller); |
379 | &info.resources); | ||
380 | if (!pbus) { | ||
381 | pci_free_resource_list(&info.resources); | ||
382 | return NULL; | ||
383 | } | ||
384 | 390 | ||
385 | pci_scan_child_bus(pbus); | ||
386 | return pbus; | 391 | return pbus; |
387 | 392 | ||
388 | out3: | 393 | out3: |
@@ -393,7 +398,55 @@ out1: | |||
393 | return NULL; | 398 | return NULL; |
394 | } | 399 | } |
395 | 400 | ||
396 | static int is_valid_resource(struct pci_dev *dev, int idx) | 401 | void pcibios_resource_to_bus(struct pci_dev *dev, |
402 | struct pci_bus_region *region, struct resource *res) | ||
403 | { | ||
404 | struct pci_controller *controller = PCI_CONTROLLER(dev); | ||
405 | unsigned long offset = 0; | ||
406 | int i; | ||
407 | |||
408 | for (i = 0; i < controller->windows; i++) { | ||
409 | struct pci_window *window = &controller->window[i]; | ||
410 | if (!(window->resource.flags & res->flags)) | ||
411 | continue; | ||
412 | if (window->resource.start > res->start) | ||
413 | continue; | ||
414 | if (window->resource.end < res->end) | ||
415 | continue; | ||
416 | offset = window->offset; | ||
417 | break; | ||
418 | } | ||
419 | |||
420 | region->start = res->start - offset; | ||
421 | region->end = res->end - offset; | ||
422 | } | ||
423 | EXPORT_SYMBOL(pcibios_resource_to_bus); | ||
424 | |||
425 | void pcibios_bus_to_resource(struct pci_dev *dev, | ||
426 | struct resource *res, struct pci_bus_region *region) | ||
427 | { | ||
428 | struct pci_controller *controller = PCI_CONTROLLER(dev); | ||
429 | unsigned long offset = 0; | ||
430 | int i; | ||
431 | |||
432 | for (i = 0; i < controller->windows; i++) { | ||
433 | struct pci_window *window = &controller->window[i]; | ||
434 | if (!(window->resource.flags & res->flags)) | ||
435 | continue; | ||
436 | if (window->resource.start - window->offset > region->start) | ||
437 | continue; | ||
438 | if (window->resource.end - window->offset < region->end) | ||
439 | continue; | ||
440 | offset = window->offset; | ||
441 | break; | ||
442 | } | ||
443 | |||
444 | res->start = region->start + offset; | ||
445 | res->end = region->end + offset; | ||
446 | } | ||
447 | EXPORT_SYMBOL(pcibios_bus_to_resource); | ||
448 | |||
449 | static int __devinit is_valid_resource(struct pci_dev *dev, int idx) | ||
397 | { | 450 | { |
398 | unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; | 451 | unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; |
399 | struct resource *devr = &dev->resource[idx], *busr; | 452 | struct resource *devr = &dev->resource[idx], *busr; |
@@ -411,25 +464,30 @@ static int is_valid_resource(struct pci_dev *dev, int idx) | |||
411 | return 0; | 464 | return 0; |
412 | } | 465 | } |
413 | 466 | ||
414 | static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) | 467 | static void __devinit |
468 | pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) | ||
415 | { | 469 | { |
470 | struct pci_bus_region region; | ||
416 | int i; | 471 | int i; |
417 | 472 | ||
418 | for (i = start; i < limit; i++) { | 473 | for (i = start; i < limit; i++) { |
419 | if (!dev->resource[i].flags) | 474 | if (!dev->resource[i].flags) |
420 | continue; | 475 | continue; |
476 | region.start = dev->resource[i].start; | ||
477 | region.end = dev->resource[i].end; | ||
478 | pcibios_bus_to_resource(dev, &dev->resource[i], ®ion); | ||
421 | if ((is_valid_resource(dev, i))) | 479 | if ((is_valid_resource(dev, i))) |
422 | pci_claim_resource(dev, i); | 480 | pci_claim_resource(dev, i); |
423 | } | 481 | } |
424 | } | 482 | } |
425 | 483 | ||
426 | void pcibios_fixup_device_resources(struct pci_dev *dev) | 484 | void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) |
427 | { | 485 | { |
428 | pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES); | 486 | pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES); |
429 | } | 487 | } |
430 | EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); | 488 | EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); |
431 | 489 | ||
432 | static void pcibios_fixup_bridge_resources(struct pci_dev *dev) | 490 | static void __devinit pcibios_fixup_bridge_resources(struct pci_dev *dev) |
433 | { | 491 | { |
434 | pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES); | 492 | pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES); |
435 | } | 493 | } |
@@ -437,22 +495,30 @@ static void pcibios_fixup_bridge_resources(struct pci_dev *dev) | |||
437 | /* | 495 | /* |
438 | * Called after each bus is probed, but before its children are examined. | 496 | * Called after each bus is probed, but before its children are examined. |
439 | */ | 497 | */ |
440 | void pcibios_fixup_bus(struct pci_bus *b) | 498 | void __devinit |
499 | pcibios_fixup_bus (struct pci_bus *b) | ||
441 | { | 500 | { |
442 | struct pci_dev *dev; | 501 | struct pci_dev *dev; |
443 | 502 | ||
444 | if (b->self) { | 503 | if (b->self) { |
445 | pci_read_bridge_bases(b); | 504 | pci_read_bridge_bases(b); |
446 | pcibios_fixup_bridge_resources(b->self); | 505 | pcibios_fixup_bridge_resources(b->self); |
506 | } else { | ||
507 | pcibios_setup_root_windows(b, b->sysdata); | ||
447 | } | 508 | } |
448 | list_for_each_entry(dev, &b->devices, bus_list) | 509 | list_for_each_entry(dev, &b->devices, bus_list) |
449 | pcibios_fixup_device_resources(dev); | 510 | pcibios_fixup_device_resources(dev); |
450 | platform_pci_fixup_bus(b); | 511 | platform_pci_fixup_bus(b); |
512 | |||
513 | return; | ||
451 | } | 514 | } |
452 | 515 | ||
453 | void pcibios_set_master (struct pci_dev *dev) | 516 | void __devinit |
517 | pcibios_update_irq (struct pci_dev *dev, int irq) | ||
454 | { | 518 | { |
455 | /* No special bus mastering setup handling */ | 519 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); |
520 | |||
521 | /* ??? FIXME -- record old value for shutdown. */ | ||
456 | } | 522 | } |
457 | 523 | ||
458 | int | 524 | int |
@@ -484,6 +550,15 @@ pcibios_align_resource (void *data, const struct resource *res, | |||
484 | return res->start; | 550 | return res->start; |
485 | } | 551 | } |
486 | 552 | ||
553 | /* | ||
554 | * PCI BIOS setup, always defaults to SAL interface | ||
555 | */ | ||
556 | char * __init | ||
557 | pcibios_setup (char *str) | ||
558 | { | ||
559 | return str; | ||
560 | } | ||
561 | |||
487 | int | 562 | int |
488 | pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, | 563 | pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, |
489 | enum pci_mmap_state mmap_state, int write_combine) | 564 | enum pci_mmap_state mmap_state, int write_combine) |