Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6592e02a authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Jesse Barnes
Browse files

pciehp: poll cmd completion if hotplug interrupt is disabled



Fix improper long wait for command completion in pciehp probing.

As described in PCI Express specification, software notification is
not generated if the command that occurs as a result of a write to the
Slot Control register that disables software notification of command
completed events. Since pciehp driver doesn't take it into account,
such command is issued in pciehp probing, and it causes improper long
wait for command completion.

This patch changes the pciehp driver to take such command into
account.

Signed-off-by: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarKristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 5808639b
Loading
Loading
Loading
Loading
+38 −4
Original line number Diff line number Diff line
@@ -247,13 +247,37 @@ static inline void pciehp_free_irq(struct controller *ctrl)
		free_irq(ctrl->pci_dev->irq, ctrl);
}

static inline int pcie_wait_cmd(struct controller *ctrl)
static inline int pcie_poll_cmd(struct controller *ctrl)
{
	u16 slot_status;
	int timeout = 1000;

	if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
		if (slot_status & CMD_COMPLETED)
			goto completed;
	for (timeout = 1000; timeout > 0; timeout -= 100) {
		msleep(100);
		if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
			if (slot_status & CMD_COMPLETED)
				goto completed;
	}
	return 0;	/* timeout */

completed:
	pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
	return timeout;
}

static inline int pcie_wait_cmd(struct controller *ctrl, int poll)
{
	int retval = 0;
	unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
	unsigned long timeout = msecs_to_jiffies(msecs);
	int rc;

	if (poll)
		rc = pcie_poll_cmd(ctrl);
	else
		rc = wait_event_interruptible_timeout(ctrl->queue,
					      !ctrl->cmd_busy, timeout);
	if (!rc)
@@ -331,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
	/*
	 * Wait for command completion.
	 */
	if (!retval && !ctrl->no_cmd_complete)
		retval = pcie_wait_cmd(ctrl);
	if (!retval && !ctrl->no_cmd_complete) {
		int poll = 0;
		/*
		 * if hotplug interrupt is not enabled or command
		 * completed interrupt is not enabled, we need to poll
		 * command completed event.
		 */
		if (!(slot_ctrl & HP_INTR_ENABLE) ||
		    !(slot_ctrl & CMD_CMPL_INTR_ENABLE))
			poll = 1;
                retval = pcie_wait_cmd(ctrl, poll);
	}
 out:
	mutex_unlock(&ctrl->ctrl_lock);
	return retval;