aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2015-06-08 19:10:50 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-21 13:10:05 -0400
commit5224e2a708f617fb69ea7cb56613838af40af188 (patch)
tree95e743254850a67ee9e7648ca4bd4921f3193d0c
parent30e8a1821385dbd85830b407103f28d989764911 (diff)
PCI: pciehp: Wait for hotplug command completion where necessary
commit a5dd4b4b0570b3bf880d563969b245dfbd170c1e upstream. The commit referenced below deferred waiting for command completion until the start of the next command, allowing hardware to do the latching asynchronously. Unfortunately, being ready to accept a new command is the only indication we have that the previous command is completed. In cases where we need that state change to be enabled, we must still wait for completion. For instance, pciehp_reset_slot() attempts to disable anything that might generate a surprise hotplug on slots that support presence detection. If we don't wait for those settings to latch before the secondary bus reset, we negate any value in attempting to prevent the spurious hotplug. Create a base function with optional wait and helper functions so that pcie_write_cmd() turns back into the "safe" interface which waits before and after issuing a command and add pcie_write_cmd_nowait(), which eliminates the trailing wait for asynchronous completion. The following functions are returned to their previous behavior: pciehp_power_on_slot pciehp_power_off_slot pcie_disable_notification pciehp_reset_slot The rationale is that pciehp_power_on_slot() enables the link and therefore relies on completion of power-on. pciehp_power_off_slot() and pcie_disable_notification() need a wait because data structures may be freed after these calls and continued signaling from the device would be unexpected. And, of course, pciehp_reset_slot() needs to wait for the scenario outlined above. Fixes: 3461a068661c ("PCI: pciehp: Wait for hotplug command completion lazily") Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 0ebf754fc177..6d6868811e56 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -176,20 +176,17 @@ static void pcie_wait_cmd(struct controller *ctrl)
176 jiffies_to_msecs(jiffies - ctrl->cmd_started)); 176 jiffies_to_msecs(jiffies - ctrl->cmd_started));
177} 177}
178 178
179/** 179static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
180 * pcie_write_cmd - Issue controller command 180 u16 mask, bool wait)
181 * @ctrl: controller to which the command is issued
182 * @cmd: command value written to slot control register
183 * @mask: bitmask of slot control register to be modified
184 */
185static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
186{ 181{
187 struct pci_dev *pdev = ctrl_dev(ctrl); 182 struct pci_dev *pdev = ctrl_dev(ctrl);
188 u16 slot_ctrl; 183 u16 slot_ctrl;
189 184
190 mutex_lock(&ctrl->ctrl_lock); 185 mutex_lock(&ctrl->ctrl_lock);
191 186
192 /* Wait for any previous command that might still be in progress */ 187 /*
188 * Always wait for any previous command that might still be in progress
189 */
193 pcie_wait_cmd(ctrl); 190 pcie_wait_cmd(ctrl);
194 191
195 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); 192 pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
@@ -201,9 +198,33 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
201 ctrl->cmd_started = jiffies; 198 ctrl->cmd_started = jiffies;
202 ctrl->slot_ctrl = slot_ctrl; 199 ctrl->slot_ctrl = slot_ctrl;
203 200
201 /*
202 * Optionally wait for the hardware to be ready for a new command,
203 * indicating completion of the above issued command.
204 */
205 if (wait)
206 pcie_wait_cmd(ctrl);
207
204 mutex_unlock(&ctrl->ctrl_lock); 208 mutex_unlock(&ctrl->ctrl_lock);
205} 209}
206 210
211/**
212 * pcie_write_cmd - Issue controller command
213 * @ctrl: controller to which the command is issued
214 * @cmd: command value written to slot control register
215 * @mask: bitmask of slot control register to be modified
216 */
217static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
218{
219 pcie_do_write_cmd(ctrl, cmd, mask, true);
220}
221
222/* Same as above without waiting for the hardware to latch */
223static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask)
224{
225 pcie_do_write_cmd(ctrl, cmd, mask, false);
226}
227
207bool pciehp_check_link_active(struct controller *ctrl) 228bool pciehp_check_link_active(struct controller *ctrl)
208{ 229{
209 struct pci_dev *pdev = ctrl_dev(ctrl); 230 struct pci_dev *pdev = ctrl_dev(ctrl);
@@ -422,7 +443,7 @@ void pciehp_set_attention_status(struct slot *slot, u8 value)
422 default: 443 default:
423 return; 444 return;
424 } 445 }
425 pcie_write_cmd(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); 446 pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC);
426 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, 447 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
427 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); 448 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
428} 449}
@@ -434,7 +455,8 @@ void pciehp_green_led_on(struct slot *slot)
434 if (!PWR_LED(ctrl)) 455 if (!PWR_LED(ctrl))
435 return; 456 return;
436 457
437 pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, PCI_EXP_SLTCTL_PIC); 458 pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
459 PCI_EXP_SLTCTL_PIC);
438 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, 460 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
439 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 461 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
440 PCI_EXP_SLTCTL_PWR_IND_ON); 462 PCI_EXP_SLTCTL_PWR_IND_ON);
@@ -447,7 +469,8 @@ void pciehp_green_led_off(struct slot *slot)
447 if (!PWR_LED(ctrl)) 469 if (!PWR_LED(ctrl))
448 return; 470 return;
449 471
450 pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, PCI_EXP_SLTCTL_PIC); 472 pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
473 PCI_EXP_SLTCTL_PIC);
451 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, 474 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
452 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 475 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
453 PCI_EXP_SLTCTL_PWR_IND_OFF); 476 PCI_EXP_SLTCTL_PWR_IND_OFF);
@@ -460,7 +483,8 @@ void pciehp_green_led_blink(struct slot *slot)
460 if (!PWR_LED(ctrl)) 483 if (!PWR_LED(ctrl))
461 return; 484 return;
462 485
463 pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, PCI_EXP_SLTCTL_PIC); 486 pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
487 PCI_EXP_SLTCTL_PIC);
464 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, 488 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
465 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 489 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
466 PCI_EXP_SLTCTL_PWR_IND_BLINK); 490 PCI_EXP_SLTCTL_PWR_IND_BLINK);
@@ -613,7 +637,7 @@ void pcie_enable_notification(struct controller *ctrl)
613 PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | 637 PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
614 PCI_EXP_SLTCTL_DLLSCE); 638 PCI_EXP_SLTCTL_DLLSCE);
615 639
616 pcie_write_cmd(ctrl, cmd, mask); 640 pcie_write_cmd_nowait(ctrl, cmd, mask);
617 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, 641 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
618 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); 642 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
619} 643}
@@ -664,7 +688,7 @@ int pciehp_reset_slot(struct slot *slot, int probe)
664 pci_reset_bridge_secondary_bus(ctrl->pcie->port); 688 pci_reset_bridge_secondary_bus(ctrl->pcie->port);
665 689
666 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); 690 pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
667 pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); 691 pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask);
668 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, 692 ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
669 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask); 693 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask);
670 if (pciehp_poll_mode) 694 if (pciehp_poll_mode)