diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/usb/host/xhci-pci.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/usb/host/xhci-pci.c')
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 213 |
1 files changed, 200 insertions, 13 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index f7efe025beda..cb16de213f64 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/slab.h> | ||
24 | 25 | ||
25 | #include "xhci.h" | 26 | #include "xhci.h" |
26 | 27 | ||
@@ -28,6 +29,9 @@ | |||
28 | #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 | 29 | #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 |
29 | #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 | 30 | #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 |
30 | 31 | ||
32 | #define PCI_VENDOR_ID_ETRON 0x1b6f | ||
33 | #define PCI_DEVICE_ID_ASROCK_P67 0x7023 | ||
34 | |||
31 | static const char hcd_name[] = "xhci_hcd"; | 35 | static const char hcd_name[] = "xhci_hcd"; |
32 | 36 | ||
33 | /* called after powerup, by probe or system-pm "wakeup" */ | 37 | /* called after powerup, by probe or system-pm "wakeup" */ |
@@ -50,13 +54,45 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) | |||
50 | /* called during probe() after chip reset completes */ | 54 | /* called during probe() after chip reset completes */ |
51 | static int xhci_pci_setup(struct usb_hcd *hcd) | 55 | static int xhci_pci_setup(struct usb_hcd *hcd) |
52 | { | 56 | { |
53 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 57 | struct xhci_hcd *xhci; |
54 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | 58 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); |
55 | int retval; | 59 | int retval; |
56 | u32 temp; | 60 | u32 temp; |
57 | 61 | ||
58 | hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; | 62 | hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; |
59 | 63 | ||
64 | if (usb_hcd_is_primary_hcd(hcd)) { | ||
65 | xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); | ||
66 | if (!xhci) | ||
67 | return -ENOMEM; | ||
68 | *((struct xhci_hcd **) hcd->hcd_priv) = xhci; | ||
69 | xhci->main_hcd = hcd; | ||
70 | /* Mark the first roothub as being USB 2.0. | ||
71 | * The xHCI driver will register the USB 3.0 roothub. | ||
72 | */ | ||
73 | hcd->speed = HCD_USB2; | ||
74 | hcd->self.root_hub->speed = USB_SPEED_HIGH; | ||
75 | /* | ||
76 | * USB 2.0 roothub under xHCI has an integrated TT, | ||
77 | * (rate matching hub) as opposed to having an OHCI/UHCI | ||
78 | * companion controller. | ||
79 | */ | ||
80 | hcd->has_tt = 1; | ||
81 | } else { | ||
82 | /* xHCI private pointer was set in xhci_pci_probe for the second | ||
83 | * registered roothub. | ||
84 | */ | ||
85 | xhci = hcd_to_xhci(hcd); | ||
86 | temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); | ||
87 | if (HCC_64BIT_ADDR(temp)) { | ||
88 | xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); | ||
89 | dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); | ||
90 | } else { | ||
91 | dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
60 | xhci->cap_regs = hcd->regs; | 96 | xhci->cap_regs = hcd->regs; |
61 | xhci->op_regs = hcd->regs + | 97 | xhci->op_regs = hcd->regs + |
62 | HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); | 98 | HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); |
@@ -73,25 +109,50 @@ static int xhci_pci_setup(struct usb_hcd *hcd) | |||
73 | 109 | ||
74 | /* Look for vendor-specific quirks */ | 110 | /* Look for vendor-specific quirks */ |
75 | if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && | 111 | if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && |
76 | pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && | 112 | pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) { |
77 | pdev->revision == 0x0) { | 113 | if (pdev->revision == 0x0) { |
78 | xhci->quirks |= XHCI_RESET_EP_QUIRK; | 114 | xhci->quirks |= XHCI_RESET_EP_QUIRK; |
79 | xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" | 115 | xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" |
80 | " endpoint cmd after reset endpoint\n"); | 116 | " endpoint cmd after reset endpoint\n"); |
117 | } | ||
118 | /* Fresco Logic confirms: all revisions of this chip do not | ||
119 | * support MSI, even though some of them claim to in their PCI | ||
120 | * capabilities. | ||
121 | */ | ||
122 | xhci->quirks |= XHCI_BROKEN_MSI; | ||
123 | xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " | ||
124 | "has broken MSI implementation\n", | ||
125 | pdev->revision); | ||
81 | } | 126 | } |
127 | |||
82 | if (pdev->vendor == PCI_VENDOR_ID_NEC) | 128 | if (pdev->vendor == PCI_VENDOR_ID_NEC) |
83 | xhci->quirks |= XHCI_NEC_HOST; | 129 | xhci->quirks |= XHCI_NEC_HOST; |
84 | 130 | ||
131 | /* AMD PLL quirk */ | ||
132 | if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) | ||
133 | xhci->quirks |= XHCI_AMD_PLL_FIX; | ||
134 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
135 | pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { | ||
136 | xhci->quirks |= XHCI_SPURIOUS_SUCCESS; | ||
137 | xhci->quirks |= XHCI_EP_LIMIT_QUIRK; | ||
138 | xhci->limit_active_eps = 64; | ||
139 | } | ||
140 | if (pdev->vendor == PCI_VENDOR_ID_ETRON && | ||
141 | pdev->device == PCI_DEVICE_ID_ASROCK_P67) { | ||
142 | xhci->quirks |= XHCI_RESET_ON_RESUME; | ||
143 | xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); | ||
144 | } | ||
145 | |||
85 | /* Make sure the HC is halted. */ | 146 | /* Make sure the HC is halted. */ |
86 | retval = xhci_halt(xhci); | 147 | retval = xhci_halt(xhci); |
87 | if (retval) | 148 | if (retval) |
88 | return retval; | 149 | goto error; |
89 | 150 | ||
90 | xhci_dbg(xhci, "Resetting HCD\n"); | 151 | xhci_dbg(xhci, "Resetting HCD\n"); |
91 | /* Reset the internal HC memory state and registers. */ | 152 | /* Reset the internal HC memory state and registers. */ |
92 | retval = xhci_reset(xhci); | 153 | retval = xhci_reset(xhci); |
93 | if (retval) | 154 | if (retval) |
94 | return retval; | 155 | goto error; |
95 | xhci_dbg(xhci, "Reset complete\n"); | 156 | xhci_dbg(xhci, "Reset complete\n"); |
96 | 157 | ||
97 | temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); | 158 | temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); |
@@ -106,33 +167,152 @@ static int xhci_pci_setup(struct usb_hcd *hcd) | |||
106 | /* Initialize HCD and host controller data structures. */ | 167 | /* Initialize HCD and host controller data structures. */ |
107 | retval = xhci_init(hcd); | 168 | retval = xhci_init(hcd); |
108 | if (retval) | 169 | if (retval) |
109 | return retval; | 170 | goto error; |
110 | xhci_dbg(xhci, "Called HCD init\n"); | 171 | xhci_dbg(xhci, "Called HCD init\n"); |
111 | 172 | ||
112 | pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); | 173 | pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); |
113 | xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); | 174 | xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); |
114 | 175 | ||
115 | /* Find any debug ports */ | 176 | /* Find any debug ports */ |
116 | return xhci_pci_reinit(xhci, pdev); | 177 | retval = xhci_pci_reinit(xhci, pdev); |
178 | if (!retval) | ||
179 | return retval; | ||
180 | |||
181 | error: | ||
182 | kfree(xhci); | ||
183 | return retval; | ||
117 | } | 184 | } |
118 | 185 | ||
186 | /* | ||
187 | * We need to register our own PCI probe function (instead of the USB core's | ||
188 | * function) in order to create a second roothub under xHCI. | ||
189 | */ | ||
190 | static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
191 | { | ||
192 | int retval; | ||
193 | struct xhci_hcd *xhci; | ||
194 | struct hc_driver *driver; | ||
195 | struct usb_hcd *hcd; | ||
196 | |||
197 | driver = (struct hc_driver *)id->driver_data; | ||
198 | /* Register the USB 2.0 roothub. | ||
199 | * FIXME: USB core must know to register the USB 2.0 roothub first. | ||
200 | * This is sort of silly, because we could just set the HCD driver flags | ||
201 | * to say USB 2.0, but I'm not sure what the implications would be in | ||
202 | * the other parts of the HCD code. | ||
203 | */ | ||
204 | retval = usb_hcd_pci_probe(dev, id); | ||
205 | |||
206 | if (retval) | ||
207 | return retval; | ||
208 | |||
209 | /* USB 2.0 roothub is stored in the PCI device now. */ | ||
210 | hcd = dev_get_drvdata(&dev->dev); | ||
211 | xhci = hcd_to_xhci(hcd); | ||
212 | xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, | ||
213 | pci_name(dev), hcd); | ||
214 | if (!xhci->shared_hcd) { | ||
215 | retval = -ENOMEM; | ||
216 | goto dealloc_usb2_hcd; | ||
217 | } | ||
218 | |||
219 | /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset) | ||
220 | * is called by usb_add_hcd(). | ||
221 | */ | ||
222 | *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; | ||
223 | |||
224 | retval = usb_add_hcd(xhci->shared_hcd, dev->irq, | ||
225 | IRQF_DISABLED | IRQF_SHARED); | ||
226 | if (retval) | ||
227 | goto put_usb3_hcd; | ||
228 | /* Roothub already marked as USB 3.0 speed */ | ||
229 | return 0; | ||
230 | |||
231 | put_usb3_hcd: | ||
232 | usb_put_hcd(xhci->shared_hcd); | ||
233 | dealloc_usb2_hcd: | ||
234 | usb_hcd_pci_remove(dev); | ||
235 | return retval; | ||
236 | } | ||
237 | |||
238 | static void xhci_pci_remove(struct pci_dev *dev) | ||
239 | { | ||
240 | struct xhci_hcd *xhci; | ||
241 | |||
242 | xhci = hcd_to_xhci(pci_get_drvdata(dev)); | ||
243 | if (xhci->shared_hcd) { | ||
244 | usb_remove_hcd(xhci->shared_hcd); | ||
245 | usb_put_hcd(xhci->shared_hcd); | ||
246 | } | ||
247 | usb_hcd_pci_remove(dev); | ||
248 | kfree(xhci); | ||
249 | } | ||
250 | |||
251 | #ifdef CONFIG_PM | ||
252 | static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | ||
253 | { | ||
254 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
255 | int retval = 0; | ||
256 | |||
257 | if (hcd->state != HC_STATE_SUSPENDED || | ||
258 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) | ||
259 | return -EINVAL; | ||
260 | |||
261 | retval = xhci_suspend(xhci); | ||
262 | |||
263 | return retval; | ||
264 | } | ||
265 | |||
266 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | ||
267 | { | ||
268 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
269 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | ||
270 | int retval = 0; | ||
271 | |||
272 | /* The BIOS on systems with the Intel Panther Point chipset may or may | ||
273 | * not support xHCI natively. That means that during system resume, it | ||
274 | * may switch the ports back to EHCI so that users can use their | ||
275 | * keyboard to select a kernel from GRUB after resume from hibernate. | ||
276 | * | ||
277 | * The BIOS is supposed to remember whether the OS had xHCI ports | ||
278 | * enabled before resume, and switch the ports back to xHCI when the | ||
279 | * BIOS/OS semaphore is written, but we all know we can't trust BIOS | ||
280 | * writers. | ||
281 | * | ||
282 | * Unconditionally switch the ports back to xHCI after a system resume. | ||
283 | * We can't tell whether the EHCI or xHCI controller will be resumed | ||
284 | * first, so we have to do the port switchover in both drivers. Writing | ||
285 | * a '1' to the port switchover registers should have no effect if the | ||
286 | * port was already switched over. | ||
287 | */ | ||
288 | if (usb_is_intel_switchable_xhci(pdev)) | ||
289 | usb_enable_xhci_ports(pdev); | ||
290 | |||
291 | retval = xhci_resume(xhci, hibernated); | ||
292 | return retval; | ||
293 | } | ||
294 | #endif /* CONFIG_PM */ | ||
295 | |||
119 | static const struct hc_driver xhci_pci_hc_driver = { | 296 | static const struct hc_driver xhci_pci_hc_driver = { |
120 | .description = hcd_name, | 297 | .description = hcd_name, |
121 | .product_desc = "xHCI Host Controller", | 298 | .product_desc = "xHCI Host Controller", |
122 | .hcd_priv_size = sizeof(struct xhci_hcd), | 299 | .hcd_priv_size = sizeof(struct xhci_hcd *), |
123 | 300 | ||
124 | /* | 301 | /* |
125 | * generic hardware linkage | 302 | * generic hardware linkage |
126 | */ | 303 | */ |
127 | .irq = xhci_irq, | 304 | .irq = xhci_irq, |
128 | .flags = HCD_MEMORY | HCD_USB3, | 305 | .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, |
129 | 306 | ||
130 | /* | 307 | /* |
131 | * basic lifecycle operations | 308 | * basic lifecycle operations |
132 | */ | 309 | */ |
133 | .reset = xhci_pci_setup, | 310 | .reset = xhci_pci_setup, |
134 | .start = xhci_run, | 311 | .start = xhci_run, |
135 | /* suspend and resume implemented later */ | 312 | #ifdef CONFIG_PM |
313 | .pci_suspend = xhci_pci_suspend, | ||
314 | .pci_resume = xhci_pci_resume, | ||
315 | #endif | ||
136 | .stop = xhci_stop, | 316 | .stop = xhci_stop, |
137 | .shutdown = xhci_shutdown, | 317 | .shutdown = xhci_shutdown, |
138 | 318 | ||
@@ -152,7 +332,7 @@ static const struct hc_driver xhci_pci_hc_driver = { | |||
152 | .reset_bandwidth = xhci_reset_bandwidth, | 332 | .reset_bandwidth = xhci_reset_bandwidth, |
153 | .address_device = xhci_address_device, | 333 | .address_device = xhci_address_device, |
154 | .update_hub_device = xhci_update_hub_device, | 334 | .update_hub_device = xhci_update_hub_device, |
155 | .reset_device = xhci_reset_device, | 335 | .reset_device = xhci_discover_or_reset_device, |
156 | 336 | ||
157 | /* | 337 | /* |
158 | * scheduling support | 338 | * scheduling support |
@@ -162,6 +342,8 @@ static const struct hc_driver xhci_pci_hc_driver = { | |||
162 | /* Root hub support */ | 342 | /* Root hub support */ |
163 | .hub_control = xhci_hub_control, | 343 | .hub_control = xhci_hub_control, |
164 | .hub_status_data = xhci_hub_status_data, | 344 | .hub_status_data = xhci_hub_status_data, |
345 | .bus_suspend = xhci_bus_suspend, | ||
346 | .bus_resume = xhci_bus_resume, | ||
165 | }; | 347 | }; |
166 | 348 | ||
167 | /*-------------------------------------------------------------------------*/ | 349 | /*-------------------------------------------------------------------------*/ |
@@ -181,11 +363,16 @@ static struct pci_driver xhci_pci_driver = { | |||
181 | .name = (char *) hcd_name, | 363 | .name = (char *) hcd_name, |
182 | .id_table = pci_ids, | 364 | .id_table = pci_ids, |
183 | 365 | ||
184 | .probe = usb_hcd_pci_probe, | 366 | .probe = xhci_pci_probe, |
185 | .remove = usb_hcd_pci_remove, | 367 | .remove = xhci_pci_remove, |
186 | /* suspend and resume implemented later */ | 368 | /* suspend and resume implemented later */ |
187 | 369 | ||
188 | .shutdown = usb_hcd_pci_shutdown, | 370 | .shutdown = usb_hcd_pci_shutdown, |
371 | #ifdef CONFIG_PM_SLEEP | ||
372 | .driver = { | ||
373 | .pm = &usb_hcd_pci_pm_ops | ||
374 | }, | ||
375 | #endif | ||
189 | }; | 376 | }; |
190 | 377 | ||
191 | int xhci_register_pci(void) | 378 | int xhci_register_pci(void) |