aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hub.c
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2010-10-14 10:22:57 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-22 13:22:12 -0400
commitbe88fe4f4dda93e3264a887745123b1e6c4a6845 (patch)
treee0a014c2eb0672da74dc458270fbc6e0a5af48b2 /drivers/usb/host/xhci-hub.c
parent85f0ff46960c2853fd1436a56798260eae91db86 (diff)
USB: xHCI: port power management implementation
Add software trigger USB device suspend resume function hook. Do port suspend & resume in terms of xHCI spec. Port Suspend: Stop all endpoints via Stop Endpoint Command with Suspend (SP) flag set. Place individual ports into suspend mode by writing '3' for Port Link State (PLS) field into PORTSC register. This can only be done when the port is in Enabled state. When writing, the Port Link State Write Strobe (LWS) bit shall be set to '1'. Allocate an xhci_command and stash it in xhci_virt_device to wait completion for the last Stop Endpoint Command. Use the Suspend bit in TRB to indicate the Stop Endpoint Command is for port suspend. Based on Sarah's suggestion. Port Resume: Write '0' in PLS field, device will transition to running state. Ring an endpoints' doorbell to restart it. Ref: USB device remote wake need another patch to implement. For details of how USB subsystem do power management, please see: Documentation/usb/power-management.txt Signed-off-by: Crane Cai <crane.cai@amd.com> Signed-off-by: Libin Yang <libin.yang@amd.com> Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r--drivers/usb/host/xhci-hub.c196
1 files changed, 195 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index a1a7a9795536..14b48b261e06 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -129,6 +129,99 @@ static u32 xhci_port_state_to_neutral(u32 state)
129 return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS); 129 return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
130} 130}
131 131
132/*
133 * find slot id based on port number.
134 */
135static int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port)
136{
137 int slot_id;
138 int i;
139
140 slot_id = 0;
141 for (i = 0; i < MAX_HC_SLOTS; i++) {
142 if (!xhci->devs[i])
143 continue;
144 if (xhci->devs[i]->port == port) {
145 slot_id = i;
146 break;
147 }
148 }
149
150 return slot_id;
151}
152
153/*
154 * Stop device
155 * It issues stop endpoint command for EP 0 to 30. And wait the last command
156 * to complete.
157 * suspend will set to 1, if suspend bit need to set in command.
158 */
159static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
160{
161 struct xhci_virt_device *virt_dev;
162 struct xhci_command *cmd;
163 unsigned long flags;
164 int timeleft;
165 int ret;
166 int i;
167
168 ret = 0;
169 virt_dev = xhci->devs[slot_id];
170 cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
171 if (!cmd) {
172 xhci_dbg(xhci, "Couldn't allocate command structure.\n");
173 return -ENOMEM;
174 }
175
176 spin_lock_irqsave(&xhci->lock, flags);
177 for (i = LAST_EP_INDEX; i > 0; i--) {
178 if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
179 xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
180 }
181 cmd->command_trb = xhci->cmd_ring->enqueue;
182 list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
183 xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
184 xhci_ring_cmd_db(xhci);
185 spin_unlock_irqrestore(&xhci->lock, flags);
186
187 /* Wait for last stop endpoint command to finish */
188 timeleft = wait_for_completion_interruptible_timeout(
189 cmd->completion,
190 USB_CTRL_SET_TIMEOUT);
191 if (timeleft <= 0) {
192 xhci_warn(xhci, "%s while waiting for stop endpoint command\n",
193 timeleft == 0 ? "Timeout" : "Signal");
194 spin_lock_irqsave(&xhci->lock, flags);
195 /* The timeout might have raced with the event ring handler, so
196 * only delete from the list if the item isn't poisoned.
197 */
198 if (cmd->cmd_list.next != LIST_POISON1)
199 list_del(&cmd->cmd_list);
200 spin_unlock_irqrestore(&xhci->lock, flags);
201 ret = -ETIME;
202 goto command_cleanup;
203 }
204
205command_cleanup:
206 xhci_free_command(xhci, cmd);
207 return ret;
208}
209
210/*
211 * Ring device, it rings the all doorbells unconditionally.
212 */
213static void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
214{
215 int i;
216
217 for (i = 0; i < LAST_EP_INDEX + 1; i++)
218 if (xhci->devs[slot_id]->eps[i].ring &&
219 xhci->devs[slot_id]->eps[i].ring->dequeue)
220 xhci_ring_ep_doorbell(xhci, slot_id, i, 0);
221
222 return;
223}
224
132static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, 225static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
133 u32 __iomem *addr, u32 port_status) 226 u32 __iomem *addr, u32 port_status)
134{ 227{
@@ -162,6 +255,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
162 status = PORT_PEC; 255 status = PORT_PEC;
163 port_change_bit = "enable/disable"; 256 port_change_bit = "enable/disable";
164 break; 257 break;
258 case USB_PORT_FEAT_C_SUSPEND:
259 status = PORT_PLC;
260 port_change_bit = "suspend/resume";
261 break;
165 default: 262 default:
166 /* Should never happen */ 263 /* Should never happen */
167 return; 264 return;
@@ -182,6 +279,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
182 u32 temp, status; 279 u32 temp, status;
183 int retval = 0; 280 int retval = 0;
184 u32 __iomem *addr; 281 u32 __iomem *addr;
282 int slot_id;
185 283
186 ports = HCS_MAX_PORTS(xhci->hcs_params1); 284 ports = HCS_MAX_PORTS(xhci->hcs_params1);
187 285
@@ -211,9 +309,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
211 if ((temp & PORT_OCC)) 309 if ((temp & PORT_OCC))
212 status |= USB_PORT_STAT_C_OVERCURRENT << 16; 310 status |= USB_PORT_STAT_C_OVERCURRENT << 16;
213 /* 311 /*
214 * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific 312 * FIXME ignoring reset and USB 2.1/3.0 specific
215 * changes 313 * changes
216 */ 314 */
315 if ((temp & PORT_PLS_MASK) == XDEV_U3
316 && (temp & PORT_POWER))
317 status |= 1 << USB_PORT_FEAT_SUSPEND;
318 if ((temp & PORT_PLS_MASK) == XDEV_U0
319 && (temp & PORT_POWER)
320 && (xhci->suspended_ports[wIndex >> 5] &
321 (1 << (wIndex & 31)))) {
322 xhci->suspended_ports[wIndex >> 5] &=
323 ~(1 << (wIndex & 31));
324 xhci->port_c_suspend[wIndex >> 5] |=
325 1 << (wIndex & 31);
326 }
217 if (temp & PORT_CONNECT) { 327 if (temp & PORT_CONNECT) {
218 status |= USB_PORT_STAT_CONNECTION; 328 status |= USB_PORT_STAT_CONNECTION;
219 status |= xhci_port_speed(temp); 329 status |= xhci_port_speed(temp);
@@ -226,6 +336,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
226 status |= USB_PORT_STAT_RESET; 336 status |= USB_PORT_STAT_RESET;
227 if (temp & PORT_POWER) 337 if (temp & PORT_POWER)
228 status |= USB_PORT_STAT_POWER; 338 status |= USB_PORT_STAT_POWER;
339 if (xhci->port_c_suspend[wIndex >> 5] & (1 << (wIndex & 31)))
340 status |= 1 << USB_PORT_FEAT_C_SUSPEND;
229 xhci_dbg(xhci, "Get port status returned 0x%x\n", status); 341 xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
230 put_unaligned(cpu_to_le32(status), (__le32 *) buf); 342 put_unaligned(cpu_to_le32(status), (__le32 *) buf);
231 break; 343 break;
@@ -238,6 +350,42 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
238 temp = xhci_readl(xhci, addr); 350 temp = xhci_readl(xhci, addr);
239 temp = xhci_port_state_to_neutral(temp); 351 temp = xhci_port_state_to_neutral(temp);
240 switch (wValue) { 352 switch (wValue) {
353 case USB_PORT_FEAT_SUSPEND:
354 temp = xhci_readl(xhci, addr);
355 /* In spec software should not attempt to suspend
356 * a port unless the port reports that it is in the
357 * enabled (PED = ‘1’,PLS < ‘3’) state.
358 */
359 if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
360 || (temp & PORT_PLS_MASK) >= XDEV_U3) {
361 xhci_warn(xhci, "USB core suspending device "
362 "not in U0/U1/U2.\n");
363 goto error;
364 }
365
366 slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
367 if (!slot_id) {
368 xhci_warn(xhci, "slot_id is zero\n");
369 goto error;
370 }
371 /* unlock to execute stop endpoint commands */
372 spin_unlock_irqrestore(&xhci->lock, flags);
373 xhci_stop_device(xhci, slot_id, 1);
374 spin_lock_irqsave(&xhci->lock, flags);
375
376 temp = xhci_port_state_to_neutral(temp);
377 temp &= ~PORT_PLS_MASK;
378 temp |= PORT_LINK_STROBE | XDEV_U3;
379 xhci_writel(xhci, temp, addr);
380
381 spin_unlock_irqrestore(&xhci->lock, flags);
382 msleep(10); /* wait device to enter */
383 spin_lock_irqsave(&xhci->lock, flags);
384
385 temp = xhci_readl(xhci, addr);
386 xhci->suspended_ports[wIndex >> 5] |=
387 1 << (wIndex & (31));
388 break;
241 case USB_PORT_FEAT_POWER: 389 case USB_PORT_FEAT_POWER:
242 /* 390 /*
243 * Turn on ports, even if there isn't per-port switching. 391 * Turn on ports, even if there isn't per-port switching.
@@ -271,6 +419,52 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
271 temp = xhci_readl(xhci, addr); 419 temp = xhci_readl(xhci, addr);
272 temp = xhci_port_state_to_neutral(temp); 420 temp = xhci_port_state_to_neutral(temp);
273 switch (wValue) { 421 switch (wValue) {
422 case USB_PORT_FEAT_SUSPEND:
423 temp = xhci_readl(xhci, addr);
424 xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
425 xhci_dbg(xhci, "PORTSC %04x\n", temp);
426 if (temp & PORT_RESET)
427 goto error;
428 if (temp & XDEV_U3) {
429 if ((temp & PORT_PE) == 0)
430 goto error;
431 if (DEV_SUPERSPEED(temp)) {
432 temp = xhci_port_state_to_neutral(temp);
433 temp &= ~PORT_PLS_MASK;
434 temp |= PORT_LINK_STROBE | XDEV_U0;
435 xhci_writel(xhci, temp, addr);
436 xhci_readl(xhci, addr);
437 } else {
438 temp = xhci_port_state_to_neutral(temp);
439 temp &= ~PORT_PLS_MASK;
440 temp |= PORT_LINK_STROBE | XDEV_RESUME;
441 xhci_writel(xhci, temp, addr);
442
443 spin_unlock_irqrestore(&xhci->lock,
444 flags);
445 msleep(20);
446 spin_lock_irqsave(&xhci->lock, flags);
447
448 temp = xhci_readl(xhci, addr);
449 temp = xhci_port_state_to_neutral(temp);
450 temp &= ~PORT_PLS_MASK;
451 temp |= PORT_LINK_STROBE | XDEV_U0;
452 xhci_writel(xhci, temp, addr);
453 }
454 xhci->port_c_suspend[wIndex >> 5] |=
455 1 << (wIndex & 31);
456 }
457
458 slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
459 if (!slot_id) {
460 xhci_dbg(xhci, "slot_id is zero\n");
461 goto error;
462 }
463 xhci_ring_device(xhci, slot_id);
464 break;
465 case USB_PORT_FEAT_C_SUSPEND:
466 xhci->port_c_suspend[wIndex >> 5] &=
467 ~(1 << (wIndex & 31));
274 case USB_PORT_FEAT_C_RESET: 468 case USB_PORT_FEAT_C_RESET:
275 case USB_PORT_FEAT_C_CONNECTION: 469 case USB_PORT_FEAT_C_CONNECTION:
276 case USB_PORT_FEAT_C_OVER_CURRENT: 470 case USB_PORT_FEAT_C_OVER_CURRENT: