diff options
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/cputable.c | 20 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh.c | 70 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh_cache.c | 18 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh_driver.c | 77 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh_pe.c | 58 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh_sysfs.c | 21 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci-common.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci-hotplug.c | 49 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_of_scan.c | 56 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/vmlinux.lds.S | 3 |
11 files changed, 247 insertions, 132 deletions
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 2a45d0f04385..22973a74df73 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -494,9 +494,27 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
494 | .cpu_restore = __restore_cpu_power7, | 494 | .cpu_restore = __restore_cpu_power7, |
495 | .platform = "power7+", | 495 | .platform = "power7+", |
496 | }, | 496 | }, |
497 | { /* Power8 */ | 497 | { /* Power8E */ |
498 | .pvr_mask = 0xffff0000, | 498 | .pvr_mask = 0xffff0000, |
499 | .pvr_value = 0x004b0000, | 499 | .pvr_value = 0x004b0000, |
500 | .cpu_name = "POWER8E (raw)", | ||
501 | .cpu_features = CPU_FTRS_POWER8, | ||
502 | .cpu_user_features = COMMON_USER_POWER8, | ||
503 | .cpu_user_features2 = COMMON_USER2_POWER8, | ||
504 | .mmu_features = MMU_FTRS_POWER8, | ||
505 | .icache_bsize = 128, | ||
506 | .dcache_bsize = 128, | ||
507 | .num_pmcs = 6, | ||
508 | .pmc_type = PPC_PMC_IBM, | ||
509 | .oprofile_cpu_type = "ppc64/power8", | ||
510 | .oprofile_type = PPC_OPROFILE_INVALID, | ||
511 | .cpu_setup = __setup_cpu_power8, | ||
512 | .cpu_restore = __restore_cpu_power8, | ||
513 | .platform = "power8", | ||
514 | }, | ||
515 | { /* Power8 */ | ||
516 | .pvr_mask = 0xffff0000, | ||
517 | .pvr_value = 0x004d0000, | ||
500 | .cpu_name = "POWER8 (raw)", | 518 | .cpu_name = "POWER8 (raw)", |
501 | .cpu_features = CPU_FTRS_POWER8, | 519 | .cpu_features = CPU_FTRS_POWER8, |
502 | .cpu_user_features = COMMON_USER_POWER8, | 520 | .cpu_user_features = COMMON_USER_POWER8, |
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 39954fe941b8..ea9414c8088d 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c | |||
@@ -231,7 +231,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) | |||
231 | void eeh_slot_error_detail(struct eeh_pe *pe, int severity) | 231 | void eeh_slot_error_detail(struct eeh_pe *pe, int severity) |
232 | { | 232 | { |
233 | size_t loglen = 0; | 233 | size_t loglen = 0; |
234 | struct eeh_dev *edev; | 234 | struct eeh_dev *edev, *tmp; |
235 | bool valid_cfg_log = true; | 235 | bool valid_cfg_log = true; |
236 | 236 | ||
237 | /* | 237 | /* |
@@ -251,7 +251,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) | |||
251 | eeh_pe_restore_bars(pe); | 251 | eeh_pe_restore_bars(pe); |
252 | 252 | ||
253 | pci_regs_buf[0] = 0; | 253 | pci_regs_buf[0] = 0; |
254 | eeh_pe_for_each_dev(pe, edev) { | 254 | eeh_pe_for_each_dev(pe, edev, tmp) { |
255 | loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen, | 255 | loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen, |
256 | EEH_PCI_REGS_LOG_LEN - loglen); | 256 | EEH_PCI_REGS_LOG_LEN - loglen); |
257 | } | 257 | } |
@@ -499,8 +499,6 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon | |||
499 | } | 499 | } |
500 | 500 | ||
501 | eeh_dev_check_failure(edev); | 501 | eeh_dev_check_failure(edev); |
502 | |||
503 | pci_dev_put(eeh_dev_to_pci_dev(edev)); | ||
504 | return val; | 502 | return val; |
505 | } | 503 | } |
506 | 504 | ||
@@ -838,7 +836,7 @@ core_initcall_sync(eeh_init); | |||
838 | * on the CEC architecture, type of the device, on earlier boot | 836 | * on the CEC architecture, type of the device, on earlier boot |
839 | * command-line arguments & etc. | 837 | * command-line arguments & etc. |
840 | */ | 838 | */ |
841 | static void eeh_add_device_early(struct device_node *dn) | 839 | void eeh_add_device_early(struct device_node *dn) |
842 | { | 840 | { |
843 | struct pci_controller *phb; | 841 | struct pci_controller *phb; |
844 | 842 | ||
@@ -886,7 +884,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); | |||
886 | * This routine must be used to complete EEH initialization for PCI | 884 | * This routine must be used to complete EEH initialization for PCI |
887 | * devices that were added after system boot (e.g. hotplug, dlpar). | 885 | * devices that were added after system boot (e.g. hotplug, dlpar). |
888 | */ | 886 | */ |
889 | static void eeh_add_device_late(struct pci_dev *dev) | 887 | void eeh_add_device_late(struct pci_dev *dev) |
890 | { | 888 | { |
891 | struct device_node *dn; | 889 | struct device_node *dn; |
892 | struct eeh_dev *edev; | 890 | struct eeh_dev *edev; |
@@ -902,9 +900,23 @@ static void eeh_add_device_late(struct pci_dev *dev) | |||
902 | pr_debug("EEH: Already referenced !\n"); | 900 | pr_debug("EEH: Already referenced !\n"); |
903 | return; | 901 | return; |
904 | } | 902 | } |
905 | WARN_ON(edev->pdev); | ||
906 | 903 | ||
907 | pci_dev_get(dev); | 904 | /* |
905 | * The EEH cache might not be removed correctly because of | ||
906 | * unbalanced kref to the device during unplug time, which | ||
907 | * relies on pcibios_release_device(). So we have to remove | ||
908 | * that here explicitly. | ||
909 | */ | ||
910 | if (edev->pdev) { | ||
911 | eeh_rmv_from_parent_pe(edev); | ||
912 | eeh_addr_cache_rmv_dev(edev->pdev); | ||
913 | eeh_sysfs_remove_device(edev->pdev); | ||
914 | edev->mode &= ~EEH_DEV_SYSFS; | ||
915 | |||
916 | edev->pdev = NULL; | ||
917 | dev->dev.archdata.edev = NULL; | ||
918 | } | ||
919 | |||
908 | edev->pdev = dev; | 920 | edev->pdev = dev; |
909 | dev->dev.archdata.edev = edev; | 921 | dev->dev.archdata.edev = edev; |
910 | 922 | ||
@@ -967,7 +979,6 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); | |||
967 | /** | 979 | /** |
968 | * eeh_remove_device - Undo EEH setup for the indicated pci device | 980 | * eeh_remove_device - Undo EEH setup for the indicated pci device |
969 | * @dev: pci device to be removed | 981 | * @dev: pci device to be removed |
970 | * @purge_pe: remove the PE or not | ||
971 | * | 982 | * |
972 | * This routine should be called when a device is removed from | 983 | * This routine should be called when a device is removed from |
973 | * a running system (e.g. by hotplug or dlpar). It unregisters | 984 | * a running system (e.g. by hotplug or dlpar). It unregisters |
@@ -975,7 +986,7 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); | |||
975 | * this device will no longer be detected after this call; thus, | 986 | * this device will no longer be detected after this call; thus, |
976 | * i/o errors affecting this slot may leave this device unusable. | 987 | * i/o errors affecting this slot may leave this device unusable. |
977 | */ | 988 | */ |
978 | static void eeh_remove_device(struct pci_dev *dev, int purge_pe) | 989 | void eeh_remove_device(struct pci_dev *dev) |
979 | { | 990 | { |
980 | struct eeh_dev *edev; | 991 | struct eeh_dev *edev; |
981 | 992 | ||
@@ -986,42 +997,29 @@ static void eeh_remove_device(struct pci_dev *dev, int purge_pe) | |||
986 | /* Unregister the device with the EEH/PCI address search system */ | 997 | /* Unregister the device with the EEH/PCI address search system */ |
987 | pr_debug("EEH: Removing device %s\n", pci_name(dev)); | 998 | pr_debug("EEH: Removing device %s\n", pci_name(dev)); |
988 | 999 | ||
989 | if (!edev || !edev->pdev) { | 1000 | if (!edev || !edev->pdev || !edev->pe) { |
990 | pr_debug("EEH: Not referenced !\n"); | 1001 | pr_debug("EEH: Not referenced !\n"); |
991 | return; | 1002 | return; |
992 | } | 1003 | } |
1004 | |||
1005 | /* | ||
1006 | * During the hotplug for EEH error recovery, we need the EEH | ||
1007 | * device attached to the parent PE in order for BAR restore | ||
1008 | * a bit later. So we keep it for BAR restore and remove it | ||
1009 | * from the parent PE during the BAR resotre. | ||
1010 | */ | ||
993 | edev->pdev = NULL; | 1011 | edev->pdev = NULL; |
994 | dev->dev.archdata.edev = NULL; | 1012 | dev->dev.archdata.edev = NULL; |
995 | pci_dev_put(dev); | 1013 | if (!(edev->pe->state & EEH_PE_KEEP)) |
1014 | eeh_rmv_from_parent_pe(edev); | ||
1015 | else | ||
1016 | edev->mode |= EEH_DEV_DISCONNECTED; | ||
996 | 1017 | ||
997 | eeh_rmv_from_parent_pe(edev, purge_pe); | ||
998 | eeh_addr_cache_rmv_dev(dev); | 1018 | eeh_addr_cache_rmv_dev(dev); |
999 | eeh_sysfs_remove_device(dev); | 1019 | eeh_sysfs_remove_device(dev); |
1020 | edev->mode &= ~EEH_DEV_SYSFS; | ||
1000 | } | 1021 | } |
1001 | 1022 | ||
1002 | /** | ||
1003 | * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device | ||
1004 | * @dev: PCI device | ||
1005 | * @purge_pe: remove the corresponding PE or not | ||
1006 | * | ||
1007 | * This routine must be called when a device is removed from the | ||
1008 | * running system through hotplug or dlpar. The corresponding | ||
1009 | * PCI address cache will be removed. | ||
1010 | */ | ||
1011 | void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) | ||
1012 | { | ||
1013 | struct pci_bus *bus = dev->subordinate; | ||
1014 | struct pci_dev *child, *tmp; | ||
1015 | |||
1016 | eeh_remove_device(dev, purge_pe); | ||
1017 | |||
1018 | if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
1019 | list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) | ||
1020 | eeh_remove_bus_device(child, purge_pe); | ||
1021 | } | ||
1022 | } | ||
1023 | EXPORT_SYMBOL_GPL(eeh_remove_bus_device); | ||
1024 | |||
1025 | static int proc_eeh_show(struct seq_file *m, void *v) | 1023 | static int proc_eeh_show(struct seq_file *m, void *v) |
1026 | { | 1024 | { |
1027 | if (0 == eeh_subsystem_enabled) { | 1025 | if (0 == eeh_subsystem_enabled) { |
diff --git a/arch/powerpc/kernel/eeh_cache.c b/arch/powerpc/kernel/eeh_cache.c index f9ac1232a746..e8c9fd546a5c 100644 --- a/arch/powerpc/kernel/eeh_cache.c +++ b/arch/powerpc/kernel/eeh_cache.c | |||
@@ -68,16 +68,12 @@ static inline struct eeh_dev *__eeh_addr_cache_get_device(unsigned long addr) | |||
68 | struct pci_io_addr_range *piar; | 68 | struct pci_io_addr_range *piar; |
69 | piar = rb_entry(n, struct pci_io_addr_range, rb_node); | 69 | piar = rb_entry(n, struct pci_io_addr_range, rb_node); |
70 | 70 | ||
71 | if (addr < piar->addr_lo) { | 71 | if (addr < piar->addr_lo) |
72 | n = n->rb_left; | 72 | n = n->rb_left; |
73 | } else { | 73 | else if (addr > piar->addr_hi) |
74 | if (addr > piar->addr_hi) { | 74 | n = n->rb_right; |
75 | n = n->rb_right; | 75 | else |
76 | } else { | 76 | return piar->edev; |
77 | pci_dev_get(piar->pcidev); | ||
78 | return piar->edev; | ||
79 | } | ||
80 | } | ||
81 | } | 77 | } |
82 | 78 | ||
83 | return NULL; | 79 | return NULL; |
@@ -156,7 +152,6 @@ eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | |||
156 | if (!piar) | 152 | if (!piar) |
157 | return NULL; | 153 | return NULL; |
158 | 154 | ||
159 | pci_dev_get(dev); | ||
160 | piar->addr_lo = alo; | 155 | piar->addr_lo = alo; |
161 | piar->addr_hi = ahi; | 156 | piar->addr_hi = ahi; |
162 | piar->edev = pci_dev_to_eeh_dev(dev); | 157 | piar->edev = pci_dev_to_eeh_dev(dev); |
@@ -250,7 +245,6 @@ restart: | |||
250 | 245 | ||
251 | if (piar->pcidev == dev) { | 246 | if (piar->pcidev == dev) { |
252 | rb_erase(n, &pci_io_addr_cache_root.rb_root); | 247 | rb_erase(n, &pci_io_addr_cache_root.rb_root); |
253 | pci_dev_put(piar->pcidev); | ||
254 | kfree(piar); | 248 | kfree(piar); |
255 | goto restart; | 249 | goto restart; |
256 | } | 250 | } |
@@ -302,12 +296,10 @@ void eeh_addr_cache_build(void) | |||
302 | if (!edev) | 296 | if (!edev) |
303 | continue; | 297 | continue; |
304 | 298 | ||
305 | pci_dev_get(dev); /* matching put is in eeh_remove_device() */ | ||
306 | dev->dev.archdata.edev = edev; | 299 | dev->dev.archdata.edev = edev; |
307 | edev->pdev = dev; | 300 | edev->pdev = dev; |
308 | 301 | ||
309 | eeh_addr_cache_insert_dev(dev); | 302 | eeh_addr_cache_insert_dev(dev); |
310 | |||
311 | eeh_sysfs_add_device(dev); | 303 | eeh_sysfs_add_device(dev); |
312 | } | 304 | } |
313 | 305 | ||
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 2b1ce17cae50..36bed5a12750 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c | |||
@@ -143,10 +143,14 @@ static void eeh_disable_irq(struct pci_dev *dev) | |||
143 | static void eeh_enable_irq(struct pci_dev *dev) | 143 | static void eeh_enable_irq(struct pci_dev *dev) |
144 | { | 144 | { |
145 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); | 145 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
146 | struct irq_desc *desc; | ||
146 | 147 | ||
147 | if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { | 148 | if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { |
148 | edev->mode &= ~EEH_DEV_IRQ_DISABLED; | 149 | edev->mode &= ~EEH_DEV_IRQ_DISABLED; |
149 | enable_irq(dev->irq); | 150 | |
151 | desc = irq_to_desc(dev->irq); | ||
152 | if (desc && desc->depth > 0) | ||
153 | enable_irq(dev->irq); | ||
150 | } | 154 | } |
151 | } | 155 | } |
152 | 156 | ||
@@ -338,6 +342,54 @@ static void *eeh_report_failure(void *data, void *userdata) | |||
338 | return NULL; | 342 | return NULL; |
339 | } | 343 | } |
340 | 344 | ||
345 | static void *eeh_rmv_device(void *data, void *userdata) | ||
346 | { | ||
347 | struct pci_driver *driver; | ||
348 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
349 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
350 | int *removed = (int *)userdata; | ||
351 | |||
352 | /* | ||
353 | * Actually, we should remove the PCI bridges as well. | ||
354 | * However, that's lots of complexity to do that, | ||
355 | * particularly some of devices under the bridge might | ||
356 | * support EEH. So we just care about PCI devices for | ||
357 | * simplicity here. | ||
358 | */ | ||
359 | if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) | ||
360 | return NULL; | ||
361 | driver = eeh_pcid_get(dev); | ||
362 | if (driver && driver->err_handler) | ||
363 | return NULL; | ||
364 | |||
365 | /* Remove it from PCI subsystem */ | ||
366 | pr_debug("EEH: Removing %s without EEH sensitive driver\n", | ||
367 | pci_name(dev)); | ||
368 | edev->bus = dev->bus; | ||
369 | edev->mode |= EEH_DEV_DISCONNECTED; | ||
370 | (*removed)++; | ||
371 | |||
372 | pci_stop_and_remove_bus_device(dev); | ||
373 | |||
374 | return NULL; | ||
375 | } | ||
376 | |||
377 | static void *eeh_pe_detach_dev(void *data, void *userdata) | ||
378 | { | ||
379 | struct eeh_pe *pe = (struct eeh_pe *)data; | ||
380 | struct eeh_dev *edev, *tmp; | ||
381 | |||
382 | eeh_pe_for_each_dev(pe, edev, tmp) { | ||
383 | if (!(edev->mode & EEH_DEV_DISCONNECTED)) | ||
384 | continue; | ||
385 | |||
386 | edev->mode &= ~(EEH_DEV_DISCONNECTED | EEH_DEV_IRQ_DISABLED); | ||
387 | eeh_rmv_from_parent_pe(edev); | ||
388 | } | ||
389 | |||
390 | return NULL; | ||
391 | } | ||
392 | |||
341 | /** | 393 | /** |
342 | * eeh_reset_device - Perform actual reset of a pci slot | 394 | * eeh_reset_device - Perform actual reset of a pci slot |
343 | * @pe: EEH PE | 395 | * @pe: EEH PE |
@@ -349,8 +401,9 @@ static void *eeh_report_failure(void *data, void *userdata) | |||
349 | */ | 401 | */ |
350 | static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | 402 | static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) |
351 | { | 403 | { |
404 | struct pci_bus *frozen_bus = eeh_pe_bus_get(pe); | ||
352 | struct timeval tstamp; | 405 | struct timeval tstamp; |
353 | int cnt, rc; | 406 | int cnt, rc, removed = 0; |
354 | 407 | ||
355 | /* pcibios will clear the counter; save the value */ | 408 | /* pcibios will clear the counter; save the value */ |
356 | cnt = pe->freeze_count; | 409 | cnt = pe->freeze_count; |
@@ -362,8 +415,11 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | |||
362 | * devices are expected to be attached soon when calling | 415 | * devices are expected to be attached soon when calling |
363 | * into pcibios_add_pci_devices(). | 416 | * into pcibios_add_pci_devices(). |
364 | */ | 417 | */ |
418 | eeh_pe_state_mark(pe, EEH_PE_KEEP); | ||
365 | if (bus) | 419 | if (bus) |
366 | __pcibios_remove_pci_devices(bus, 0); | 420 | pcibios_remove_pci_devices(bus); |
421 | else if (frozen_bus) | ||
422 | eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed); | ||
367 | 423 | ||
368 | /* Reset the pci controller. (Asserts RST#; resets config space). | 424 | /* Reset the pci controller. (Asserts RST#; resets config space). |
369 | * Reconfigure bridges and devices. Don't try to bring the system | 425 | * Reconfigure bridges and devices. Don't try to bring the system |
@@ -384,9 +440,24 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | |||
384 | * potentially weird things happen. | 440 | * potentially weird things happen. |
385 | */ | 441 | */ |
386 | if (bus) { | 442 | if (bus) { |
443 | pr_info("EEH: Sleep 5s ahead of complete hotplug\n"); | ||
387 | ssleep(5); | 444 | ssleep(5); |
445 | |||
446 | /* | ||
447 | * The EEH device is still connected with its parent | ||
448 | * PE. We should disconnect it so the binding can be | ||
449 | * rebuilt when adding PCI devices. | ||
450 | */ | ||
451 | eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); | ||
388 | pcibios_add_pci_devices(bus); | 452 | pcibios_add_pci_devices(bus); |
453 | } else if (frozen_bus && removed) { | ||
454 | pr_info("EEH: Sleep 5s ahead of partial hotplug\n"); | ||
455 | ssleep(5); | ||
456 | |||
457 | eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); | ||
458 | pcibios_add_pci_devices(frozen_bus); | ||
389 | } | 459 | } |
460 | eeh_pe_state_clear(pe, EEH_PE_KEEP); | ||
390 | 461 | ||
391 | pe->tstamp = tstamp; | 462 | pe->tstamp = tstamp; |
392 | pe->freeze_count = cnt; | 463 | pe->freeze_count = cnt; |
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 016588a6f5ed..f9450537e335 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c | |||
@@ -149,8 +149,8 @@ static struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, | |||
149 | * callback returns something other than NULL, or no more PEs | 149 | * callback returns something other than NULL, or no more PEs |
150 | * to be traversed. | 150 | * to be traversed. |
151 | */ | 151 | */ |
152 | static void *eeh_pe_traverse(struct eeh_pe *root, | 152 | void *eeh_pe_traverse(struct eeh_pe *root, |
153 | eeh_traverse_func fn, void *flag) | 153 | eeh_traverse_func fn, void *flag) |
154 | { | 154 | { |
155 | struct eeh_pe *pe; | 155 | struct eeh_pe *pe; |
156 | void *ret; | 156 | void *ret; |
@@ -176,7 +176,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root, | |||
176 | eeh_traverse_func fn, void *flag) | 176 | eeh_traverse_func fn, void *flag) |
177 | { | 177 | { |
178 | struct eeh_pe *pe; | 178 | struct eeh_pe *pe; |
179 | struct eeh_dev *edev; | 179 | struct eeh_dev *edev, *tmp; |
180 | void *ret; | 180 | void *ret; |
181 | 181 | ||
182 | if (!root) { | 182 | if (!root) { |
@@ -186,7 +186,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root, | |||
186 | 186 | ||
187 | /* Traverse root PE */ | 187 | /* Traverse root PE */ |
188 | for (pe = root; pe; pe = eeh_pe_next(pe, root)) { | 188 | for (pe = root; pe; pe = eeh_pe_next(pe, root)) { |
189 | eeh_pe_for_each_dev(pe, edev) { | 189 | eeh_pe_for_each_dev(pe, edev, tmp) { |
190 | ret = fn(edev, flag); | 190 | ret = fn(edev, flag); |
191 | if (ret) | 191 | if (ret) |
192 | return ret; | 192 | return ret; |
@@ -333,7 +333,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) | |||
333 | while (parent) { | 333 | while (parent) { |
334 | if (!(parent->type & EEH_PE_INVALID)) | 334 | if (!(parent->type & EEH_PE_INVALID)) |
335 | break; | 335 | break; |
336 | parent->type &= ~EEH_PE_INVALID; | 336 | parent->type &= ~(EEH_PE_INVALID | EEH_PE_KEEP); |
337 | parent = parent->parent; | 337 | parent = parent->parent; |
338 | } | 338 | } |
339 | pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", | 339 | pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", |
@@ -397,21 +397,20 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) | |||
397 | /** | 397 | /** |
398 | * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE | 398 | * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE |
399 | * @edev: EEH device | 399 | * @edev: EEH device |
400 | * @purge_pe: remove PE or not | ||
401 | * | 400 | * |
402 | * The PE hierarchy tree might be changed when doing PCI hotplug. | 401 | * The PE hierarchy tree might be changed when doing PCI hotplug. |
403 | * Also, the PCI devices or buses could be removed from the system | 402 | * Also, the PCI devices or buses could be removed from the system |
404 | * during EEH recovery. So we have to call the function remove the | 403 | * during EEH recovery. So we have to call the function remove the |
405 | * corresponding PE accordingly if necessary. | 404 | * corresponding PE accordingly if necessary. |
406 | */ | 405 | */ |
407 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) | 406 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev) |
408 | { | 407 | { |
409 | struct eeh_pe *pe, *parent, *child; | 408 | struct eeh_pe *pe, *parent, *child; |
410 | int cnt; | 409 | int cnt; |
411 | 410 | ||
412 | if (!edev->pe) { | 411 | if (!edev->pe) { |
413 | pr_warning("%s: No PE found for EEH device %s\n", | 412 | pr_debug("%s: No PE found for EEH device %s\n", |
414 | __func__, edev->dn->full_name); | 413 | __func__, edev->dn->full_name); |
415 | return -EEXIST; | 414 | return -EEXIST; |
416 | } | 415 | } |
417 | 416 | ||
@@ -431,7 +430,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) | |||
431 | if (pe->type & EEH_PE_PHB) | 430 | if (pe->type & EEH_PE_PHB) |
432 | break; | 431 | break; |
433 | 432 | ||
434 | if (purge_pe) { | 433 | if (!(pe->state & EEH_PE_KEEP)) { |
435 | if (list_empty(&pe->edevs) && | 434 | if (list_empty(&pe->edevs) && |
436 | list_empty(&pe->child_list)) { | 435 | list_empty(&pe->child_list)) { |
437 | list_del(&pe->child); | 436 | list_del(&pe->child); |
@@ -502,7 +501,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag) | |||
502 | { | 501 | { |
503 | struct eeh_pe *pe = (struct eeh_pe *)data; | 502 | struct eeh_pe *pe = (struct eeh_pe *)data; |
504 | int state = *((int *)flag); | 503 | int state = *((int *)flag); |
505 | struct eeh_dev *tmp; | 504 | struct eeh_dev *edev, *tmp; |
506 | struct pci_dev *pdev; | 505 | struct pci_dev *pdev; |
507 | 506 | ||
508 | /* | 507 | /* |
@@ -512,8 +511,8 @@ static void *__eeh_pe_state_mark(void *data, void *flag) | |||
512 | * the PCI device driver. | 511 | * the PCI device driver. |
513 | */ | 512 | */ |
514 | pe->state |= state; | 513 | pe->state |= state; |
515 | eeh_pe_for_each_dev(pe, tmp) { | 514 | eeh_pe_for_each_dev(pe, edev, tmp) { |
516 | pdev = eeh_dev_to_pci_dev(tmp); | 515 | pdev = eeh_dev_to_pci_dev(edev); |
517 | if (pdev) | 516 | if (pdev) |
518 | pdev->error_state = pci_channel_io_frozen; | 517 | pdev->error_state = pci_channel_io_frozen; |
519 | } | 518 | } |
@@ -579,7 +578,7 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state) | |||
579 | * blocked on normal path during the stage. So we need utilize | 578 | * blocked on normal path during the stage. So we need utilize |
580 | * eeh operations, which is always permitted. | 579 | * eeh operations, which is always permitted. |
581 | */ | 580 | */ |
582 | static void eeh_bridge_check_link(struct pci_dev *pdev, | 581 | static void eeh_bridge_check_link(struct eeh_dev *edev, |
583 | struct device_node *dn) | 582 | struct device_node *dn) |
584 | { | 583 | { |
585 | int cap; | 584 | int cap; |
@@ -590,16 +589,17 @@ static void eeh_bridge_check_link(struct pci_dev *pdev, | |||
590 | * We only check root port and downstream ports of | 589 | * We only check root port and downstream ports of |
591 | * PCIe switches | 590 | * PCIe switches |
592 | */ | 591 | */ |
593 | if (!pci_is_pcie(pdev) || | 592 | if (!(edev->mode & (EEH_DEV_ROOT_PORT | EEH_DEV_DS_PORT))) |
594 | (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && | ||
595 | pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)) | ||
596 | return; | 593 | return; |
597 | 594 | ||
598 | pr_debug("%s: Check PCIe link for %s ...\n", | 595 | pr_debug("%s: Check PCIe link for %04x:%02x:%02x.%01x ...\n", |
599 | __func__, pci_name(pdev)); | 596 | __func__, edev->phb->global_number, |
597 | edev->config_addr >> 8, | ||
598 | PCI_SLOT(edev->config_addr & 0xFF), | ||
599 | PCI_FUNC(edev->config_addr & 0xFF)); | ||
600 | 600 | ||
601 | /* Check slot status */ | 601 | /* Check slot status */ |
602 | cap = pdev->pcie_cap; | 602 | cap = edev->pcie_cap; |
603 | eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val); | 603 | eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val); |
604 | if (!(val & PCI_EXP_SLTSTA_PDS)) { | 604 | if (!(val & PCI_EXP_SLTSTA_PDS)) { |
605 | pr_debug(" No card in the slot (0x%04x) !\n", val); | 605 | pr_debug(" No card in the slot (0x%04x) !\n", val); |
@@ -653,8 +653,7 @@ static void eeh_bridge_check_link(struct pci_dev *pdev, | |||
653 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | 653 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) |
654 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) | 654 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) |
655 | 655 | ||
656 | static void eeh_restore_bridge_bars(struct pci_dev *pdev, | 656 | static void eeh_restore_bridge_bars(struct eeh_dev *edev, |
657 | struct eeh_dev *edev, | ||
658 | struct device_node *dn) | 657 | struct device_node *dn) |
659 | { | 658 | { |
660 | int i; | 659 | int i; |
@@ -680,7 +679,7 @@ static void eeh_restore_bridge_bars(struct pci_dev *pdev, | |||
680 | eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]); | 679 | eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]); |
681 | 680 | ||
682 | /* Check the PCIe link is ready */ | 681 | /* Check the PCIe link is ready */ |
683 | eeh_bridge_check_link(pdev, dn); | 682 | eeh_bridge_check_link(edev, dn); |
684 | } | 683 | } |
685 | 684 | ||
686 | static void eeh_restore_device_bars(struct eeh_dev *edev, | 685 | static void eeh_restore_device_bars(struct eeh_dev *edev, |
@@ -729,19 +728,12 @@ static void eeh_restore_device_bars(struct eeh_dev *edev, | |||
729 | */ | 728 | */ |
730 | static void *eeh_restore_one_device_bars(void *data, void *flag) | 729 | static void *eeh_restore_one_device_bars(void *data, void *flag) |
731 | { | 730 | { |
732 | struct pci_dev *pdev = NULL; | ||
733 | struct eeh_dev *edev = (struct eeh_dev *)data; | 731 | struct eeh_dev *edev = (struct eeh_dev *)data; |
734 | struct device_node *dn = eeh_dev_to_of_node(edev); | 732 | struct device_node *dn = eeh_dev_to_of_node(edev); |
735 | 733 | ||
736 | /* Trace the PCI bridge */ | 734 | /* Do special restore for bridges */ |
737 | if (eeh_probe_mode_dev()) { | 735 | if (edev->mode & EEH_DEV_BRIDGE) |
738 | pdev = eeh_dev_to_pci_dev(edev); | 736 | eeh_restore_bridge_bars(edev, dn); |
739 | if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE) | ||
740 | pdev = NULL; | ||
741 | } | ||
742 | |||
743 | if (pdev) | ||
744 | eeh_restore_bridge_bars(pdev, edev, dn); | ||
745 | else | 737 | else |
746 | eeh_restore_device_bars(edev, dn); | 738 | eeh_restore_device_bars(edev, dn); |
747 | 739 | ||
diff --git a/arch/powerpc/kernel/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c index e7ae3484918c..5d753d4f2c75 100644 --- a/arch/powerpc/kernel/eeh_sysfs.c +++ b/arch/powerpc/kernel/eeh_sysfs.c | |||
@@ -56,19 +56,40 @@ EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); | |||
56 | 56 | ||
57 | void eeh_sysfs_add_device(struct pci_dev *pdev) | 57 | void eeh_sysfs_add_device(struct pci_dev *pdev) |
58 | { | 58 | { |
59 | struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); | ||
59 | int rc=0; | 60 | int rc=0; |
60 | 61 | ||
62 | if (edev && (edev->mode & EEH_DEV_SYSFS)) | ||
63 | return; | ||
64 | |||
61 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); | 65 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); |
62 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); | 66 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); |
63 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); | 67 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); |
64 | 68 | ||
65 | if (rc) | 69 | if (rc) |
66 | printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); | 70 | printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); |
71 | else if (edev) | ||
72 | edev->mode |= EEH_DEV_SYSFS; | ||
67 | } | 73 | } |
68 | 74 | ||
69 | void eeh_sysfs_remove_device(struct pci_dev *pdev) | 75 | void eeh_sysfs_remove_device(struct pci_dev *pdev) |
70 | { | 76 | { |
77 | struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); | ||
78 | |||
79 | /* | ||
80 | * The parent directory might have been removed. We needn't | ||
81 | * continue for that case. | ||
82 | */ | ||
83 | if (!pdev->dev.kobj.sd) { | ||
84 | if (edev) | ||
85 | edev->mode &= ~EEH_DEV_SYSFS; | ||
86 | return; | ||
87 | } | ||
88 | |||
71 | device_remove_file(&pdev->dev, &dev_attr_eeh_mode); | 89 | device_remove_file(&pdev->dev, &dev_attr_eeh_mode); |
72 | device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); | 90 | device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); |
73 | device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); | 91 | device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); |
92 | |||
93 | if (edev) | ||
94 | edev->mode &= ~EEH_DEV_SYSFS; | ||
74 | } | 95 | } |
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index f46914a0f33e..7d22a675fe1a 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c | |||
@@ -1462,6 +1462,8 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus) | |||
1462 | /* Allocate bus and devices resources */ | 1462 | /* Allocate bus and devices resources */ |
1463 | pcibios_allocate_bus_resources(bus); | 1463 | pcibios_allocate_bus_resources(bus); |
1464 | pcibios_claim_one_bus(bus); | 1464 | pcibios_claim_one_bus(bus); |
1465 | if (!pci_has_flag(PCI_PROBE_ONLY)) | ||
1466 | pci_assign_unassigned_bus_resources(bus); | ||
1465 | 1467 | ||
1466 | /* Fixup EEH */ | 1468 | /* Fixup EEH */ |
1467 | eeh_add_device_tree_late(bus); | 1469 | eeh_add_device_tree_late(bus); |
diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c index 3f608800c06b..c1e17ae68a08 100644 --- a/arch/powerpc/kernel/pci-hotplug.c +++ b/arch/powerpc/kernel/pci-hotplug.c | |||
@@ -22,45 +22,40 @@ | |||
22 | #include <asm/eeh.h> | 22 | #include <asm/eeh.h> |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * __pcibios_remove_pci_devices - remove all devices under this bus | 25 | * pcibios_release_device - release PCI device |
26 | * @dev: PCI device | ||
27 | * | ||
28 | * The function is called before releasing the indicated PCI device. | ||
29 | */ | ||
30 | void pcibios_release_device(struct pci_dev *dev) | ||
31 | { | ||
32 | eeh_remove_device(dev); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * pcibios_remove_pci_devices - remove all devices under this bus | ||
26 | * @bus: the indicated PCI bus | 37 | * @bus: the indicated PCI bus |
27 | * @purge_pe: destroy the PE on removal of PCI devices | ||
28 | * | 38 | * |
29 | * Remove all of the PCI devices under this bus both from the | 39 | * Remove all of the PCI devices under this bus both from the |
30 | * linux pci device tree, and from the powerpc EEH address cache. | 40 | * linux pci device tree, and from the powerpc EEH address cache. |
31 | * By default, the corresponding PE will be destroied during the | ||
32 | * normal PCI hotplug path. For PCI hotplug during EEH recovery, | ||
33 | * the corresponding PE won't be destroied and deallocated. | ||
34 | */ | 41 | */ |
35 | void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe) | 42 | void pcibios_remove_pci_devices(struct pci_bus *bus) |
36 | { | 43 | { |
37 | struct pci_dev *dev, *tmp; | 44 | struct pci_dev *dev, *tmp; |
38 | struct pci_bus *child_bus; | 45 | struct pci_bus *child_bus; |
39 | 46 | ||
40 | /* First go down child busses */ | 47 | /* First go down child busses */ |
41 | list_for_each_entry(child_bus, &bus->children, node) | 48 | list_for_each_entry(child_bus, &bus->children, node) |
42 | __pcibios_remove_pci_devices(child_bus, purge_pe); | 49 | pcibios_remove_pci_devices(child_bus); |
43 | 50 | ||
44 | pr_debug("PCI: Removing devices on bus %04x:%02x\n", | 51 | pr_debug("PCI: Removing devices on bus %04x:%02x\n", |
45 | pci_domain_nr(bus), bus->number); | 52 | pci_domain_nr(bus), bus->number); |
46 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | 53 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { |
47 | pr_debug(" * Removing %s...\n", pci_name(dev)); | 54 | pr_debug(" Removing %s...\n", pci_name(dev)); |
48 | eeh_remove_bus_device(dev, purge_pe); | ||
49 | pci_stop_and_remove_bus_device(dev); | 55 | pci_stop_and_remove_bus_device(dev); |
50 | } | 56 | } |
51 | } | 57 | } |
52 | 58 | ||
53 | /** | ||
54 | * pcibios_remove_pci_devices - remove all devices under this bus | ||
55 | * @bus: the indicated PCI bus | ||
56 | * | ||
57 | * Remove all of the PCI devices under this bus both from the | ||
58 | * linux pci device tree, and from the powerpc EEH address cache. | ||
59 | */ | ||
60 | void pcibios_remove_pci_devices(struct pci_bus *bus) | ||
61 | { | ||
62 | __pcibios_remove_pci_devices(bus, 1); | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); | 59 | EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); |
65 | 60 | ||
66 | /** | 61 | /** |
@@ -76,7 +71,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); | |||
76 | */ | 71 | */ |
77 | void pcibios_add_pci_devices(struct pci_bus * bus) | 72 | void pcibios_add_pci_devices(struct pci_bus * bus) |
78 | { | 73 | { |
79 | int slotno, num, mode, pass, max; | 74 | int slotno, mode, pass, max; |
80 | struct pci_dev *dev; | 75 | struct pci_dev *dev; |
81 | struct device_node *dn = pci_bus_to_OF_node(bus); | 76 | struct device_node *dn = pci_bus_to_OF_node(bus); |
82 | 77 | ||
@@ -90,11 +85,15 @@ void pcibios_add_pci_devices(struct pci_bus * bus) | |||
90 | /* use ofdt-based probe */ | 85 | /* use ofdt-based probe */ |
91 | of_rescan_bus(dn, bus); | 86 | of_rescan_bus(dn, bus); |
92 | } else if (mode == PCI_PROBE_NORMAL) { | 87 | } else if (mode == PCI_PROBE_NORMAL) { |
93 | /* use legacy probe */ | 88 | /* |
89 | * Use legacy probe. In the partial hotplug case, we | ||
90 | * probably have grandchildren devices unplugged. So | ||
91 | * we don't check the return value from pci_scan_slot() in | ||
92 | * order for fully rescan all the way down to pick them up. | ||
93 | * They can have been removed during partial hotplug. | ||
94 | */ | ||
94 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); | 95 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); |
95 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); | 96 | pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); |
96 | if (!num) | ||
97 | return; | ||
98 | pcibios_setup_bus_devices(bus); | 97 | pcibios_setup_bus_devices(bus); |
99 | max = bus->busn_res.start; | 98 | max = bus->busn_res.start; |
100 | for (pass = 0; pass < 2; pass++) { | 99 | for (pass = 0; pass < 2; pass++) { |
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 6b0ba5854d99..15d9105323bf 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c | |||
@@ -230,11 +230,14 @@ void of_scan_pci_bridge(struct pci_dev *dev) | |||
230 | return; | 230 | return; |
231 | } | 231 | } |
232 | 232 | ||
233 | bus = pci_add_new_bus(dev->bus, dev, busrange[0]); | 233 | bus = pci_find_bus(pci_domain_nr(dev->bus), busrange[0]); |
234 | if (!bus) { | 234 | if (!bus) { |
235 | printk(KERN_ERR "Failed to create pci bus for %s\n", | 235 | bus = pci_add_new_bus(dev->bus, dev, busrange[0]); |
236 | node->full_name); | 236 | if (!bus) { |
237 | return; | 237 | printk(KERN_ERR "Failed to create pci bus for %s\n", |
238 | node->full_name); | ||
239 | return; | ||
240 | } | ||
238 | } | 241 | } |
239 | 242 | ||
240 | bus->primary = dev->bus->number; | 243 | bus->primary = dev->bus->number; |
@@ -292,6 +295,38 @@ void of_scan_pci_bridge(struct pci_dev *dev) | |||
292 | } | 295 | } |
293 | EXPORT_SYMBOL(of_scan_pci_bridge); | 296 | EXPORT_SYMBOL(of_scan_pci_bridge); |
294 | 297 | ||
298 | static struct pci_dev *of_scan_pci_dev(struct pci_bus *bus, | ||
299 | struct device_node *dn) | ||
300 | { | ||
301 | struct pci_dev *dev = NULL; | ||
302 | const u32 *reg; | ||
303 | int reglen, devfn; | ||
304 | |||
305 | pr_debug(" * %s\n", dn->full_name); | ||
306 | if (!of_device_is_available(dn)) | ||
307 | return NULL; | ||
308 | |||
309 | reg = of_get_property(dn, "reg", ®len); | ||
310 | if (reg == NULL || reglen < 20) | ||
311 | return NULL; | ||
312 | devfn = (reg[0] >> 8) & 0xff; | ||
313 | |||
314 | /* Check if the PCI device is already there */ | ||
315 | dev = pci_get_slot(bus, devfn); | ||
316 | if (dev) { | ||
317 | pci_dev_put(dev); | ||
318 | return dev; | ||
319 | } | ||
320 | |||
321 | /* create a new pci_dev for this device */ | ||
322 | dev = of_create_pci_dev(dn, bus, devfn); | ||
323 | if (!dev) | ||
324 | return NULL; | ||
325 | |||
326 | pr_debug(" dev header type: %x\n", dev->hdr_type); | ||
327 | return dev; | ||
328 | } | ||
329 | |||
295 | /** | 330 | /** |
296 | * __of_scan_bus - given a PCI bus node, setup bus and scan for child devices | 331 | * __of_scan_bus - given a PCI bus node, setup bus and scan for child devices |
297 | * @node: device tree node for the PCI bus | 332 | * @node: device tree node for the PCI bus |
@@ -302,8 +337,6 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus, | |||
302 | int rescan_existing) | 337 | int rescan_existing) |
303 | { | 338 | { |
304 | struct device_node *child; | 339 | struct device_node *child; |
305 | const u32 *reg; | ||
306 | int reglen, devfn; | ||
307 | struct pci_dev *dev; | 340 | struct pci_dev *dev; |
308 | 341 | ||
309 | pr_debug("of_scan_bus(%s) bus no %d...\n", | 342 | pr_debug("of_scan_bus(%s) bus no %d...\n", |
@@ -311,16 +344,7 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus, | |||
311 | 344 | ||
312 | /* Scan direct children */ | 345 | /* Scan direct children */ |
313 | for_each_child_of_node(node, child) { | 346 | for_each_child_of_node(node, child) { |
314 | pr_debug(" * %s\n", child->full_name); | 347 | dev = of_scan_pci_dev(bus, child); |
315 | if (!of_device_is_available(child)) | ||
316 | continue; | ||
317 | reg = of_get_property(child, "reg", ®len); | ||
318 | if (reg == NULL || reglen < 20) | ||
319 | continue; | ||
320 | devfn = (reg[0] >> 8) & 0xff; | ||
321 | |||
322 | /* create a new pci_dev for this device */ | ||
323 | dev = of_create_pci_dev(child, bus, devfn); | ||
324 | if (!dev) | 348 | if (!dev) |
325 | continue; | 349 | continue; |
326 | pr_debug(" dev header type: %x\n", dev->hdr_type); | 350 | pr_debug(" dev header type: %x\n", dev->hdr_type); |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 5eccda9fd33f..607902424e73 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -644,7 +644,8 @@ unsigned char ibm_architecture_vec[] = { | |||
644 | W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ | 644 | W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ |
645 | W(0xffff0000), W(0x003e0000), /* POWER6 */ | 645 | W(0xffff0000), W(0x003e0000), /* POWER6 */ |
646 | W(0xffff0000), W(0x003f0000), /* POWER7 */ | 646 | W(0xffff0000), W(0x003f0000), /* POWER7 */ |
647 | W(0xffff0000), W(0x004b0000), /* POWER8 */ | 647 | W(0xffff0000), W(0x004b0000), /* POWER8E */ |
648 | W(0xffff0000), W(0x004d0000), /* POWER8 */ | ||
648 | W(0xffffffff), W(0x0f000004), /* all 2.07-compliant */ | 649 | W(0xffffffff), W(0x0f000004), /* all 2.07-compliant */ |
649 | W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ | 650 | W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ |
650 | W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ | 651 | W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ |
@@ -706,7 +707,7 @@ unsigned char ibm_architecture_vec[] = { | |||
706 | * must match by the macro below. Update the definition if | 707 | * must match by the macro below. Update the definition if |
707 | * the structure layout changes. | 708 | * the structure layout changes. |
708 | */ | 709 | */ |
709 | #define IBM_ARCH_VEC_NRCORES_OFFSET 117 | 710 | #define IBM_ARCH_VEC_NRCORES_OFFSET 125 |
710 | W(NR_CPUS), /* number of cores supported */ | 711 | W(NR_CPUS), /* number of cores supported */ |
711 | 0, | 712 | 0, |
712 | 0, | 713 | 0, |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 654e479802f2..f096e72262f4 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -38,9 +38,6 @@ jiffies = jiffies_64 + 4; | |||
38 | #endif | 38 | #endif |
39 | SECTIONS | 39 | SECTIONS |
40 | { | 40 | { |
41 | . = 0; | ||
42 | reloc_start = .; | ||
43 | |||
44 | . = KERNELBASE; | 41 | . = KERNELBASE; |
45 | 42 | ||
46 | /* | 43 | /* |