PCI: pciehp: Wait for hotplug command completion lazily

Previously we issued a hotplug command and waited for it to complete.  But
there's no need to wait until we're ready to issue the *next* command.  The
next command will probably be much later, so the first one may have already
completed and we may not have to actually wait at all.

Because of hardware errata, some controllers generate command completion
events for some commands but not others.  In the case of Intel CF118 (see
spec update reference), the controller indicates command completion only
for Slot Control writes that change the value of the following bits:

  Power Controller Control
  Power Indicator Control
  Attention Indicator Control
  Electromechanical Interlock Control

Changes to other bits, e.g., the interrupt enable bits, do not cause the
Command Completed bit to be set.  Controllers from AMD and Nvidia are
reported to have similar errata.

These errata cause timeouts when pcie_enable_notification() enables
interrupts.  Previously that timeout occurred at boot-time.  With this
change, the timeout occurs later, when we change the state of the slot
power, indicators, or interlock.  This speeds up boot but causes a timeout
at the first hotplug event on the slot.  Subsequent events don't timeout
because only the first (boot-time) hotplug command updates Slot Control
without touching the power/indicator/interlock controls.

Link: http://www.intel.com/content/www/us/en/processors/xeon/xeon-e7-v2-spec-update.html
Tested-by: Rajat Jain <rajatxjain@gmail.com>	(IDT 807a controller)
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Yinghai Lu <yinghai@kernel.org>
This commit is contained in:
Bjorn Helgaas 2014-06-13 15:06:40 -06:00
parent 4283c70e91
commit 3461a06866

View File

@ -168,6 +168,9 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
mutex_lock(&ctrl->ctrl_lock);
/* Wait for any previous command that might still be in progress */
pcie_wait_cmd(ctrl);
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (slot_status & PCI_EXP_SLTSTA_CC) {
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
@ -200,10 +203,6 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl);
ctrl->slot_ctrl = slot_ctrl;
/*
* Wait for command completion.
*/
pcie_wait_cmd(ctrl);
mutex_unlock(&ctrl->ctrl_lock);
}