aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorDong Nguyen <Dong.Nguyen@amd.com>2010-07-21 19:56:08 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 17:35:40 -0400
commit43b86af83da7db8b2c6d85ca970203950e5bad88 (patch)
treedce6f46e7902bb295d2520c5ef9d3191e1e31489 /drivers/usb
parent13dd0c9767349b280cf131c34461f85e5effc42a (diff)
USB: xHCI: Supporting MSI/MSI-X
Enable MSI/MSI-X supporting in xhci driver. Provide the mechanism to fall back using MSI and Legacy IRQs if MSI-X IRQs register failed. Signed-off-by: Dong Nguyen <Dong.Nguyen@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')
-rw-r--r--drivers/usb/core/hcd.c1
-rw-r--r--drivers/usb/host/xhci.c166
-rw-r--r--drivers/usb/host/xhci.h2
3 files changed, 128 insertions, 41 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index c5753c797735..5cca00a6d09d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2085,6 +2085,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
2085 local_irq_restore(flags); 2085 local_irq_restore(flags);
2086 return rc; 2086 return rc;
2087} 2087}
2088EXPORT_SYMBOL_GPL(usb_hcd_irq);
2088 2089
2089/*-------------------------------------------------------------------------*/ 2090/*-------------------------------------------------------------------------*/
2090 2091
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 5e73386b3899..3106d22ae053 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -20,6 +20,7 @@
20 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */ 21 */
22 22
23#include <linux/pci.h>
23#include <linux/irq.h> 24#include <linux/irq.h>
24#include <linux/log2.h> 25#include <linux/log2.h>
25#include <linux/module.h> 26#include <linux/module.h>
@@ -171,22 +172,95 @@ int xhci_reset(struct xhci_hcd *xhci)
171 return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); 172 return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
172} 173}
173 174
175static irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
176{
177 irqreturn_t ret;
174 178
175#if 0 179 set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
176/* Set up MSI-X table for entry 0 (may claim other entries later) */ 180
177static int xhci_setup_msix(struct xhci_hcd *xhci) 181 ret = xhci_irq(hcd);
182
183 return ret;
184}
185
186/*
187 * Free IRQs
188 * free all IRQs request
189 */
190static void xhci_free_irq(struct xhci_hcd *xhci)
191{
192 int i;
193 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
194
195 /* return if using legacy interrupt */
196 if (xhci_to_hcd(xhci)->irq >= 0)
197 return;
198
199 if (xhci->msix_entries) {
200 for (i = 0; i < xhci->msix_count; i++)
201 if (xhci->msix_entries[i].vector)
202 free_irq(xhci->msix_entries[i].vector,
203 xhci_to_hcd(xhci));
204 } else if (pdev->irq >= 0)
205 free_irq(pdev->irq, xhci_to_hcd(xhci));
206
207 return;
208}
209
210/*
211 * Set up MSI
212 */
213static int xhci_setup_msi(struct xhci_hcd *xhci)
178{ 214{
179 int ret; 215 int ret;
216 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
217
218 ret = pci_enable_msi(pdev);
219 if (ret) {
220 xhci_err(xhci, "failed to allocate MSI entry\n");
221 return ret;
222 }
223
224 ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq,
225 0, "xhci_hcd", xhci_to_hcd(xhci));
226 if (ret) {
227 xhci_err(xhci, "disable MSI interrupt\n");
228 pci_disable_msi(pdev);
229 }
230
231 return ret;
232}
233
234/*
235 * Set up MSI-X
236 */
237static int xhci_setup_msix(struct xhci_hcd *xhci)
238{
239 int i, ret = 0;
180 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); 240 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
181 241
182 xhci->msix_count = 0; 242 /*
183 /* XXX: did I do this right? ixgbe does kcalloc for more than one */ 243 * calculate number of msi-x vectors supported.
184 xhci->msix_entries = kmalloc(sizeof(struct msix_entry), GFP_KERNEL); 244 * - HCS_MAX_INTRS: the max number of interrupts the host can handle,
245 * with max number of interrupters based on the xhci HCSPARAMS1.
246 * - num_online_cpus: maximum msi-x vectors per CPUs core.
247 * Add additional 1 vector to ensure always available interrupt.
248 */
249 xhci->msix_count = min(num_online_cpus() + 1,
250 HCS_MAX_INTRS(xhci->hcs_params1));
251
252 xhci->msix_entries =
253 kmalloc((sizeof(struct msix_entry))*xhci->msix_count,
254 GFP_KERNEL);
185 if (!xhci->msix_entries) { 255 if (!xhci->msix_entries) {
186 xhci_err(xhci, "Failed to allocate MSI-X entries\n"); 256 xhci_err(xhci, "Failed to allocate MSI-X entries\n");
187 return -ENOMEM; 257 return -ENOMEM;
188 } 258 }
189 xhci->msix_entries[0].entry = 0; 259
260 for (i = 0; i < xhci->msix_count; i++) {
261 xhci->msix_entries[i].entry = i;
262 xhci->msix_entries[i].vector = 0;
263 }
190 264
191 ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); 265 ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
192 if (ret) { 266 if (ret) {
@@ -194,20 +268,19 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
194 goto free_entries; 268 goto free_entries;
195 } 269 }
196 270
197 /* 271 for (i = 0; i < xhci->msix_count; i++) {
198 * Pass the xhci pointer value as the request_irq "cookie". 272 ret = request_irq(xhci->msix_entries[i].vector,
199 * If more irqs are added, this will need to be unique for each one. 273 (irq_handler_t)xhci_msi_irq,
200 */ 274 0, "xhci_hcd", xhci_to_hcd(xhci));
201 ret = request_irq(xhci->msix_entries[0].vector, &xhci_irq, 0, 275 if (ret)
202 "xHCI", xhci_to_hcd(xhci)); 276 goto disable_msix;
203 if (ret) {
204 xhci_err(xhci, "Failed to allocate MSI-X interrupt\n");
205 goto disable_msix;
206 } 277 }
207 xhci_dbg(xhci, "Finished setting up MSI-X\n"); 278
208 return 0; 279 return ret;
209 280
210disable_msix: 281disable_msix:
282 xhci_err(xhci, "disable MSI-X interrupt\n");
283 xhci_free_irq(xhci);
211 pci_disable_msix(pdev); 284 pci_disable_msix(pdev);
212free_entries: 285free_entries:
213 kfree(xhci->msix_entries); 286 kfree(xhci->msix_entries);
@@ -215,21 +288,23 @@ free_entries:
215 return ret; 288 return ret;
216} 289}
217 290
218/* XXX: code duplication; can xhci_setup_msix call this? */
219/* Free any IRQs and disable MSI-X */ 291/* Free any IRQs and disable MSI-X */
220static void xhci_cleanup_msix(struct xhci_hcd *xhci) 292static void xhci_cleanup_msix(struct xhci_hcd *xhci)
221{ 293{
222 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); 294 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
223 if (!xhci->msix_entries)
224 return;
225 295
226 free_irq(xhci->msix_entries[0].vector, xhci); 296 xhci_free_irq(xhci);
227 pci_disable_msix(pdev); 297
228 kfree(xhci->msix_entries); 298 if (xhci->msix_entries) {
229 xhci->msix_entries = NULL; 299 pci_disable_msix(pdev);
230 xhci_dbg(xhci, "Finished cleaning up MSI-X\n"); 300 kfree(xhci->msix_entries);
301 xhci->msix_entries = NULL;
302 } else {
303 pci_disable_msi(pdev);
304 }
305
306 return;
231} 307}
232#endif
233 308
234/* 309/*
235 * Initialize memory for HCD and xHC (one-time init). 310 * Initialize memory for HCD and xHC (one-time init).
@@ -423,20 +498,36 @@ int xhci_run(struct usb_hcd *hcd)
423{ 498{
424 u32 temp; 499 u32 temp;
425 u64 temp_64; 500 u64 temp_64;
501 u32 ret;
426 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 502 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
503 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
427 void (*doorbell)(struct xhci_hcd *) = NULL; 504 void (*doorbell)(struct xhci_hcd *) = NULL;
428 505
429 hcd->uses_new_polling = 1; 506 hcd->uses_new_polling = 1;
430 507
431 xhci_dbg(xhci, "xhci_run\n"); 508 xhci_dbg(xhci, "xhci_run\n");
432#if 0 /* FIXME: MSI not setup yet */ 509 /* unregister the legacy interrupt */
433 /* Do this at the very last minute */ 510 if (hcd->irq)
511 free_irq(hcd->irq, hcd);
512 hcd->irq = -1;
513
434 ret = xhci_setup_msix(xhci); 514 ret = xhci_setup_msix(xhci);
435 if (!ret) 515 if (ret)
436 return ret; 516 /* fall back to msi*/
517 ret = xhci_setup_msi(xhci);
518
519 if (ret) {
520 /* fall back to legacy interrupt*/
521 ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
522 hcd->irq_descr, hcd);
523 if (ret) {
524 xhci_err(xhci, "request interrupt %d failed\n",
525 pdev->irq);
526 return ret;
527 }
528 hcd->irq = pdev->irq;
529 }
437 530
438 return -ENOSYS;
439#endif
440#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING 531#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
441 init_timer(&xhci->event_ring_timer); 532 init_timer(&xhci->event_ring_timer);
442 xhci->event_ring_timer.data = (unsigned long) xhci; 533 xhci->event_ring_timer.data = (unsigned long) xhci;
@@ -520,11 +611,9 @@ void xhci_stop(struct usb_hcd *hcd)
520 spin_lock_irq(&xhci->lock); 611 spin_lock_irq(&xhci->lock);
521 xhci_halt(xhci); 612 xhci_halt(xhci);
522 xhci_reset(xhci); 613 xhci_reset(xhci);
614 xhci_cleanup_msix(xhci);
523 spin_unlock_irq(&xhci->lock); 615 spin_unlock_irq(&xhci->lock);
524 616
525#if 0 /* No MSI yet */
526 xhci_cleanup_msix(xhci);
527#endif
528#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING 617#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
529 /* Tell the event ring poll function not to reschedule */ 618 /* Tell the event ring poll function not to reschedule */
530 xhci->zombie = 1; 619 xhci->zombie = 1;
@@ -558,11 +647,8 @@ void xhci_shutdown(struct usb_hcd *hcd)
558 647
559 spin_lock_irq(&xhci->lock); 648 spin_lock_irq(&xhci->lock);
560 xhci_halt(xhci); 649 xhci_halt(xhci);
561 spin_unlock_irq(&xhci->lock);
562
563#if 0
564 xhci_cleanup_msix(xhci); 650 xhci_cleanup_msix(xhci);
565#endif 651 spin_unlock_irq(&xhci->lock);
566 652
567 xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", 653 xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
568 xhci_readl(xhci, &xhci->op_regs->status)); 654 xhci_readl(xhci, &xhci->op_regs->status));
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 6c7e3430ec93..5bc03d1c2beb 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1130,7 +1130,7 @@ struct xhci_hcd {
1130 int page_size; 1130 int page_size;
1131 /* Valid values are 12 to 20, inclusive */ 1131 /* Valid values are 12 to 20, inclusive */
1132 int page_shift; 1132 int page_shift;
1133 /* only one MSI vector for now, but might need more later */ 1133 /* msi-x vectors */
1134 int msix_count; 1134 int msix_count;
1135 struct msix_entry *msix_entries; 1135 struct msix_entry *msix_entries;
1136 /* data structures */ 1136 /* data structures */