diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2013-08-15 16:41:33 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-08-15 16:41:33 -0400 |
commit | 7d8c4a2c5ae6d76f1142fb052d698b3c40ce518c (patch) | |
tree | e5f4d7779bd2e6b4e9ccc3e73d5c40bb537513e8 /drivers | |
parent | 63ef41811b86432101b4627ff07c9671f93a483f (diff) | |
parent | 9a3d2b9beefd5b07c1d8f70ded01b88f203ee304 (diff) |
Merge branch 'pci/aw-reset-v5' into next
* pci/aw-reset-v5:
PCI: Add pci_probe_reset_slot() and pci_probe_reset_bus()
PCI: Remove aer_do_secondary_bus_reset()
PCI: Tune secondary bus reset timing
PCI: Wake-up devices before saving config space for reset
PCI: Add pci_reset_slot() and pci_reset_bus()
PCI: Split out pci_dev lock/unlock and save/restore
PCI: Add slot reset option to pci_dev_reset()
PCI: pciehp: Add reset_slot() method
PCI: Add hotplug_slot_ops.reset_slot()
PCI: Add pci_reset_bridge_secondary_bus()
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 31 | ||||
-rw-r--r-- | drivers/pci/pci.c | 373 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.c | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 35 |
7 files changed, 393 insertions, 62 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 7fb326983ed6..541bbe6d5343 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -155,6 +155,7 @@ void pciehp_green_led_off(struct slot *slot); | |||
155 | void pciehp_green_led_blink(struct slot *slot); | 155 | void pciehp_green_led_blink(struct slot *slot); |
156 | int pciehp_check_link_status(struct controller *ctrl); | 156 | int pciehp_check_link_status(struct controller *ctrl); |
157 | void pciehp_release_ctrl(struct controller *ctrl); | 157 | void pciehp_release_ctrl(struct controller *ctrl); |
158 | int pciehp_reset_slot(struct slot *slot, int probe); | ||
158 | 159 | ||
159 | static inline const char *slot_name(struct slot *slot) | 160 | static inline const char *slot_name(struct slot *slot) |
160 | { | 161 | { |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 7d72c5e2eba9..f4a18f51a29c 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -69,6 +69,7 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); | |||
69 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 69 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
70 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 70 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
71 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 71 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
72 | static int reset_slot (struct hotplug_slot *slot, int probe); | ||
72 | 73 | ||
73 | /** | 74 | /** |
74 | * release_slot - free up the memory used by a slot | 75 | * release_slot - free up the memory used by a slot |
@@ -111,6 +112,7 @@ static int init_slot(struct controller *ctrl) | |||
111 | ops->disable_slot = disable_slot; | 112 | ops->disable_slot = disable_slot; |
112 | ops->get_power_status = get_power_status; | 113 | ops->get_power_status = get_power_status; |
113 | ops->get_adapter_status = get_adapter_status; | 114 | ops->get_adapter_status = get_adapter_status; |
115 | ops->reset_slot = reset_slot; | ||
114 | if (MRL_SENS(ctrl)) | 116 | if (MRL_SENS(ctrl)) |
115 | ops->get_latch_status = get_latch_status; | 117 | ops->get_latch_status = get_latch_status; |
116 | if (ATTN_LED(ctrl)) { | 118 | if (ATTN_LED(ctrl)) { |
@@ -223,6 +225,16 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | |||
223 | return pciehp_get_adapter_status(slot, value); | 225 | return pciehp_get_adapter_status(slot, value); |
224 | } | 226 | } |
225 | 227 | ||
228 | static int reset_slot(struct hotplug_slot *hotplug_slot, int probe) | ||
229 | { | ||
230 | struct slot *slot = hotplug_slot->private; | ||
231 | |||
232 | ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", | ||
233 | __func__, slot_name(slot)); | ||
234 | |||
235 | return pciehp_reset_slot(slot, probe); | ||
236 | } | ||
237 | |||
226 | static int pciehp_probe(struct pcie_device *dev) | 238 | static int pciehp_probe(struct pcie_device *dev) |
227 | { | 239 | { |
228 | int rc; | 240 | int rc; |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index b2255736ac81..51f56ef4ab6f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -749,6 +749,37 @@ static void pcie_disable_notification(struct controller *ctrl) | |||
749 | ctrl_warn(ctrl, "Cannot disable software notification\n"); | 749 | ctrl_warn(ctrl, "Cannot disable software notification\n"); |
750 | } | 750 | } |
751 | 751 | ||
752 | /* | ||
753 | * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary | ||
754 | * bus reset of the bridge, but if the slot supports surprise removal we need | ||
755 | * to disable presence detection around the bus reset and clear any spurious | ||
756 | * events after. | ||
757 | */ | ||
758 | int pciehp_reset_slot(struct slot *slot, int probe) | ||
759 | { | ||
760 | struct controller *ctrl = slot->ctrl; | ||
761 | |||
762 | if (probe) | ||
763 | return 0; | ||
764 | |||
765 | if (HP_SUPR_RM(ctrl)) { | ||
766 | pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE); | ||
767 | if (pciehp_poll_mode) | ||
768 | del_timer_sync(&ctrl->poll_timer); | ||
769 | } | ||
770 | |||
771 | pci_reset_bridge_secondary_bus(ctrl->pcie->port); | ||
772 | |||
773 | if (HP_SUPR_RM(ctrl)) { | ||
774 | pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDC); | ||
775 | pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE); | ||
776 | if (pciehp_poll_mode) | ||
777 | int_poll_timeout(ctrl->poll_timer.data); | ||
778 | } | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | |||
752 | int pcie_init_notification(struct controller *ctrl) | 783 | int pcie_init_notification(struct controller *ctrl) |
753 | { | 784 | { |
754 | if (pciehp_request_irq(ctrl)) | 785 | if (pciehp_request_irq(ctrl)) |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7d6ce2ec04ec..10e3c4e15178 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/pm_runtime.h> | 24 | #include <linux/pm_runtime.h> |
25 | #include <linux/pci_hotplug.h> | ||
25 | #include <asm-generic/pci-bridge.h> | 26 | #include <asm-generic/pci-bridge.h> |
26 | #include <asm/setup.h> | 27 | #include <asm/setup.h> |
27 | #include "pci.h" | 28 | #include "pci.h" |
@@ -3288,9 +3289,42 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) | |||
3288 | return 0; | 3289 | return 0; |
3289 | } | 3290 | } |
3290 | 3291 | ||
3291 | static int pci_parent_bus_reset(struct pci_dev *dev, int probe) | 3292 | /** |
3293 | * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge. | ||
3294 | * @dev: Bridge device | ||
3295 | * | ||
3296 | * Use the bridge control register to assert reset on the secondary bus. | ||
3297 | * Devices on the secondary bus are left in power-on state. | ||
3298 | */ | ||
3299 | void pci_reset_bridge_secondary_bus(struct pci_dev *dev) | ||
3292 | { | 3300 | { |
3293 | u16 ctrl; | 3301 | u16 ctrl; |
3302 | |||
3303 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl); | ||
3304 | ctrl |= PCI_BRIDGE_CTL_BUS_RESET; | ||
3305 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); | ||
3306 | /* | ||
3307 | * PCI spec v3.0 7.6.4.2 requires minimum Trst of 1ms. Double | ||
3308 | * this to 2ms to ensure that we meet the minium requirement. | ||
3309 | */ | ||
3310 | msleep(2); | ||
3311 | |||
3312 | ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; | ||
3313 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); | ||
3314 | |||
3315 | /* | ||
3316 | * Trhfa for conventional PCI is 2^25 clock cycles. | ||
3317 | * Assuming a minimum 33MHz clock this results in a 1s | ||
3318 | * delay before we can consider subordinate devices to | ||
3319 | * be re-initialized. PCIe has some ways to shorten this, | ||
3320 | * but we don't make use of them yet. | ||
3321 | */ | ||
3322 | ssleep(1); | ||
3323 | } | ||
3324 | EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus); | ||
3325 | |||
3326 | static int pci_parent_bus_reset(struct pci_dev *dev, int probe) | ||
3327 | { | ||
3294 | struct pci_dev *pdev; | 3328 | struct pci_dev *pdev; |
3295 | 3329 | ||
3296 | if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self) | 3330 | if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self) |
@@ -3303,18 +3337,40 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) | |||
3303 | if (probe) | 3337 | if (probe) |
3304 | return 0; | 3338 | return 0; |
3305 | 3339 | ||
3306 | pci_read_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, &ctrl); | 3340 | pci_reset_bridge_secondary_bus(dev->bus->self); |
3307 | ctrl |= PCI_BRIDGE_CTL_BUS_RESET; | ||
3308 | pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); | ||
3309 | msleep(100); | ||
3310 | |||
3311 | ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; | ||
3312 | pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); | ||
3313 | msleep(100); | ||
3314 | 3341 | ||
3315 | return 0; | 3342 | return 0; |
3316 | } | 3343 | } |
3317 | 3344 | ||
3345 | static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe) | ||
3346 | { | ||
3347 | int rc = -ENOTTY; | ||
3348 | |||
3349 | if (!hotplug || !try_module_get(hotplug->ops->owner)) | ||
3350 | return rc; | ||
3351 | |||
3352 | if (hotplug->ops->reset_slot) | ||
3353 | rc = hotplug->ops->reset_slot(hotplug, probe); | ||
3354 | |||
3355 | module_put(hotplug->ops->owner); | ||
3356 | |||
3357 | return rc; | ||
3358 | } | ||
3359 | |||
3360 | static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) | ||
3361 | { | ||
3362 | struct pci_dev *pdev; | ||
3363 | |||
3364 | if (dev->subordinate || !dev->slot) | ||
3365 | return -ENOTTY; | ||
3366 | |||
3367 | list_for_each_entry(pdev, &dev->bus->devices, bus_list) | ||
3368 | if (pdev != dev && pdev->slot == dev->slot) | ||
3369 | return -ENOTTY; | ||
3370 | |||
3371 | return pci_reset_hotplug_slot(dev->slot->hotplug, probe); | ||
3372 | } | ||
3373 | |||
3318 | static int __pci_dev_reset(struct pci_dev *dev, int probe) | 3374 | static int __pci_dev_reset(struct pci_dev *dev, int probe) |
3319 | { | 3375 | { |
3320 | int rc; | 3376 | int rc; |
@@ -3337,27 +3393,65 @@ static int __pci_dev_reset(struct pci_dev *dev, int probe) | |||
3337 | if (rc != -ENOTTY) | 3393 | if (rc != -ENOTTY) |
3338 | goto done; | 3394 | goto done; |
3339 | 3395 | ||
3396 | rc = pci_dev_reset_slot_function(dev, probe); | ||
3397 | if (rc != -ENOTTY) | ||
3398 | goto done; | ||
3399 | |||
3340 | rc = pci_parent_bus_reset(dev, probe); | 3400 | rc = pci_parent_bus_reset(dev, probe); |
3341 | done: | 3401 | done: |
3342 | return rc; | 3402 | return rc; |
3343 | } | 3403 | } |
3344 | 3404 | ||
3405 | static void pci_dev_lock(struct pci_dev *dev) | ||
3406 | { | ||
3407 | pci_cfg_access_lock(dev); | ||
3408 | /* block PM suspend, driver probe, etc. */ | ||
3409 | device_lock(&dev->dev); | ||
3410 | } | ||
3411 | |||
3412 | static void pci_dev_unlock(struct pci_dev *dev) | ||
3413 | { | ||
3414 | device_unlock(&dev->dev); | ||
3415 | pci_cfg_access_unlock(dev); | ||
3416 | } | ||
3417 | |||
3418 | static void pci_dev_save_and_disable(struct pci_dev *dev) | ||
3419 | { | ||
3420 | /* | ||
3421 | * Wake-up device prior to save. PM registers default to D0 after | ||
3422 | * reset and a simple register restore doesn't reliably return | ||
3423 | * to a non-D0 state anyway. | ||
3424 | */ | ||
3425 | pci_set_power_state(dev, PCI_D0); | ||
3426 | |||
3427 | pci_save_state(dev); | ||
3428 | /* | ||
3429 | * Disable the device by clearing the Command register, except for | ||
3430 | * INTx-disable which is set. This not only disables MMIO and I/O port | ||
3431 | * BARs, but also prevents the device from being Bus Master, preventing | ||
3432 | * DMA from the device including MSI/MSI-X interrupts. For PCI 2.3 | ||
3433 | * compliant devices, INTx-disable prevents legacy interrupts. | ||
3434 | */ | ||
3435 | pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); | ||
3436 | } | ||
3437 | |||
3438 | static void pci_dev_restore(struct pci_dev *dev) | ||
3439 | { | ||
3440 | pci_restore_state(dev); | ||
3441 | } | ||
3442 | |||
3345 | static int pci_dev_reset(struct pci_dev *dev, int probe) | 3443 | static int pci_dev_reset(struct pci_dev *dev, int probe) |
3346 | { | 3444 | { |
3347 | int rc; | 3445 | int rc; |
3348 | 3446 | ||
3349 | if (!probe) { | 3447 | if (!probe) |
3350 | pci_cfg_access_lock(dev); | 3448 | pci_dev_lock(dev); |
3351 | /* block PM suspend, driver probe, etc. */ | ||
3352 | device_lock(&dev->dev); | ||
3353 | } | ||
3354 | 3449 | ||
3355 | rc = __pci_dev_reset(dev, probe); | 3450 | rc = __pci_dev_reset(dev, probe); |
3356 | 3451 | ||
3357 | if (!probe) { | 3452 | if (!probe) |
3358 | device_unlock(&dev->dev); | 3453 | pci_dev_unlock(dev); |
3359 | pci_cfg_access_unlock(dev); | 3454 | |
3360 | } | ||
3361 | return rc; | 3455 | return rc; |
3362 | } | 3456 | } |
3363 | /** | 3457 | /** |
@@ -3448,22 +3542,249 @@ int pci_reset_function(struct pci_dev *dev) | |||
3448 | if (rc) | 3542 | if (rc) |
3449 | return rc; | 3543 | return rc; |
3450 | 3544 | ||
3451 | pci_save_state(dev); | 3545 | pci_dev_save_and_disable(dev); |
3452 | |||
3453 | /* | ||
3454 | * both INTx and MSI are disabled after the Interrupt Disable bit | ||
3455 | * is set and the Bus Master bit is cleared. | ||
3456 | */ | ||
3457 | pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); | ||
3458 | 3546 | ||
3459 | rc = pci_dev_reset(dev, 0); | 3547 | rc = pci_dev_reset(dev, 0); |
3460 | 3548 | ||
3461 | pci_restore_state(dev); | 3549 | pci_dev_restore(dev); |
3462 | 3550 | ||
3463 | return rc; | 3551 | return rc; |
3464 | } | 3552 | } |
3465 | EXPORT_SYMBOL_GPL(pci_reset_function); | 3553 | EXPORT_SYMBOL_GPL(pci_reset_function); |
3466 | 3554 | ||
3555 | /* Lock devices from the top of the tree down */ | ||
3556 | static void pci_bus_lock(struct pci_bus *bus) | ||
3557 | { | ||
3558 | struct pci_dev *dev; | ||
3559 | |||
3560 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
3561 | pci_dev_lock(dev); | ||
3562 | if (dev->subordinate) | ||
3563 | pci_bus_lock(dev->subordinate); | ||
3564 | } | ||
3565 | } | ||
3566 | |||
3567 | /* Unlock devices from the bottom of the tree up */ | ||
3568 | static void pci_bus_unlock(struct pci_bus *bus) | ||
3569 | { | ||
3570 | struct pci_dev *dev; | ||
3571 | |||
3572 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
3573 | if (dev->subordinate) | ||
3574 | pci_bus_unlock(dev->subordinate); | ||
3575 | pci_dev_unlock(dev); | ||
3576 | } | ||
3577 | } | ||
3578 | |||
3579 | /* Lock devices from the top of the tree down */ | ||
3580 | static void pci_slot_lock(struct pci_slot *slot) | ||
3581 | { | ||
3582 | struct pci_dev *dev; | ||
3583 | |||
3584 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | ||
3585 | if (!dev->slot || dev->slot != slot) | ||
3586 | continue; | ||
3587 | pci_dev_lock(dev); | ||
3588 | if (dev->subordinate) | ||
3589 | pci_bus_lock(dev->subordinate); | ||
3590 | } | ||
3591 | } | ||
3592 | |||
3593 | /* Unlock devices from the bottom of the tree up */ | ||
3594 | static void pci_slot_unlock(struct pci_slot *slot) | ||
3595 | { | ||
3596 | struct pci_dev *dev; | ||
3597 | |||
3598 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | ||
3599 | if (!dev->slot || dev->slot != slot) | ||
3600 | continue; | ||
3601 | if (dev->subordinate) | ||
3602 | pci_bus_unlock(dev->subordinate); | ||
3603 | pci_dev_unlock(dev); | ||
3604 | } | ||
3605 | } | ||
3606 | |||
3607 | /* Save and disable devices from the top of the tree down */ | ||
3608 | static void pci_bus_save_and_disable(struct pci_bus *bus) | ||
3609 | { | ||
3610 | struct pci_dev *dev; | ||
3611 | |||
3612 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
3613 | pci_dev_save_and_disable(dev); | ||
3614 | if (dev->subordinate) | ||
3615 | pci_bus_save_and_disable(dev->subordinate); | ||
3616 | } | ||
3617 | } | ||
3618 | |||
3619 | /* | ||
3620 | * Restore devices from top of the tree down - parent bridges need to be | ||
3621 | * restored before we can get to subordinate devices. | ||
3622 | */ | ||
3623 | static void pci_bus_restore(struct pci_bus *bus) | ||
3624 | { | ||
3625 | struct pci_dev *dev; | ||
3626 | |||
3627 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
3628 | pci_dev_restore(dev); | ||
3629 | if (dev->subordinate) | ||
3630 | pci_bus_restore(dev->subordinate); | ||
3631 | } | ||
3632 | } | ||
3633 | |||
3634 | /* Save and disable devices from the top of the tree down */ | ||
3635 | static void pci_slot_save_and_disable(struct pci_slot *slot) | ||
3636 | { | ||
3637 | struct pci_dev *dev; | ||
3638 | |||
3639 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | ||
3640 | if (!dev->slot || dev->slot != slot) | ||
3641 | continue; | ||
3642 | pci_dev_save_and_disable(dev); | ||
3643 | if (dev->subordinate) | ||
3644 | pci_bus_save_and_disable(dev->subordinate); | ||
3645 | } | ||
3646 | } | ||
3647 | |||
3648 | /* | ||
3649 | * Restore devices from top of the tree down - parent bridges need to be | ||
3650 | * restored before we can get to subordinate devices. | ||
3651 | */ | ||
3652 | static void pci_slot_restore(struct pci_slot *slot) | ||
3653 | { | ||
3654 | struct pci_dev *dev; | ||
3655 | |||
3656 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | ||
3657 | if (!dev->slot || dev->slot != slot) | ||
3658 | continue; | ||
3659 | pci_dev_restore(dev); | ||
3660 | if (dev->subordinate) | ||
3661 | pci_bus_restore(dev->subordinate); | ||
3662 | } | ||
3663 | } | ||
3664 | |||
3665 | static int pci_slot_reset(struct pci_slot *slot, int probe) | ||
3666 | { | ||
3667 | int rc; | ||
3668 | |||
3669 | if (!slot) | ||
3670 | return -ENOTTY; | ||
3671 | |||
3672 | if (!probe) | ||
3673 | pci_slot_lock(slot); | ||
3674 | |||
3675 | might_sleep(); | ||
3676 | |||
3677 | rc = pci_reset_hotplug_slot(slot->hotplug, probe); | ||
3678 | |||
3679 | if (!probe) | ||
3680 | pci_slot_unlock(slot); | ||
3681 | |||
3682 | return rc; | ||
3683 | } | ||
3684 | |||
3685 | /** | ||
3686 | * pci_probe_reset_slot - probe whether a PCI slot can be reset | ||
3687 | * @slot: PCI slot to probe | ||
3688 | * | ||
3689 | * Return 0 if slot can be reset, negative if a slot reset is not supported. | ||
3690 | */ | ||
3691 | int pci_probe_reset_slot(struct pci_slot *slot) | ||
3692 | { | ||
3693 | return pci_slot_reset(slot, 1); | ||
3694 | } | ||
3695 | EXPORT_SYMBOL_GPL(pci_probe_reset_slot); | ||
3696 | |||
3697 | /** | ||
3698 | * pci_reset_slot - reset a PCI slot | ||
3699 | * @slot: PCI slot to reset | ||
3700 | * | ||
3701 | * A PCI bus may host multiple slots, each slot may support a reset mechanism | ||
3702 | * independent of other slots. For instance, some slots may support slot power | ||
3703 | * control. In the case of a 1:1 bus to slot architecture, this function may | ||
3704 | * wrap the bus reset to avoid spurious slot related events such as hotplug. | ||
3705 | * Generally a slot reset should be attempted before a bus reset. All of the | ||
3706 | * function of the slot and any subordinate buses behind the slot are reset | ||
3707 | * through this function. PCI config space of all devices in the slot and | ||
3708 | * behind the slot is saved before and restored after reset. | ||
3709 | * | ||
3710 | * Return 0 on success, non-zero on error. | ||
3711 | */ | ||
3712 | int pci_reset_slot(struct pci_slot *slot) | ||
3713 | { | ||
3714 | int rc; | ||
3715 | |||
3716 | rc = pci_slot_reset(slot, 1); | ||
3717 | if (rc) | ||
3718 | return rc; | ||
3719 | |||
3720 | pci_slot_save_and_disable(slot); | ||
3721 | |||
3722 | rc = pci_slot_reset(slot, 0); | ||
3723 | |||
3724 | pci_slot_restore(slot); | ||
3725 | |||
3726 | return rc; | ||
3727 | } | ||
3728 | EXPORT_SYMBOL_GPL(pci_reset_slot); | ||
3729 | |||
3730 | static int pci_bus_reset(struct pci_bus *bus, int probe) | ||
3731 | { | ||
3732 | if (!bus->self) | ||
3733 | return -ENOTTY; | ||
3734 | |||
3735 | if (probe) | ||
3736 | return 0; | ||
3737 | |||
3738 | pci_bus_lock(bus); | ||
3739 | |||
3740 | might_sleep(); | ||
3741 | |||
3742 | pci_reset_bridge_secondary_bus(bus->self); | ||
3743 | |||
3744 | pci_bus_unlock(bus); | ||
3745 | |||
3746 | return 0; | ||
3747 | } | ||
3748 | |||
3749 | /** | ||
3750 | * pci_probe_reset_bus - probe whether a PCI bus can be reset | ||
3751 | * @bus: PCI bus to probe | ||
3752 | * | ||
3753 | * Return 0 if bus can be reset, negative if a bus reset is not supported. | ||
3754 | */ | ||
3755 | int pci_probe_reset_bus(struct pci_bus *bus) | ||
3756 | { | ||
3757 | return pci_bus_reset(bus, 1); | ||
3758 | } | ||
3759 | EXPORT_SYMBOL_GPL(pci_probe_reset_bus); | ||
3760 | |||
3761 | /** | ||
3762 | * pci_reset_bus - reset a PCI bus | ||
3763 | * @bus: top level PCI bus to reset | ||
3764 | * | ||
3765 | * Do a bus reset on the given bus and any subordinate buses, saving | ||
3766 | * and restoring state of all devices. | ||
3767 | * | ||
3768 | * Return 0 on success, non-zero on error. | ||
3769 | */ | ||
3770 | int pci_reset_bus(struct pci_bus *bus) | ||
3771 | { | ||
3772 | int rc; | ||
3773 | |||
3774 | rc = pci_bus_reset(bus, 1); | ||
3775 | if (rc) | ||
3776 | return rc; | ||
3777 | |||
3778 | pci_bus_save_and_disable(bus); | ||
3779 | |||
3780 | rc = pci_bus_reset(bus, 0); | ||
3781 | |||
3782 | pci_bus_restore(bus); | ||
3783 | |||
3784 | return rc; | ||
3785 | } | ||
3786 | EXPORT_SYMBOL_GPL(pci_reset_bus); | ||
3787 | |||
3467 | /** | 3788 | /** |
3468 | * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count | 3789 | * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count |
3469 | * @dev: PCI device to query | 3790 | * @dev: PCI device to query |
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 76ef634caf6f..0bf82a20a0fb 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c | |||
@@ -352,7 +352,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) | |||
352 | reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; | 352 | reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; |
353 | pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); | 353 | pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); |
354 | 354 | ||
355 | aer_do_secondary_bus_reset(dev); | 355 | pci_reset_bridge_secondary_bus(dev); |
356 | dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n"); | 356 | dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n"); |
357 | 357 | ||
358 | /* Clear Root Error Status */ | 358 | /* Clear Root Error Status */ |
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 90ea3e88041f..84420b7c9456 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h | |||
@@ -106,7 +106,6 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig, | |||
106 | } | 106 | } |
107 | 107 | ||
108 | extern struct bus_type pcie_port_bus_type; | 108 | extern struct bus_type pcie_port_bus_type; |
109 | void aer_do_secondary_bus_reset(struct pci_dev *dev); | ||
110 | int aer_init(struct pcie_device *dev); | 109 | int aer_init(struct pcie_device *dev); |
111 | void aer_isr(struct work_struct *work); | 110 | void aer_isr(struct work_struct *work); |
112 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); | 111 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); |
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 8b68ae59b7b6..85ca36f2136d 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -367,39 +367,6 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, | |||
367 | } | 367 | } |
368 | 368 | ||
369 | /** | 369 | /** |
370 | * aer_do_secondary_bus_reset - perform secondary bus reset | ||
371 | * @dev: pointer to bridge's pci_dev data structure | ||
372 | * | ||
373 | * Invoked when performing link reset at Root Port or Downstream Port. | ||
374 | */ | ||
375 | void aer_do_secondary_bus_reset(struct pci_dev *dev) | ||
376 | { | ||
377 | u16 p2p_ctrl; | ||
378 | |||
379 | /* Assert Secondary Bus Reset */ | ||
380 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl); | ||
381 | p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET; | ||
382 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); | ||
383 | |||
384 | /* | ||
385 | * we should send hot reset message for 2ms to allow it time to | ||
386 | * propagate to all downstream ports | ||
387 | */ | ||
388 | msleep(2); | ||
389 | |||
390 | /* De-assert Secondary Bus Reset */ | ||
391 | p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; | ||
392 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); | ||
393 | |||
394 | /* | ||
395 | * System software must wait for at least 100ms from the end | ||
396 | * of a reset of one or more device before it is permitted | ||
397 | * to issue Configuration Requests to those devices. | ||
398 | */ | ||
399 | msleep(200); | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * default_reset_link - default reset function | 370 | * default_reset_link - default reset function |
404 | * @dev: pointer to pci_dev data structure | 371 | * @dev: pointer to pci_dev data structure |
405 | * | 372 | * |
@@ -408,7 +375,7 @@ void aer_do_secondary_bus_reset(struct pci_dev *dev) | |||
408 | */ | 375 | */ |
409 | static pci_ers_result_t default_reset_link(struct pci_dev *dev) | 376 | static pci_ers_result_t default_reset_link(struct pci_dev *dev) |
410 | { | 377 | { |
411 | aer_do_secondary_bus_reset(dev); | 378 | pci_reset_bridge_secondary_bus(dev); |
412 | dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n"); | 379 | dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n"); |
413 | return PCI_ERS_RESULT_RECOVERED; | 380 | return PCI_ERS_RESULT_RECOVERED; |
414 | } | 381 | } |