Skip to content

Commit a5dd4b4

Browse files
awilliambjorn-helgaas
authored andcommitted
PCI: pciehp: Wait for hotplug command completion where necessary
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: 3461a06 ("PCI: pciehp: Wait for hotplug command completion lazily") Signed-off-by: Alex Williamson <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> CC: [email protected] # v3.17+
1 parent 0824965 commit a5dd4b4

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

drivers/pci/hotplug/pciehp_hpc.c

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -176,20 +176,17 @@ static void pcie_wait_cmd(struct controller *ctrl)
176176
jiffies_to_msecs(jiffies - ctrl->cmd_started));
177177
}
178178

179-
/**
180-
* pcie_write_cmd - Issue controller command
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-
*/
185-
static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
179+
static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
180+
u16 mask, bool wait)
186181
{
187182
struct pci_dev *pdev = ctrl_dev(ctrl);
188183
u16 slot_ctrl;
189184

190185
mutex_lock(&ctrl->ctrl_lock);
191186

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+
*/
193190
pcie_wait_cmd(ctrl);
194191

195192
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)
201198
ctrl->cmd_started = jiffies;
202199
ctrl->slot_ctrl = slot_ctrl;
203200

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+
204208
mutex_unlock(&ctrl->ctrl_lock);
205209
}
206210

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+
*/
217+
static 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 */
223+
static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask)
224+
{
225+
pcie_do_write_cmd(ctrl, cmd, mask, false);
226+
}
227+
207228
bool pciehp_check_link_active(struct controller *ctrl)
208229
{
209230
struct pci_dev *pdev = ctrl_dev(ctrl);
@@ -422,7 +443,7 @@ void pciehp_set_attention_status(struct slot *slot, u8 value)
422443
default:
423444
return;
424445
}
425-
pcie_write_cmd(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC);
446+
pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC);
426447
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
427448
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
428449
}
@@ -434,7 +455,8 @@ void pciehp_green_led_on(struct slot *slot)
434455
if (!PWR_LED(ctrl))
435456
return;
436457

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);
438460
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
439461
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
440462
PCI_EXP_SLTCTL_PWR_IND_ON);
@@ -447,7 +469,8 @@ void pciehp_green_led_off(struct slot *slot)
447469
if (!PWR_LED(ctrl))
448470
return;
449471

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);
451474
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
452475
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
453476
PCI_EXP_SLTCTL_PWR_IND_OFF);
@@ -460,7 +483,8 @@ void pciehp_green_led_blink(struct slot *slot)
460483
if (!PWR_LED(ctrl))
461484
return;
462485

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);
464488
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
465489
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
466490
PCI_EXP_SLTCTL_PWR_IND_BLINK);
@@ -613,7 +637,7 @@ void pcie_enable_notification(struct controller *ctrl)
613637
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
614638
PCI_EXP_SLTCTL_DLLSCE);
615639

616-
pcie_write_cmd(ctrl, cmd, mask);
640+
pcie_write_cmd_nowait(ctrl, cmd, mask);
617641
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
618642
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
619643
}
@@ -664,7 +688,7 @@ int pciehp_reset_slot(struct slot *slot, int probe)
664688
pci_reset_bridge_secondary_bus(ctrl->pcie->port);
665689

666690
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);
668692
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
669693
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask);
670694
if (pciehp_poll_mode)

0 commit comments

Comments
 (0)