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

Commit 6d5f89c7 authored by Stephen Warren's avatar Stephen Warren Committed by Greg Kroah-Hartman
Browse files

USB: EHCI: remove PORT_RWC_BITS when clearing USB_PORT_FEAT_ENABLE



In the ClearPortFeature/USB_PORT_FEAT_ENABLE case, ehci_hub_control()
would read from status_reg, clear PORT_PE, and write the result back to
status_reg. This would clear any bits in PORT_RWC_BITS that were set in
the registers. Fix this by masking these bits off before the write.

Since this masking is common across all ClearPortFeature cases, move it
into a single early location to avoid duplicating it.

Remove the same bugfix from ehci-tegra.c's tegra_ehci_hub_control(), now
that this case is correctly handled by the core.

Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cae18768
Loading
Loading
Loading
Loading
+7 −10
Original line number Diff line number Diff line
@@ -704,6 +704,7 @@ static int ehci_hub_control (
			goto error;
		wIndex--;
		temp = ehci_readl(ehci, status_reg);
		temp &= ~PORT_RWC_BITS;

		/*
		 * Even if OWNER is set, so the port is owned by the
@@ -717,8 +718,7 @@ static int ehci_hub_control (
			ehci_writel(ehci, temp & ~PORT_PE, status_reg);
			break;
		case USB_PORT_FEAT_C_ENABLE:
			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
					status_reg);
			ehci_writel(ehci, temp | PORT_PEC, status_reg);
			break;
		case USB_PORT_FEAT_SUSPEND:
			if (temp & PORT_RESET)
@@ -747,7 +747,7 @@ static int ehci_hub_control (
				spin_lock_irqsave(&ehci->lock, flags);
			}
			/* resume signaling for 20 msec */
			temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
			temp &= ~PORT_WAKE_BITS;
			ehci_writel(ehci, temp | PORT_RESUME, status_reg);
			ehci->reset_done[wIndex] = jiffies
					+ msecs_to_jiffies(20);
@@ -757,8 +757,7 @@ static int ehci_hub_control (
			break;
		case USB_PORT_FEAT_POWER:
			if (HCS_PPC (ehci->hcs_params))
				ehci_writel(ehci,
					  temp & ~(PORT_RWC_BITS | PORT_POWER),
				ehci_writel(ehci, temp & ~PORT_POWER,
						status_reg);
			break;
		case USB_PORT_FEAT_C_CONNECTION:
@@ -767,12 +766,10 @@ static int ehci_hub_control (
				temp &= ~PORT_LPM;
				temp &= ~PORT_DEV_ADDR;
			}
			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
					status_reg);
			ehci_writel(ehci, temp | PORT_CSC, status_reg);
			break;
		case USB_PORT_FEAT_C_OVER_CURRENT:
			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
					status_reg);
			ehci_writel(ehci, temp | PORT_OCC, status_reg);
			break;
		case USB_PORT_FEAT_C_RESET:
			/* GetPortStatus clears reset */
+1 −12
Original line number Diff line number Diff line
@@ -148,18 +148,7 @@ static int tegra_ehci_hub_control(

	spin_lock_irqsave(&ehci->lock, flags);

	/*
	 * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
	 * that are write on clear, by writing back the register read value, so
	 * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
	 */
	if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
		temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
		ehci_writel(ehci, temp & ~PORT_PE, status_reg);
		goto done;
	}

	else if (typeReq == GetPortStatus) {
	if (typeReq == GetPortStatus) {
		temp = ehci_readl(ehci, status_reg);
		if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
			/* Resume completed, re-enable disconnect detection */