diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2010-07-30 01:12:29 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 17:35:44 -0400 |
commit | 9032cd52798daf4cd6314ffea5030b37b3eb34af (patch) | |
tree | afcc0b71073b069e0ea19f4e5f4a19706964ebab /drivers/usb/host | |
parent | 021bff9179c2d19c26599dc3e9134d04cf1c8a3a (diff) |
USB: xhci: Performance - move interrupt handlers into xhci-ring.c
Most of the work for interrupt handling is done in xhci-ring.c, so it makes
sense to move the functions that are first called when an interrupt happens
(xhci_irq() or xhci_msi_irq()) into xhci-ring.c, so that the compiler can better
optimize them.
Shorten some lines to make it pass checkpatch.
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-ring.c | 103 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 103 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 1 |
3 files changed, 104 insertions, 103 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 7f1c54585b63..4b50a02ba114 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -2030,6 +2030,109 @@ void xhci_handle_event(struct xhci_hcd *xhci) | |||
2030 | /* Are there more items on the event ring? */ | 2030 | /* Are there more items on the event ring? */ |
2031 | xhci_handle_event(xhci); | 2031 | xhci_handle_event(xhci); |
2032 | } | 2032 | } |
2033 | /* | ||
2034 | * Called in interrupt context when there might be work | ||
2035 | * queued on the event ring | ||
2036 | * | ||
2037 | * xhci->lock must be held by caller. | ||
2038 | */ | ||
2039 | static void xhci_work(struct xhci_hcd *xhci) | ||
2040 | { | ||
2041 | u32 temp; | ||
2042 | u64 temp_64; | ||
2043 | |||
2044 | /* | ||
2045 | * Clear the op reg interrupt status first, | ||
2046 | * so we can receive interrupts from other MSI-X interrupters. | ||
2047 | * Write 1 to clear the interrupt status. | ||
2048 | */ | ||
2049 | temp = xhci_readl(xhci, &xhci->op_regs->status); | ||
2050 | temp |= STS_EINT; | ||
2051 | xhci_writel(xhci, temp, &xhci->op_regs->status); | ||
2052 | /* FIXME when MSI-X is supported and there are multiple vectors */ | ||
2053 | /* Clear the MSI-X event interrupt status */ | ||
2054 | |||
2055 | /* Acknowledge the interrupt */ | ||
2056 | temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); | ||
2057 | temp |= 0x3; | ||
2058 | xhci_writel(xhci, temp, &xhci->ir_set->irq_pending); | ||
2059 | |||
2060 | if (xhci->xhc_state & XHCI_STATE_DYING) | ||
2061 | xhci_dbg(xhci, "xHCI dying, ignoring interrupt. " | ||
2062 | "Shouldn't IRQs be disabled?\n"); | ||
2063 | else | ||
2064 | /* FIXME this should be a delayed service routine | ||
2065 | * that clears the EHB. | ||
2066 | */ | ||
2067 | xhci_handle_event(xhci); | ||
2068 | |||
2069 | /* Clear the event handler busy flag (RW1C); event ring is empty. */ | ||
2070 | temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); | ||
2071 | xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue); | ||
2072 | /* Flush posted writes -- FIXME is this necessary? */ | ||
2073 | xhci_readl(xhci, &xhci->ir_set->irq_pending); | ||
2074 | } | ||
2075 | |||
2076 | /* | ||
2077 | * xHCI spec says we can get an interrupt, and if the HC has an error condition, | ||
2078 | * we might get bad data out of the event ring. Section 4.10.2.7 has a list of | ||
2079 | * indicators of an event TRB error, but we check the status *first* to be safe. | ||
2080 | */ | ||
2081 | irqreturn_t xhci_irq(struct usb_hcd *hcd) | ||
2082 | { | ||
2083 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
2084 | u32 temp, temp2; | ||
2085 | union xhci_trb *trb; | ||
2086 | |||
2087 | spin_lock(&xhci->lock); | ||
2088 | trb = xhci->event_ring->dequeue; | ||
2089 | /* Check if the xHC generated the interrupt, or the irq is shared */ | ||
2090 | temp = xhci_readl(xhci, &xhci->op_regs->status); | ||
2091 | temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); | ||
2092 | if (temp == 0xffffffff && temp2 == 0xffffffff) | ||
2093 | goto hw_died; | ||
2094 | |||
2095 | if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) { | ||
2096 | spin_unlock(&xhci->lock); | ||
2097 | xhci_warn(xhci, "Spurious interrupt.\n"); | ||
2098 | return IRQ_NONE; | ||
2099 | } | ||
2100 | xhci_dbg(xhci, "op reg status = %08x\n", temp); | ||
2101 | xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2); | ||
2102 | xhci_dbg(xhci, "Event ring dequeue ptr:\n"); | ||
2103 | xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n", | ||
2104 | (unsigned long long) | ||
2105 | xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb), | ||
2106 | lower_32_bits(trb->link.segment_ptr), | ||
2107 | upper_32_bits(trb->link.segment_ptr), | ||
2108 | (unsigned int) trb->link.intr_target, | ||
2109 | (unsigned int) trb->link.control); | ||
2110 | |||
2111 | if (temp & STS_FATAL) { | ||
2112 | xhci_warn(xhci, "WARNING: Host System Error\n"); | ||
2113 | xhci_halt(xhci); | ||
2114 | hw_died: | ||
2115 | xhci_to_hcd(xhci)->state = HC_STATE_HALT; | ||
2116 | spin_unlock(&xhci->lock); | ||
2117 | return -ESHUTDOWN; | ||
2118 | } | ||
2119 | |||
2120 | xhci_work(xhci); | ||
2121 | spin_unlock(&xhci->lock); | ||
2122 | |||
2123 | return IRQ_HANDLED; | ||
2124 | } | ||
2125 | |||
2126 | irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) | ||
2127 | { | ||
2128 | irqreturn_t ret; | ||
2129 | |||
2130 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); | ||
2131 | |||
2132 | ret = xhci_irq(hcd); | ||
2133 | |||
2134 | return ret; | ||
2135 | } | ||
2033 | 2136 | ||
2034 | /**** Endpoint Ring Operations ****/ | 2137 | /**** Endpoint Ring Operations ****/ |
2035 | 2138 | ||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f5e0b00cbb83..d5c550ea3e68 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -172,17 +172,6 @@ int xhci_reset(struct xhci_hcd *xhci) | |||
172 | 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); |
173 | } | 173 | } |
174 | 174 | ||
175 | static irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) | ||
176 | { | ||
177 | irqreturn_t ret; | ||
178 | |||
179 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); | ||
180 | |||
181 | ret = xhci_irq(hcd); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /* | 175 | /* |
187 | * Free IRQs | 176 | * Free IRQs |
188 | * free all IRQs request | 177 | * free all IRQs request |
@@ -332,100 +321,8 @@ int xhci_init(struct usb_hcd *hcd) | |||
332 | return retval; | 321 | return retval; |
333 | } | 322 | } |
334 | 323 | ||
335 | /* | ||
336 | * Called in interrupt context when there might be work | ||
337 | * queued on the event ring | ||
338 | * | ||
339 | * xhci->lock must be held by caller. | ||
340 | */ | ||
341 | static void xhci_work(struct xhci_hcd *xhci) | ||
342 | { | ||
343 | u32 temp; | ||
344 | u64 temp_64; | ||
345 | |||
346 | /* | ||
347 | * Clear the op reg interrupt status first, | ||
348 | * so we can receive interrupts from other MSI-X interrupters. | ||
349 | * Write 1 to clear the interrupt status. | ||
350 | */ | ||
351 | temp = xhci_readl(xhci, &xhci->op_regs->status); | ||
352 | temp |= STS_EINT; | ||
353 | xhci_writel(xhci, temp, &xhci->op_regs->status); | ||
354 | /* FIXME when MSI-X is supported and there are multiple vectors */ | ||
355 | /* Clear the MSI-X event interrupt status */ | ||
356 | |||
357 | /* Acknowledge the interrupt */ | ||
358 | temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); | ||
359 | temp |= 0x3; | ||
360 | xhci_writel(xhci, temp, &xhci->ir_set->irq_pending); | ||
361 | /* Flush posted writes */ | ||
362 | xhci_readl(xhci, &xhci->ir_set->irq_pending); | ||
363 | |||
364 | if (xhci->xhc_state & XHCI_STATE_DYING) | ||
365 | xhci_dbg(xhci, "xHCI dying, ignoring interrupt. " | ||
366 | "Shouldn't IRQs be disabled?\n"); | ||
367 | else | ||
368 | /* FIXME this should be a delayed service routine | ||
369 | * that clears the EHB. | ||
370 | */ | ||
371 | xhci_handle_event(xhci); | ||
372 | |||
373 | /* Clear the event handler busy flag (RW1C); the event ring should be empty. */ | ||
374 | temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); | ||
375 | xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue); | ||
376 | /* Flush posted writes -- FIXME is this necessary? */ | ||
377 | xhci_readl(xhci, &xhci->ir_set->irq_pending); | ||
378 | } | ||
379 | |||
380 | /*-------------------------------------------------------------------------*/ | 324 | /*-------------------------------------------------------------------------*/ |
381 | 325 | ||
382 | /* | ||
383 | * xHCI spec says we can get an interrupt, and if the HC has an error condition, | ||
384 | * we might get bad data out of the event ring. Section 4.10.2.7 has a list of | ||
385 | * indicators of an event TRB error, but we check the status *first* to be safe. | ||
386 | */ | ||
387 | irqreturn_t xhci_irq(struct usb_hcd *hcd) | ||
388 | { | ||
389 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
390 | u32 temp, temp2; | ||
391 | union xhci_trb *trb; | ||
392 | |||
393 | spin_lock(&xhci->lock); | ||
394 | trb = xhci->event_ring->dequeue; | ||
395 | /* Check if the xHC generated the interrupt, or the irq is shared */ | ||
396 | temp = xhci_readl(xhci, &xhci->op_regs->status); | ||
397 | temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); | ||
398 | if (temp == 0xffffffff && temp2 == 0xffffffff) | ||
399 | goto hw_died; | ||
400 | |||
401 | if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) { | ||
402 | spin_unlock(&xhci->lock); | ||
403 | return IRQ_NONE; | ||
404 | } | ||
405 | xhci_dbg(xhci, "op reg status = %08x\n", temp); | ||
406 | xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2); | ||
407 | xhci_dbg(xhci, "Event ring dequeue ptr:\n"); | ||
408 | xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n", | ||
409 | (unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb), | ||
410 | lower_32_bits(trb->link.segment_ptr), | ||
411 | upper_32_bits(trb->link.segment_ptr), | ||
412 | (unsigned int) trb->link.intr_target, | ||
413 | (unsigned int) trb->link.control); | ||
414 | |||
415 | if (temp & STS_FATAL) { | ||
416 | xhci_warn(xhci, "WARNING: Host System Error\n"); | ||
417 | xhci_halt(xhci); | ||
418 | hw_died: | ||
419 | xhci_to_hcd(xhci)->state = HC_STATE_HALT; | ||
420 | spin_unlock(&xhci->lock); | ||
421 | return -ESHUTDOWN; | ||
422 | } | ||
423 | |||
424 | xhci_work(xhci); | ||
425 | spin_unlock(&xhci->lock); | ||
426 | |||
427 | return IRQ_HANDLED; | ||
428 | } | ||
429 | 326 | ||
430 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING | 327 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING |
431 | void xhci_event_ring_work(unsigned long arg) | 328 | void xhci_event_ring_work(unsigned long arg) |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9fe95c4e2a56..6d829c41d963 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1371,6 +1371,7 @@ void xhci_stop(struct usb_hcd *hcd); | |||
1371 | void xhci_shutdown(struct usb_hcd *hcd); | 1371 | void xhci_shutdown(struct usb_hcd *hcd); |
1372 | int xhci_get_frame(struct usb_hcd *hcd); | 1372 | int xhci_get_frame(struct usb_hcd *hcd); |
1373 | irqreturn_t xhci_irq(struct usb_hcd *hcd); | 1373 | irqreturn_t xhci_irq(struct usb_hcd *hcd); |
1374 | irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd); | ||
1374 | int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); | 1375 | int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); |
1375 | void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); | 1376 | void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); |
1376 | int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, | 1377 | int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, |