diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-23 11:20:44 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-23 11:21:03 -0500 |
commit | c69263c66e5b2a5d0c7e5a41c189b1846ae1de92 (patch) | |
tree | 81c6cf0f5b3b05739e2e73b0118077d9dd245182 /drivers/usb/host | |
parent | 45196cee28a5bcfb6ddbe2bffa4270cbed66ae4b (diff) | |
parent | 5407a3c3d942e75d4d123d213fd692bce5acc961 (diff) |
Merge branch 'usb-3.3-rc4' into usb-next
This is to pull in the xhci changes and the other fixes and device id
updates that were done in Linus's tree.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 14 | ||||
-rw-r--r-- | drivers/usb/host/ehci-fsl.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/ehci-ls1x.c | 159 | ||||
-rw-r--r-- | drivers/usb/host/imx21-dbg.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 41 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 74 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 1 |
11 files changed, 303 insertions, 17 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index c26a82e83f6e..10e008a730a5 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c | |||
@@ -323,7 +323,9 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) | |||
323 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 323 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
324 | int retval; | 324 | int retval; |
325 | struct fsl_usb2_platform_data *pdata; | 325 | struct fsl_usb2_platform_data *pdata; |
326 | struct device *dev; | ||
326 | 327 | ||
328 | dev = hcd->self.controller; | ||
327 | pdata = hcd->self.controller->platform_data; | 329 | pdata = hcd->self.controller->platform_data; |
328 | ehci->big_endian_desc = pdata->big_endian_desc; | 330 | ehci->big_endian_desc = pdata->big_endian_desc; |
329 | ehci->big_endian_mmio = pdata->big_endian_mmio; | 331 | ehci->big_endian_mmio = pdata->big_endian_mmio; |
@@ -353,6 +355,16 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) | |||
353 | 355 | ||
354 | ehci_reset(ehci); | 356 | ehci_reset(ehci); |
355 | 357 | ||
358 | if (of_device_is_compatible(dev->parent->of_node, | ||
359 | "fsl,mpc5121-usb2-dr")) { | ||
360 | /* | ||
361 | * set SBUSCFG:AHBBRST so that control msgs don't | ||
362 | * fail when doing heavy PATA writes. | ||
363 | */ | ||
364 | ehci_writel(ehci, SBUSCFG_INCR8, | ||
365 | hcd->regs + FSL_SOC_USB_SBUSCFG); | ||
366 | } | ||
367 | |||
356 | retval = ehci_fsl_reinit(ehci); | 368 | retval = ehci_fsl_reinit(ehci); |
357 | return retval; | 369 | return retval; |
358 | } | 370 | } |
@@ -476,6 +488,8 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev) | |||
476 | ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE, | 488 | ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE, |
477 | hcd->regs + FSL_SOC_USB_ISIPHYCTRL); | 489 | hcd->regs + FSL_SOC_USB_ISIPHYCTRL); |
478 | 490 | ||
491 | ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG); | ||
492 | |||
479 | /* restore EHCI registers */ | 493 | /* restore EHCI registers */ |
480 | ehci_writel(ehci, pdata->pm_command, &ehci->regs->command); | 494 | ehci_writel(ehci, pdata->pm_command, &ehci->regs->command); |
481 | ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable); | 495 | ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable); |
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index bdf43e2adc51..6d5a94e9bb3c 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h | |||
@@ -19,6 +19,8 @@ | |||
19 | #define _EHCI_FSL_H | 19 | #define _EHCI_FSL_H |
20 | 20 | ||
21 | /* offsets for the non-ehci registers in the FSL SOC USB controller */ | 21 | /* offsets for the non-ehci registers in the FSL SOC USB controller */ |
22 | #define FSL_SOC_USB_SBUSCFG 0x90 | ||
23 | #define SBUSCFG_INCR8 0x02 /* INCR8, specified */ | ||
22 | #define FSL_SOC_USB_ULPIVP 0x170 | 24 | #define FSL_SOC_USB_ULPIVP 0x170 |
23 | #define FSL_SOC_USB_PORTSC1 0x184 | 25 | #define FSL_SOC_USB_PORTSC1 0x184 |
24 | #define PORT_PTS_MSK (3<<30) | 26 | #define PORT_PTS_MSK (3<<30) |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a007a9fe0f87..4918b0c59af9 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -1376,6 +1376,11 @@ MODULE_LICENSE ("GPL"); | |||
1376 | #define PLATFORM_DRIVER ehci_mv_driver | 1376 | #define PLATFORM_DRIVER ehci_mv_driver |
1377 | #endif | 1377 | #endif |
1378 | 1378 | ||
1379 | #ifdef CONFIG_MACH_LOONGSON1 | ||
1380 | #include "ehci-ls1x.c" | ||
1381 | #define PLATFORM_DRIVER ehci_ls1x_driver | ||
1382 | #endif | ||
1383 | |||
1379 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ | 1384 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ |
1380 | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ | 1385 | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ |
1381 | !defined(XILINX_OF_PLATFORM_DRIVER) | 1386 | !defined(XILINX_OF_PLATFORM_DRIVER) |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 77bbb2357e47..01011dd0cb5d 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
107 | ehci->owned_ports = 0; | 107 | ehci->owned_ports = 0; |
108 | } | 108 | } |
109 | 109 | ||
110 | static int ehci_port_change(struct ehci_hcd *ehci) | 110 | static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci) |
111 | { | 111 | { |
112 | int i = HCS_N_PORTS(ehci->hcs_params); | 112 | int i = HCS_N_PORTS(ehci->hcs_params); |
113 | 113 | ||
@@ -1076,7 +1076,8 @@ error_exit: | |||
1076 | return retval; | 1076 | return retval; |
1077 | } | 1077 | } |
1078 | 1078 | ||
1079 | static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) | 1079 | static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd, |
1080 | int portnum) | ||
1080 | { | 1081 | { |
1081 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 1082 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
1082 | 1083 | ||
@@ -1085,7 +1086,8 @@ static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) | |||
1085 | set_owner(ehci, --portnum, PORT_OWNER); | 1086 | set_owner(ehci, --portnum, PORT_OWNER); |
1086 | } | 1087 | } |
1087 | 1088 | ||
1088 | static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum) | 1089 | static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd, |
1090 | int portnum) | ||
1089 | { | 1091 | { |
1090 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 1092 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
1091 | u32 __iomem *reg; | 1093 | u32 __iomem *reg; |
diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c new file mode 100644 index 000000000000..a283e59709d6 --- /dev/null +++ b/drivers/usb/host/ehci-ls1x.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Bus Glue for Loongson LS1X built-in EHCI controller. | ||
3 | * | ||
4 | * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published | ||
8 | * by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | |||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | static int ehci_ls1x_reset(struct usb_hcd *hcd) | ||
15 | { | ||
16 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
17 | int ret; | ||
18 | |||
19 | ehci->caps = hcd->regs; | ||
20 | |||
21 | ret = ehci_setup(hcd); | ||
22 | if (ret) | ||
23 | return ret; | ||
24 | |||
25 | ehci_port_power(ehci, 0); | ||
26 | |||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | static const struct hc_driver ehci_ls1x_hc_driver = { | ||
31 | .description = hcd_name, | ||
32 | .product_desc = "LOONGSON1 EHCI", | ||
33 | .hcd_priv_size = sizeof(struct ehci_hcd), | ||
34 | |||
35 | /* | ||
36 | * generic hardware linkage | ||
37 | */ | ||
38 | .irq = ehci_irq, | ||
39 | .flags = HCD_MEMORY | HCD_USB2, | ||
40 | |||
41 | /* | ||
42 | * basic lifecycle operations | ||
43 | */ | ||
44 | .reset = ehci_ls1x_reset, | ||
45 | .start = ehci_run, | ||
46 | .stop = ehci_stop, | ||
47 | .shutdown = ehci_shutdown, | ||
48 | |||
49 | /* | ||
50 | * managing i/o requests and associated device resources | ||
51 | */ | ||
52 | .urb_enqueue = ehci_urb_enqueue, | ||
53 | .urb_dequeue = ehci_urb_dequeue, | ||
54 | .endpoint_disable = ehci_endpoint_disable, | ||
55 | .endpoint_reset = ehci_endpoint_reset, | ||
56 | |||
57 | /* | ||
58 | * scheduling support | ||
59 | */ | ||
60 | .get_frame_number = ehci_get_frame, | ||
61 | |||
62 | /* | ||
63 | * root hub support | ||
64 | */ | ||
65 | .hub_status_data = ehci_hub_status_data, | ||
66 | .hub_control = ehci_hub_control, | ||
67 | .relinquish_port = ehci_relinquish_port, | ||
68 | .port_handed_over = ehci_port_handed_over, | ||
69 | |||
70 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
71 | }; | ||
72 | |||
73 | static int ehci_hcd_ls1x_probe(struct platform_device *pdev) | ||
74 | { | ||
75 | struct usb_hcd *hcd; | ||
76 | struct resource *res; | ||
77 | int irq; | ||
78 | int ret; | ||
79 | |||
80 | pr_debug("initializing loongson1 ehci USB Controller\n"); | ||
81 | |||
82 | if (usb_disabled()) | ||
83 | return -ENODEV; | ||
84 | |||
85 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
86 | if (!res) { | ||
87 | dev_err(&pdev->dev, | ||
88 | "Found HC with no IRQ. Check %s setup!\n", | ||
89 | dev_name(&pdev->dev)); | ||
90 | return -ENODEV; | ||
91 | } | ||
92 | irq = res->start; | ||
93 | |||
94 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
95 | if (!res) { | ||
96 | dev_err(&pdev->dev, | ||
97 | "Found HC with no register addr. Check %s setup!\n", | ||
98 | dev_name(&pdev->dev)); | ||
99 | return -ENODEV; | ||
100 | } | ||
101 | |||
102 | hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev, | ||
103 | dev_name(&pdev->dev)); | ||
104 | if (!hcd) | ||
105 | return -ENOMEM; | ||
106 | hcd->rsrc_start = res->start; | ||
107 | hcd->rsrc_len = resource_size(res); | ||
108 | |||
109 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | ||
110 | dev_dbg(&pdev->dev, "controller already in use\n"); | ||
111 | ret = -EBUSY; | ||
112 | goto err_put_hcd; | ||
113 | } | ||
114 | |||
115 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
116 | if (hcd->regs == NULL) { | ||
117 | dev_dbg(&pdev->dev, "error mapping memory\n"); | ||
118 | ret = -EFAULT; | ||
119 | goto err_release_region; | ||
120 | } | ||
121 | |||
122 | ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); | ||
123 | if (ret) | ||
124 | goto err_iounmap; | ||
125 | |||
126 | return ret; | ||
127 | |||
128 | err_iounmap: | ||
129 | iounmap(hcd->regs); | ||
130 | err_release_region: | ||
131 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
132 | err_put_hcd: | ||
133 | usb_put_hcd(hcd); | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | static int ehci_hcd_ls1x_remove(struct platform_device *pdev) | ||
138 | { | ||
139 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
140 | |||
141 | usb_remove_hcd(hcd); | ||
142 | iounmap(hcd->regs); | ||
143 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
144 | usb_put_hcd(hcd); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static struct platform_driver ehci_ls1x_driver = { | ||
150 | .probe = ehci_hcd_ls1x_probe, | ||
151 | .remove = ehci_hcd_ls1x_remove, | ||
152 | .shutdown = usb_hcd_platform_shutdown, | ||
153 | .driver = { | ||
154 | .name = "ls1x-ehci", | ||
155 | .owner = THIS_MODULE, | ||
156 | }, | ||
157 | }; | ||
158 | |||
159 | MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci"); | ||
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c index 6d7533427163..ec98ecee3517 100644 --- a/drivers/usb/host/imx21-dbg.c +++ b/drivers/usb/host/imx21-dbg.c | |||
@@ -239,7 +239,7 @@ static int debug_status_show(struct seq_file *s, void *v) | |||
239 | "ETDs allocated: %d/%d (max=%d)\n" | 239 | "ETDs allocated: %d/%d (max=%d)\n" |
240 | "ETDs in use sw: %d\n" | 240 | "ETDs in use sw: %d\n" |
241 | "ETDs in use hw: %d\n" | 241 | "ETDs in use hw: %d\n" |
242 | "DMEM alocated: %d/%d (max=%d)\n" | 242 | "DMEM allocated: %d/%d (max=%d)\n" |
243 | "DMEM blocks: %d\n" | 243 | "DMEM blocks: %d\n" |
244 | "Queued waiting for ETD: %d\n" | 244 | "Queued waiting for ETD: %d\n" |
245 | "Queued waiting for DMEM: %d\n", | 245 | "Queued waiting for DMEM: %d\n", |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 6b5eb1017e2c..e37dea87bb56 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -565,6 +565,9 @@ static int uhci_start(struct usb_hcd *hcd) | |||
565 | struct dentry __maybe_unused *dentry; | 565 | struct dentry __maybe_unused *dentry; |
566 | 566 | ||
567 | hcd->uses_new_polling = 1; | 567 | hcd->uses_new_polling = 1; |
568 | /* Accept arbitrarily long scatter-gather lists */ | ||
569 | if (!(hcd->driver->flags & HCD_LOCAL_MEM)) | ||
570 | hcd->self.sg_tablesize = ~0; | ||
568 | 571 | ||
569 | spin_lock_init(&uhci->lock); | 572 | spin_lock_init(&uhci->lock); |
570 | setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout, | 573 | setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout, |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 557b6f32db86..673ad120c43e 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -422,6 +422,32 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, | |||
422 | xhci_writel(xhci, temp, port_array[port_id]); | 422 | xhci_writel(xhci, temp, port_array[port_id]); |
423 | } | 423 | } |
424 | 424 | ||
425 | void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, | ||
426 | __le32 __iomem **port_array, int port_id, u16 wake_mask) | ||
427 | { | ||
428 | u32 temp; | ||
429 | |||
430 | temp = xhci_readl(xhci, port_array[port_id]); | ||
431 | temp = xhci_port_state_to_neutral(temp); | ||
432 | |||
433 | if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT) | ||
434 | temp |= PORT_WKCONN_E; | ||
435 | else | ||
436 | temp &= ~PORT_WKCONN_E; | ||
437 | |||
438 | if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT) | ||
439 | temp |= PORT_WKDISC_E; | ||
440 | else | ||
441 | temp &= ~PORT_WKDISC_E; | ||
442 | |||
443 | if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT) | ||
444 | temp |= PORT_WKOC_E; | ||
445 | else | ||
446 | temp &= ~PORT_WKOC_E; | ||
447 | |||
448 | xhci_writel(xhci, temp, port_array[port_id]); | ||
449 | } | ||
450 | |||
425 | /* Test and clear port RWC bit */ | 451 | /* Test and clear port RWC bit */ |
426 | void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, | 452 | void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, |
427 | int port_id, u32 port_bit) | 453 | int port_id, u32 port_bit) |
@@ -448,6 +474,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
448 | int slot_id; | 474 | int slot_id; |
449 | struct xhci_bus_state *bus_state; | 475 | struct xhci_bus_state *bus_state; |
450 | u16 link_state = 0; | 476 | u16 link_state = 0; |
477 | u16 wake_mask = 0; | ||
451 | 478 | ||
452 | max_ports = xhci_get_ports(hcd, &port_array); | 479 | max_ports = xhci_get_ports(hcd, &port_array); |
453 | bus_state = &xhci->bus_state[hcd_index(hcd)]; | 480 | bus_state = &xhci->bus_state[hcd_index(hcd)]; |
@@ -593,6 +620,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
593 | case SetPortFeature: | 620 | case SetPortFeature: |
594 | if (wValue == USB_PORT_FEAT_LINK_STATE) | 621 | if (wValue == USB_PORT_FEAT_LINK_STATE) |
595 | link_state = (wIndex & 0xff00) >> 3; | 622 | link_state = (wIndex & 0xff00) >> 3; |
623 | if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) | ||
624 | wake_mask = wIndex & 0xff00; | ||
596 | wIndex &= 0xff; | 625 | wIndex &= 0xff; |
597 | if (!wIndex || wIndex > max_ports) | 626 | if (!wIndex || wIndex > max_ports) |
598 | goto error; | 627 | goto error; |
@@ -703,6 +732,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
703 | temp = xhci_readl(xhci, port_array[wIndex]); | 732 | temp = xhci_readl(xhci, port_array[wIndex]); |
704 | xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); | 733 | xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); |
705 | break; | 734 | break; |
735 | case USB_PORT_FEAT_REMOTE_WAKE_MASK: | ||
736 | xhci_set_remote_wake_mask(xhci, port_array, | ||
737 | wIndex, wake_mask); | ||
738 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
739 | xhci_dbg(xhci, "set port remote wake mask, " | ||
740 | "actual port %d status = 0x%x\n", | ||
741 | wIndex, temp); | ||
742 | break; | ||
706 | case USB_PORT_FEAT_BH_PORT_RESET: | 743 | case USB_PORT_FEAT_BH_PORT_RESET: |
707 | temp |= PORT_WR; | 744 | temp |= PORT_WR; |
708 | xhci_writel(xhci, temp, port_array[wIndex]); | 745 | xhci_writel(xhci, temp, port_array[wIndex]); |
@@ -883,6 +920,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd) | |||
883 | t2 |= PORT_LINK_STROBE | XDEV_U3; | 920 | t2 |= PORT_LINK_STROBE | XDEV_U3; |
884 | set_bit(port_index, &bus_state->bus_suspended); | 921 | set_bit(port_index, &bus_state->bus_suspended); |
885 | } | 922 | } |
923 | /* USB core sets remote wake mask for USB 3.0 hubs, | ||
924 | * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND | ||
925 | * is enabled, so also enable remote wake here. | ||
926 | */ | ||
886 | if (hcd->self.root_hub->do_remote_wakeup) { | 927 | if (hcd->self.root_hub->do_remote_wakeup) { |
887 | if (t1 & PORT_CONNECT) { | 928 | if (t1 & PORT_CONNECT) { |
888 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; | 929 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; |
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 383fc857491c..8339d826ce58 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -2157,7 +2157,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | |||
2157 | unsigned int val, val2; | 2157 | unsigned int val, val2; |
2158 | u64 val_64; | 2158 | u64 val_64; |
2159 | struct xhci_segment *seg; | 2159 | struct xhci_segment *seg; |
2160 | u32 page_size; | 2160 | u32 page_size, temp; |
2161 | int i; | 2161 | int i; |
2162 | 2162 | ||
2163 | page_size = xhci_readl(xhci, &xhci->op_regs->page_size); | 2163 | page_size = xhci_readl(xhci, &xhci->op_regs->page_size); |
@@ -2340,6 +2340,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | |||
2340 | 2340 | ||
2341 | INIT_LIST_HEAD(&xhci->lpm_failed_devs); | 2341 | INIT_LIST_HEAD(&xhci->lpm_failed_devs); |
2342 | 2342 | ||
2343 | /* Enable USB 3.0 device notifications for function remote wake, which | ||
2344 | * is necessary for allowing USB 3.0 devices to do remote wakeup from | ||
2345 | * U3 (device suspend). | ||
2346 | */ | ||
2347 | temp = xhci_readl(xhci, &xhci->op_regs->dev_notification); | ||
2348 | temp &= ~DEV_NOTE_MASK; | ||
2349 | temp |= DEV_NOTE_FWAKE; | ||
2350 | xhci_writel(xhci, temp, &xhci->op_regs->dev_notification); | ||
2351 | |||
2343 | return 0; | 2352 | return 0; |
2344 | 2353 | ||
2345 | fail: | 2354 | fail: |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b62037bff688..3a033240ec64 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1237,6 +1237,26 @@ 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 | ||
1240 | static void handle_device_notification(struct xhci_hcd *xhci, | ||
1241 | union xhci_trb *event) | ||
1242 | { | ||
1243 | u32 slot_id; | ||
1244 | struct usb_device *udev; | ||
1245 | |||
1246 | slot_id = TRB_TO_SLOT_ID(event->generic.field[3]); | ||
1247 | if (!xhci->devs[slot_id]) { | ||
1248 | xhci_warn(xhci, "Device Notification event for " | ||
1249 | "unused slot %u\n", slot_id); | ||
1250 | return; | ||
1251 | } | ||
1252 | |||
1253 | xhci_dbg(xhci, "Device Wake Notification event for slot ID %u\n", | ||
1254 | slot_id); | ||
1255 | udev = xhci->devs[slot_id]->udev; | ||
1256 | if (udev && udev->parent) | ||
1257 | usb_wakeup_notification(udev->parent, udev->portnum); | ||
1258 | } | ||
1259 | |||
1240 | static void handle_port_status(struct xhci_hcd *xhci, | 1260 | static void handle_port_status(struct xhci_hcd *xhci, |
1241 | union xhci_trb *event) | 1261 | union xhci_trb *event) |
1242 | { | 1262 | { |
@@ -1321,20 +1341,21 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1321 | } | 1341 | } |
1322 | 1342 | ||
1323 | if (DEV_SUPERSPEED(temp)) { | 1343 | if (DEV_SUPERSPEED(temp)) { |
1324 | xhci_dbg(xhci, "resume SS port %d\n", port_id); | 1344 | xhci_dbg(xhci, "remote wake SS port %d\n", port_id); |
1345 | /* Set a flag to say the port signaled remote wakeup, | ||
1346 | * so we can tell the difference between the end of | ||
1347 | * device and host initiated resume. | ||
1348 | */ | ||
1349 | bus_state->port_remote_wakeup |= 1 << faked_port_index; | ||
1350 | xhci_test_and_clear_bit(xhci, port_array, | ||
1351 | faked_port_index, PORT_PLC); | ||
1325 | xhci_set_link_state(xhci, port_array, faked_port_index, | 1352 | xhci_set_link_state(xhci, port_array, faked_port_index, |
1326 | XDEV_U0); | 1353 | XDEV_U0); |
1327 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, | 1354 | /* Need to wait until the next link state change |
1328 | faked_port_index + 1); | 1355 | * indicates the device is actually in U0. |
1329 | if (!slot_id) { | 1356 | */ |
1330 | xhci_dbg(xhci, "slot_id is zero\n"); | 1357 | bogus_port_status = true; |
1331 | goto cleanup; | 1358 | goto cleanup; |
1332 | } | ||
1333 | xhci_ring_device(xhci, slot_id); | ||
1334 | xhci_dbg(xhci, "resume SS port %d finished\n", port_id); | ||
1335 | /* Clear PORT_PLC */ | ||
1336 | xhci_test_and_clear_bit(xhci, port_array, | ||
1337 | faked_port_index, PORT_PLC); | ||
1338 | } else { | 1359 | } else { |
1339 | xhci_dbg(xhci, "resume HS port %d\n", port_id); | 1360 | xhci_dbg(xhci, "resume HS port %d\n", port_id); |
1340 | bus_state->resume_done[faked_port_index] = jiffies + | 1361 | bus_state->resume_done[faked_port_index] = jiffies + |
@@ -1345,6 +1366,32 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1345 | } | 1366 | } |
1346 | } | 1367 | } |
1347 | 1368 | ||
1369 | if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 && | ||
1370 | DEV_SUPERSPEED(temp)) { | ||
1371 | xhci_dbg(xhci, "resume SS port %d finished\n", port_id); | ||
1372 | /* We've just brought the device into U0 through either the | ||
1373 | * Resume state after a device remote wakeup, or through the | ||
1374 | * U3Exit state after a host-initiated resume. If it's a device | ||
1375 | * initiated remote wake, don't pass up the link state change, | ||
1376 | * so the roothub behavior is consistent with external | ||
1377 | * USB 3.0 hub behavior. | ||
1378 | */ | ||
1379 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, | ||
1380 | faked_port_index + 1); | ||
1381 | if (slot_id && xhci->devs[slot_id]) | ||
1382 | xhci_ring_device(xhci, slot_id); | ||
1383 | if (bus_state->port_remote_wakeup && (1 << faked_port_index)) { | ||
1384 | bus_state->port_remote_wakeup &= | ||
1385 | ~(1 << faked_port_index); | ||
1386 | xhci_test_and_clear_bit(xhci, port_array, | ||
1387 | faked_port_index, PORT_PLC); | ||
1388 | usb_wakeup_notification(hcd->self.root_hub, | ||
1389 | faked_port_index + 1); | ||
1390 | bogus_port_status = true; | ||
1391 | goto cleanup; | ||
1392 | } | ||
1393 | } | ||
1394 | |||
1348 | if (hcd->speed != HCD_USB3) | 1395 | if (hcd->speed != HCD_USB3) |
1349 | xhci_test_and_clear_bit(xhci, port_array, faked_port_index, | 1396 | xhci_test_and_clear_bit(xhci, port_array, faked_port_index, |
1350 | PORT_PLC); | 1397 | PORT_PLC); |
@@ -2277,6 +2324,9 @@ static int xhci_handle_event(struct xhci_hcd *xhci) | |||
2277 | else | 2324 | else |
2278 | update_ptrs = 0; | 2325 | update_ptrs = 0; |
2279 | break; | 2326 | break; |
2327 | case TRB_TYPE(TRB_DEV_NOTE): | ||
2328 | handle_device_notification(xhci, event); | ||
2329 | break; | ||
2280 | default: | 2330 | default: |
2281 | if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >= | 2331 | if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >= |
2282 | TRB_TYPE(48)) | 2332 | TRB_TYPE(48)) |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index fb99c8379142..0f4936956103 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1344,6 +1344,7 @@ struct xhci_bus_state { | |||
1344 | /* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */ | 1344 | /* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */ |
1345 | u32 port_c_suspend; | 1345 | u32 port_c_suspend; |
1346 | u32 suspended_ports; | 1346 | u32 suspended_ports; |
1347 | u32 port_remote_wakeup; | ||
1347 | unsigned long resume_done[USB_MAXCHILDREN]; | 1348 | unsigned long resume_done[USB_MAXCHILDREN]; |
1348 | }; | 1349 | }; |
1349 | 1350 | ||