diff options
| -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 |
3 files changed, 44 insertions, 0 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)) |
