diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2011-09-23 17:19:58 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-09-26 18:51:12 -0400 |
commit | 421aa841a134f6a743111cf44d0c6d3b45e3cf8c (patch) | |
tree | 01be6ebd0ad752bac77c3b432cd3ee4b0050b4a8 /drivers/usb/host | |
parent | 3fd1ec58734e38a3f48776b6831ad0279d92d094 (diff) |
usb/xhci: hide MSI code behind PCI bars
The MSI related fuctionality requires a few structs which are not
available if CONFIG_PCI is not enabled. This is a prepartion to allow
xhci be built without CONFIG_PCI set.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
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')
-rw-r--r-- | drivers/usb/host/xhci.c | 160 |
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 | 179 | static int xhci_free_msi(struct xhci_hcd *xhci) |
180 | * free all IRQs request | ||
181 | */ | ||
182 | static 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 | */ | ||
221 | static 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 | */ |
229 | static int xhci_setup_msix(struct xhci_hcd *xhci) | 242 | static 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 | ||
318 | static 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 | |||
328 | static 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 | |||
369 | static int xhci_try_enable_msi(struct usb_hcd *hcd) | ||
370 | { | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static void xhci_cleanup_msix(struct xhci_hcd *xhci) | ||
375 | { | ||
376 | } | ||
377 | |||
378 | static 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 | ||
400 | static 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 | } |