Skip to content

Commit

Permalink
USB: EHCI: remove PORT_RWC_BITS when clearing USB_PORT_FEAT_ENABLE
Browse files Browse the repository at this point in the history
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: Stephen Warren <swarren@nvidia.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Stephen Warren authored and Greg Kroah-Hartman committed Apr 20, 2012
1 parent cae1876 commit 6d5f89c
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 22 deletions.
17 changes: 7 additions & 10 deletions drivers/usb/host/ehci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -757,22 +757,19 @@ 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),
status_reg);
ehci_writel(ehci, temp & ~PORT_POWER,
status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
if (ehci->has_lpm) {
/* clear PORTSC bits on disconnect */
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 */
Expand Down
13 changes: 1 addition & 12 deletions drivers/usb/host/ehci-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit 6d5f89c

Please sign in to comment.