aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2011-04-27 06:07:43 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-02 19:42:53 -0400
commit0ed9a57e052a3d20df052a2ff12a3b42380867aa (patch)
tree3e9f2abb102045cbd162a7ebe8563d4e9ee47148
parent2c44178032b046c4113c40d0d459a0d36e39b920 (diff)
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: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
-rw-r--r--drivers/usb/core/hub.c52
-rw-r--r--drivers/usb/host/xhci-hub.c41
2 files changed, 66 insertions, 27 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 93720bdc9efd..dcd78c15f8cd 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1,
379 *status = le16_to_cpu(hub->status->port.wPortStatus); 379 *status = le16_to_cpu(hub->status->port.wPortStatus);
380 *change = le16_to_cpu(hub->status->port.wPortChange); 380 *change = le16_to_cpu(hub->status->port.wPortChange);
381 381
382 if ((hub->hdev->parent != NULL) &&
383 hub_is_superspeed(hub->hdev)) {
384 /* Translate the USB 3 port status */
385 u16 tmp = *status & USB_SS_PORT_STAT_MASK;
386 if (*status & USB_SS_PORT_STAT_POWER)
387 tmp |= USB_PORT_STAT_POWER;
388 *status = tmp;
389 }
390
391 ret = 0; 382 ret = 0;
392 } 383 }
393 mutex_unlock(&hub->status_mutex); 384 mutex_unlock(&hub->status_mutex);
@@ -2160,11 +2151,40 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
2160 return status; 2151 return status;
2161} 2152}
2162 2153
2154/* Check if a port is power on */
2155static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
2156{
2157 int ret = 0;
2158
2159 if (hub_is_superspeed(hub->hdev)) {
2160 if (portstatus & USB_SS_PORT_STAT_POWER)
2161 ret = 1;
2162 } else {
2163 if (portstatus & USB_PORT_STAT_POWER)
2164 ret = 1;
2165 }
2166
2167 return ret;
2168}
2169
2163#ifdef CONFIG_PM 2170#ifdef CONFIG_PM
2164 2171
2165#define MASK_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION | \ 2172/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
2166 USB_PORT_STAT_SUSPEND) 2173static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
2167#define WANT_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION) 2174{
2175 int ret = 0;
2176
2177 if (hub_is_superspeed(hub->hdev)) {
2178 if ((portstatus & USB_PORT_STAT_LINK_STATE)
2179 == USB_SS_PORT_LS_U3)
2180 ret = 1;
2181 } else {
2182 if (portstatus & USB_PORT_STAT_SUSPEND)
2183 ret = 1;
2184 }
2185
2186 return ret;
2187}
2168 2188
2169/* Determine whether the device on a port is ready for a normal resume, 2189/* Determine whether the device on a port is ready for a normal resume,
2170 * is ready for a reset-resume, or should be disconnected. 2190 * 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 int status, unsigned portchange, unsigned portstatus) 2194 int status, unsigned portchange, unsigned portstatus)
2175{ 2195{
2176 /* Is the device still present? */ 2196 /* Is the device still present? */
2177 if (status || (portstatus & MASK_BITS) != WANT_BITS) { 2197 if (status || port_is_suspended(hub, portstatus) ||
2198 !port_is_power_on(hub, portstatus) ||
2199 !(portstatus & USB_PORT_STAT_CONNECTION)) {
2178 if (status >= 0) 2200 if (status >= 0)
2179 status = -ENODEV; 2201 status = -ENODEV;
2180 } 2202 }
@@ -2439,7 +2461,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
2439 2461
2440 /* Skip the initial Clear-Suspend step for a remote wakeup */ 2462 /* Skip the initial Clear-Suspend step for a remote wakeup */
2441 status = hub_port_status(hub, port1, &portstatus, &portchange); 2463 status = hub_port_status(hub, port1, &portstatus, &portchange);
2442 if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND)) 2464 if (status == 0 && !port_is_suspended(hub, portstatus))
2443 goto SuspendCleared; 2465 goto SuspendCleared;
2444 2466
2445 // dev_dbg(hub->intfdev, "resume port %d\n", port1); 2467 // 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 3169
3148 /* maybe switch power back on (e.g. root hub was reset) */ 3170 /* maybe switch power back on (e.g. root hub was reset) */
3149 if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 3171 if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
3150 && !(portstatus & USB_PORT_STAT_POWER)) 3172 && !port_is_power_on(hub, portstatus))
3151 set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); 3173 set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
3152 3174
3153 if (portstatus & USB_PORT_STAT_ENABLE) 3175 if (portstatus & USB_PORT_STAT_ENABLE)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index b87535442386..4a3ca99fc64e 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -431,9 +431,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
431 } 431 }
432 xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); 432 xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
433 433
434 /* FIXME - should we return a port status value like the USB
435 * 3.0 external hubs do?
436 */
437 /* wPortChange bits */ 434 /* wPortChange bits */
438 if (temp & PORT_CSC) 435 if (temp & PORT_CSC)
439 status |= USB_PORT_STAT_C_CONNECTION << 16; 436 status |= USB_PORT_STAT_C_CONNECTION << 16;
@@ -441,13 +438,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
441 status |= USB_PORT_STAT_C_ENABLE << 16; 438 status |= USB_PORT_STAT_C_ENABLE << 16;
442 if ((temp & PORT_OCC)) 439 if ((temp & PORT_OCC))
443 status |= USB_PORT_STAT_C_OVERCURRENT << 16; 440 status |= USB_PORT_STAT_C_OVERCURRENT << 16;
444 /* 441 if ((temp & PORT_RC))
445 * FIXME ignoring reset and USB 2.1/3.0 specific 442 status |= USB_PORT_STAT_C_RESET << 16;
446 * changes 443 /* USB3.0 only */
447 */ 444 if (hcd->speed == HCD_USB3) {
448 if ((temp & PORT_PLS_MASK) == XDEV_U3 445 if ((temp & PORT_PLC))
449 && (temp & PORT_POWER)) 446 status |= USB_PORT_STAT_C_LINK_STATE << 16;
450 status |= 1 << USB_PORT_FEAT_SUSPEND; 447 if ((temp & PORT_WRC))
448 status |= USB_PORT_STAT_C_BH_RESET << 16;
449 }
450
451 if (hcd->speed != HCD_USB3) {
452 if ((temp & PORT_PLS_MASK) == XDEV_U3
453 && (temp & PORT_POWER))
454 status |= USB_PORT_STAT_SUSPEND;
455 }
451 if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { 456 if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
452 if ((temp & PORT_RESET) || !(temp & PORT_PE)) 457 if ((temp & PORT_RESET) || !(temp & PORT_PE))
453 goto error; 458 goto error;
@@ -490,8 +495,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
490 status |= USB_PORT_STAT_OVERCURRENT; 495 status |= USB_PORT_STAT_OVERCURRENT;
491 if (temp & PORT_RESET) 496 if (temp & PORT_RESET)
492 status |= USB_PORT_STAT_RESET; 497 status |= USB_PORT_STAT_RESET;
493 if (temp & PORT_POWER) 498 if (temp & PORT_POWER) {
494 status |= USB_PORT_STAT_POWER; 499 if (hcd->speed == HCD_USB3)
500 status |= USB_SS_PORT_STAT_POWER;
501 else
502 status |= USB_PORT_STAT_POWER;
503 }
504 /* Port Link State */
505 if (hcd->speed == HCD_USB3) {
506 /* resume state is a xHCI internal state.
507 * Do not report it to usb core.
508 */
509 if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
510 status |= (temp & PORT_PLS_MASK);
511 }
495 if (bus_state->port_c_suspend & (1 << wIndex)) 512 if (bus_state->port_c_suspend & (1 << wIndex))
496 status |= 1 << USB_PORT_FEAT_C_SUSPEND; 513 status |= 1 << USB_PORT_FEAT_C_SUSPEND;
497 xhci_dbg(xhci, "Get port status returned 0x%x\n", status); 514 xhci_dbg(xhci, "Get port status returned 0x%x\n", status);