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: Stephen Warren <swarren@nvidia.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
cae18768ac
commit
6d5f89c7b4
2 changed files with 8 additions and 22 deletions
|
@ -704,6 +704,7 @@ static int ehci_hub_control (
|
||||||
goto error;
|
goto error;
|
||||||
wIndex--;
|
wIndex--;
|
||||||
temp = ehci_readl(ehci, status_reg);
|
temp = ehci_readl(ehci, status_reg);
|
||||||
|
temp &= ~PORT_RWC_BITS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Even if OWNER is set, so the port is owned by the
|
* 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);
|
ehci_writel(ehci, temp & ~PORT_PE, status_reg);
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_C_ENABLE:
|
case USB_PORT_FEAT_C_ENABLE:
|
||||||
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
|
ehci_writel(ehci, temp | PORT_PEC, status_reg);
|
||||||
status_reg);
|
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_SUSPEND:
|
case USB_PORT_FEAT_SUSPEND:
|
||||||
if (temp & PORT_RESET)
|
if (temp & PORT_RESET)
|
||||||
|
@ -747,7 +747,7 @@ static int ehci_hub_control (
|
||||||
spin_lock_irqsave(&ehci->lock, flags);
|
spin_lock_irqsave(&ehci->lock, flags);
|
||||||
}
|
}
|
||||||
/* resume signaling for 20 msec */
|
/* 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_writel(ehci, temp | PORT_RESUME, status_reg);
|
||||||
ehci->reset_done[wIndex] = jiffies
|
ehci->reset_done[wIndex] = jiffies
|
||||||
+ msecs_to_jiffies(20);
|
+ msecs_to_jiffies(20);
|
||||||
|
@ -757,9 +757,8 @@ static int ehci_hub_control (
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_POWER:
|
case USB_PORT_FEAT_POWER:
|
||||||
if (HCS_PPC (ehci->hcs_params))
|
if (HCS_PPC (ehci->hcs_params))
|
||||||
ehci_writel(ehci,
|
ehci_writel(ehci, temp & ~PORT_POWER,
|
||||||
temp & ~(PORT_RWC_BITS | PORT_POWER),
|
status_reg);
|
||||||
status_reg);
|
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_C_CONNECTION:
|
case USB_PORT_FEAT_C_CONNECTION:
|
||||||
if (ehci->has_lpm) {
|
if (ehci->has_lpm) {
|
||||||
|
@ -767,12 +766,10 @@ static int ehci_hub_control (
|
||||||
temp &= ~PORT_LPM;
|
temp &= ~PORT_LPM;
|
||||||
temp &= ~PORT_DEV_ADDR;
|
temp &= ~PORT_DEV_ADDR;
|
||||||
}
|
}
|
||||||
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
|
ehci_writel(ehci, temp | PORT_CSC, status_reg);
|
||||||
status_reg);
|
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_C_OVER_CURRENT:
|
case USB_PORT_FEAT_C_OVER_CURRENT:
|
||||||
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
|
ehci_writel(ehci, temp | PORT_OCC, status_reg);
|
||||||
status_reg);
|
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_C_RESET:
|
case USB_PORT_FEAT_C_RESET:
|
||||||
/* GetPortStatus clears reset */
|
/* GetPortStatus clears reset */
|
||||||
|
|
|
@ -148,18 +148,7 @@ static int tegra_ehci_hub_control(
|
||||||
|
|
||||||
spin_lock_irqsave(&ehci->lock, flags);
|
spin_lock_irqsave(&ehci->lock, flags);
|
||||||
|
|
||||||
/*
|
if (typeReq == GetPortStatus) {
|
||||||
* 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) {
|
|
||||||
temp = ehci_readl(ehci, status_reg);
|
temp = ehci_readl(ehci, status_reg);
|
||||||
if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
|
if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
|
||||||
/* Resume completed, re-enable disconnect detection */
|
/* Resume completed, re-enable disconnect detection */
|
||||||
|
|
Loading…
Reference in a new issue