aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/xhci.c160
1 files changed, 98 insertions, 62 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 583a3e330105..a8c3e8a34d26 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -175,28 +175,19 @@ int xhci_reset(struct xhci_hcd *xhci)
175 return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); 175 return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
176} 176}
177 177
178/* 178#ifdef CONFIG_PCI
179 * Free IRQs 179static int xhci_free_msi(struct xhci_hcd *xhci)
180 * free all IRQs request
181 */
182static void xhci_free_irq(struct xhci_hcd *xhci)
183{ 180{
184 int i; 181 int i;
185 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
186
187 /* return if using legacy interrupt */
188 if (xhci_to_hcd(xhci)->irq >= 0)
189 return;
190 182
191 if (xhci->msix_entries) { 183 if (!xhci->msix_entries)
192 for (i = 0; i < xhci->msix_count; i++) 184 return -EINVAL;
193 if (xhci->msix_entries[i].vector)
194 free_irq(xhci->msix_entries[i].vector,
195 xhci_to_hcd(xhci));
196 } else if (pdev->irq >= 0)
197 free_irq(pdev->irq, xhci_to_hcd(xhci));
198 185
199 return; 186 for (i = 0; i < xhci->msix_count; i++)
187 if (xhci->msix_entries[i].vector)
188 free_irq(xhci->msix_entries[i].vector,
189 xhci_to_hcd(xhci));
190 return 0;
200} 191}
201 192
202/* 193/*
@@ -224,6 +215,28 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
224} 215}
225 216
226/* 217/*
218 * Free IRQs
219 * free all IRQs request
220 */
221static void xhci_free_irq(struct xhci_hcd *xhci)
222{
223 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
224 int ret;
225
226 /* return if using legacy interrupt */
227 if (xhci_to_hcd(xhci)->irq >= 0)
228 return;
229
230 ret = xhci_free_msi(xhci);
231 if (!ret)
232 return;
233 if (pdev->irq >= 0)
234 free_irq(pdev->irq, xhci_to_hcd(xhci));
235
236 return;
237}
238
239/*
227 * Set up MSI-X 240 * Set up MSI-X
228 */ 241 */
229static int xhci_setup_msix(struct xhci_hcd *xhci) 242static int xhci_setup_msix(struct xhci_hcd *xhci)
@@ -302,6 +315,72 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
302 return; 315 return;
303} 316}
304 317
318static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
319{
320 int i;
321
322 if (xhci->msix_entries) {
323 for (i = 0; i < xhci->msix_count; i++)
324 synchronize_irq(xhci->msix_entries[i].vector);
325 }
326}
327
328static int xhci_try_enable_msi(struct usb_hcd *hcd)
329{
330 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
331 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
332 int ret;
333
334 /*
335 * Some Fresco Logic host controllers advertise MSI, but fail to
336 * generate interrupts. Don't even try to enable MSI.
337 */
338 if (xhci->quirks & XHCI_BROKEN_MSI)
339 return 0;
340
341 /* unregister the legacy interrupt */
342 if (hcd->irq)
343 free_irq(hcd->irq, hcd);
344 hcd->irq = -1;
345
346 ret = xhci_setup_msix(xhci);
347 if (ret)
348 /* fall back to msi*/
349 ret = xhci_setup_msi(xhci);
350
351 if (!ret)
352 /* hcd->irq is -1, we have MSI */
353 return 0;
354
355 /* fall back to legacy interrupt*/
356 ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
357 hcd->irq_descr, hcd);
358 if (ret) {
359 xhci_err(xhci, "request interrupt %d failed\n",
360 pdev->irq);
361 return ret;
362 }
363 hcd->irq = pdev->irq;
364 return 0;
365}
366
367#else
368
369static int xhci_try_enable_msi(struct usb_hcd *hcd)
370{
371 return 0;
372}
373
374static void xhci_cleanup_msix(struct xhci_hcd *xhci)
375{
376}
377
378static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
379{
380}
381
382#endif
383
305/* 384/*
306 * Initialize memory for HCD and xHC (one-time init). 385 * Initialize memory for HCD and xHC (one-time init).
307 * 386 *
@@ -397,45 +476,6 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
397 return 0; 476 return 0;
398} 477}
399 478
400static int xhci_try_enable_msi(struct usb_hcd *hcd)
401{
402 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
403 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
404 int ret;
405
406 /*
407 * Some Fresco Logic host controllers advertise MSI, but fail to
408 * generate interrupts. Don't even try to enable MSI.
409 */
410 if (xhci->quirks & XHCI_BROKEN_MSI)
411 return 0;
412
413 /* unregister the legacy interrupt */
414 if (hcd->irq)
415 free_irq(hcd->irq, hcd);
416 hcd->irq = -1;
417
418 ret = xhci_setup_msix(xhci);
419 if (ret)
420 /* fall back to msi*/
421 ret = xhci_setup_msi(xhci);
422
423 if (!ret)
424 /* hcd->irq is -1, we have MSI */
425 return 0;
426
427 /* fall back to legacy interrupt*/
428 ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
429 hcd->irq_descr, hcd);
430 if (ret) {
431 xhci_err(xhci, "request interrupt %d failed\n",
432 pdev->irq);
433 return ret;
434 }
435 hcd->irq = pdev->irq;
436 return 0;
437}
438
439/* 479/*
440 * Start the HC after it was halted. 480 * Start the HC after it was halted.
441 * 481 *
@@ -708,7 +748,6 @@ int xhci_suspend(struct xhci_hcd *xhci)
708 int rc = 0; 748 int rc = 0;
709 struct usb_hcd *hcd = xhci_to_hcd(xhci); 749 struct usb_hcd *hcd = xhci_to_hcd(xhci);
710 u32 command; 750 u32 command;
711 int i;
712 751
713 spin_lock_irq(&xhci->lock); 752 spin_lock_irq(&xhci->lock);
714 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 753 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -744,10 +783,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
744 783
745 /* step 5: remove core well power */ 784 /* step 5: remove core well power */
746 /* synchronize irq when using MSI-X */ 785 /* synchronize irq when using MSI-X */
747 if (xhci->msix_entries) { 786 xhci_msix_sync_irqs(xhci);
748 for (i = 0; i < xhci->msix_count; i++)
749 synchronize_irq(xhci->msix_entries[i].vector);
750 }
751 787
752 return rc; 788 return rc;
753} 789}