Commit 0ed9a57e authored by Andiry Xu's avatar Andiry Xu Committed by Sarah Sharp

xHCI: report USB3.0 portstatus comply with USB3.0 specification

USB3.0 specification has different wPortStatus and wPortChange definitions
from USB2.0 specification. Since USB3 root hub and USB2 root hub are split
now and USB3 hub only has USB3 protocol ports, we should modify the
portstatus and portchange report of USB3 ports to comply with USB3.0
specification.
Signed-off-by: default avatarAndiry Xu <andiry.xu@amd.com>
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
parent 2c441780
...@@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1, ...@@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1,
*status = le16_to_cpu(hub->status->port.wPortStatus); *status = le16_to_cpu(hub->status->port.wPortStatus);
*change = le16_to_cpu(hub->status->port.wPortChange); *change = le16_to_cpu(hub->status->port.wPortChange);
if ((hub->hdev->parent != NULL) &&
hub_is_superspeed(hub->hdev)) {
/* Translate the USB 3 port status */
u16 tmp = *status & USB_SS_PORT_STAT_MASK;
if (*status & USB_SS_PORT_STAT_POWER)
tmp |= USB_PORT_STAT_POWER;
*status = tmp;
}
ret = 0; ret = 0;
} }
mutex_unlock(&hub->status_mutex); mutex_unlock(&hub->status_mutex);
...@@ -2160,11 +2151,40 @@ static int hub_port_reset(struct usb_hub *hub, int port1, ...@@ -2160,11 +2151,40 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
return status; return status;
} }
/* Check if a port is power on */
static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
{
int ret = 0;
if (hub_is_superspeed(hub->hdev)) {
if (portstatus & USB_SS_PORT_STAT_POWER)
ret = 1;
} else {
if (portstatus & USB_PORT_STAT_POWER)
ret = 1;
}
return ret;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
#define MASK_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION | \ /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
USB_PORT_STAT_SUSPEND) static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
#define WANT_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION) {
int ret = 0;
if (hub_is_superspeed(hub->hdev)) {
if ((portstatus & USB_PORT_STAT_LINK_STATE)
== USB_SS_PORT_LS_U3)
ret = 1;
} else {
if (portstatus & USB_PORT_STAT_SUSPEND)
ret = 1;
}
return ret;
}
/* Determine whether the device on a port is ready for a normal resume, /* Determine whether the device on a port is ready for a normal resume,
* is ready for a reset-resume, or should be disconnected. * is ready for a reset-resume, or should be disconnected.
...@@ -2174,7 +2194,9 @@ static int check_port_resume_type(struct usb_device *udev, ...@@ -2174,7 +2194,9 @@ static int check_port_resume_type(struct usb_device *udev,
int status, unsigned portchange, unsigned portstatus) int status, unsigned portchange, unsigned portstatus)
{ {
/* Is the device still present? */ /* Is the device still present? */
if (status || (portstatus & MASK_BITS) != WANT_BITS) { if (status || port_is_suspended(hub, portstatus) ||
!port_is_power_on(hub, portstatus) ||
!(portstatus & USB_PORT_STAT_CONNECTION)) {
if (status >= 0) if (status >= 0)
status = -ENODEV; status = -ENODEV;
} }
...@@ -2439,7 +2461,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) ...@@ -2439,7 +2461,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
/* Skip the initial Clear-Suspend step for a remote wakeup */ /* Skip the initial Clear-Suspend step for a remote wakeup */
status = hub_port_status(hub, port1, &portstatus, &portchange); status = hub_port_status(hub, port1, &portstatus, &portchange);
if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND)) if (status == 0 && !port_is_suspended(hub, portstatus))
goto SuspendCleared; goto SuspendCleared;
// dev_dbg(hub->intfdev, "resume port %d\n", port1); // dev_dbg(hub->intfdev, "resume port %d\n", port1);
...@@ -3147,7 +3169,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, ...@@ -3147,7 +3169,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* maybe switch power back on (e.g. root hub was reset) */ /* maybe switch power back on (e.g. root hub was reset) */
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
&& !(portstatus & USB_PORT_STAT_POWER)) && !port_is_power_on(hub, portstatus))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
if (portstatus & USB_PORT_STAT_ENABLE) if (portstatus & USB_PORT_STAT_ENABLE)
......
...@@ -431,9 +431,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -431,9 +431,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
} }
xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
/* FIXME - should we return a port status value like the USB
* 3.0 external hubs do?
*/
/* wPortChange bits */ /* wPortChange bits */
if (temp & PORT_CSC) if (temp & PORT_CSC)
status |= USB_PORT_STAT_C_CONNECTION << 16; status |= USB_PORT_STAT_C_CONNECTION << 16;
...@@ -441,13 +438,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -441,13 +438,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
status |= USB_PORT_STAT_C_ENABLE << 16; status |= USB_PORT_STAT_C_ENABLE << 16;
if ((temp & PORT_OCC)) if ((temp & PORT_OCC))
status |= USB_PORT_STAT_C_OVERCURRENT << 16; status |= USB_PORT_STAT_C_OVERCURRENT << 16;
/* if ((temp & PORT_RC))
* FIXME ignoring reset and USB 2.1/3.0 specific status |= USB_PORT_STAT_C_RESET << 16;
* changes /* USB3.0 only */
*/ if (hcd->speed == HCD_USB3) {
if ((temp & PORT_PLS_MASK) == XDEV_U3 if ((temp & PORT_PLC))
&& (temp & PORT_POWER)) status |= USB_PORT_STAT_C_LINK_STATE << 16;
status |= 1 << USB_PORT_FEAT_SUSPEND; if ((temp & PORT_WRC))
status |= USB_PORT_STAT_C_BH_RESET << 16;
}
if (hcd->speed != HCD_USB3) {
if ((temp & PORT_PLS_MASK) == XDEV_U3
&& (temp & PORT_POWER))
status |= USB_PORT_STAT_SUSPEND;
}
if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
if ((temp & PORT_RESET) || !(temp & PORT_PE)) if ((temp & PORT_RESET) || !(temp & PORT_PE))
goto error; goto error;
...@@ -490,8 +495,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -490,8 +495,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
status |= USB_PORT_STAT_OVERCURRENT; status |= USB_PORT_STAT_OVERCURRENT;
if (temp & PORT_RESET) if (temp & PORT_RESET)
status |= USB_PORT_STAT_RESET; status |= USB_PORT_STAT_RESET;
if (temp & PORT_POWER) if (temp & PORT_POWER) {
status |= USB_PORT_STAT_POWER; if (hcd->speed == HCD_USB3)
status |= USB_SS_PORT_STAT_POWER;
else
status |= USB_PORT_STAT_POWER;
}
/* Port Link State */
if (hcd->speed == HCD_USB3) {
/* resume state is a xHCI internal state.
* Do not report it to usb core.
*/
if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
status |= (temp & PORT_PLS_MASK);
}
if (bus_state->port_c_suspend & (1 << wIndex)) if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND; status |= 1 << USB_PORT_FEAT_C_SUSPEND;
xhci_dbg(xhci, "Get port status returned 0x%x\n", status); xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment