aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-11-11 17:57:33 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-02-14 15:12:22 -0500
commit623bef9e03a60adc623b09673297ca7a1cdfb367 (patch)
treee6a7a90af43d6f091874a036275bf01b155e36b6 /drivers/usb/host
parentd93814cfadb131fb219359d4b7008c728421c552 (diff)
USB/xhci: Enable remote wakeup for USB3 devices.
When the USB 3.0 hub support went in, I disabled selective suspend for all external USB 3.0 hubs because they used a different mechanism to enable remote wakeup. In fact, other USB 3.0 devices that could signal remote wakeup would have been prevented from going into suspend because they would have stalled the SetFeature Device Remote Wakeup request. This patch adds support for the USB 3.0 way of enabling remote wake up (with a SetFeature Function Suspend request), and enables selective suspend for all hubs during hub_probe. It assumes that all USB 3.0 have only one "function" as defined by the interface association descriptor, which is true of all the USB 3.0 devices I've seen so far. FIXME if that turns out to change later. After a device signals a remote wakeup, it is supposed to send a Device Notification packet to the host controller, signaling which function sent the remote wakeup. The host can then put any other functions back into function suspend. Since we don't have support for function suspend (and no devices currently support it), we'll just assume the hub function will resume the device properly when it received the port status change notification, and simply ignore any device notification events from the xHCI host controller. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/xhci-mem.c11
-rw-r--r--drivers/usb/host/xhci-ring.c21
2 files changed, 31 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 36cbe2226a44..6b70e7fb484c 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -2141,7 +2141,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
2141 unsigned int val, val2; 2141 unsigned int val, val2;
2142 u64 val_64; 2142 u64 val_64;
2143 struct xhci_segment *seg; 2143 struct xhci_segment *seg;
2144 u32 page_size; 2144 u32 page_size, temp;
2145 int i; 2145 int i;
2146 2146
2147 page_size = xhci_readl(xhci, &xhci->op_regs->page_size); 2147 page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
@@ -2324,6 +2324,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
2324 2324
2325 INIT_LIST_HEAD(&xhci->lpm_failed_devs); 2325 INIT_LIST_HEAD(&xhci->lpm_failed_devs);
2326 2326
2327 /* Enable USB 3.0 device notifications for function remote wake, which
2328 * is necessary for allowing USB 3.0 devices to do remote wakeup from
2329 * U3 (device suspend).
2330 */
2331 temp = xhci_readl(xhci, &xhci->op_regs->dev_notification);
2332 temp &= ~DEV_NOTE_MASK;
2333 temp |= DEV_NOTE_FWAKE;
2334 xhci_writel(xhci, temp, &xhci->op_regs->dev_notification);
2335
2327 return 0; 2336 return 0;
2328 2337
2329fail: 2338fail:
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index ca38483c9f56..ffe549338cec 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1237,6 +1237,24 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
1237 return num_similar_speed_ports; 1237 return num_similar_speed_ports;
1238} 1238}
1239 1239
1240static void handle_device_notification(struct xhci_hcd *xhci,
1241 union xhci_trb *event)
1242{
1243 u32 slot_id;
1244
1245 slot_id = TRB_TO_SLOT_ID(event->generic.field[3]);
1246 if (!xhci->devs[slot_id])
1247 xhci_warn(xhci, "Device Notification event for "
1248 "unused slot %u\n", slot_id);
1249 else
1250 xhci_dbg(xhci, "Device Notification event for slot ID %u\n",
1251 slot_id);
1252 /* XXX should we kick khubd for the parent hub? It should have send an
1253 * interrupt transfer when the port started signaling resume, so there's
1254 * probably no need to do so.
1255 */
1256}
1257
1240static void handle_port_status(struct xhci_hcd *xhci, 1258static void handle_port_status(struct xhci_hcd *xhci,
1241 union xhci_trb *event) 1259 union xhci_trb *event)
1242{ 1260{
@@ -2282,6 +2300,9 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
2282 else 2300 else
2283 update_ptrs = 0; 2301 update_ptrs = 0;
2284 break; 2302 break;
2303 case TRB_TYPE(TRB_DEV_NOTE):
2304 handle_device_notification(xhci, event);
2305 break;
2285 default: 2306 default:
2286 if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >= 2307 if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
2287 TRB_TYPE(48)) 2308 TRB_TYPE(48))