aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/wusbcore
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2014-03-07 16:37:34 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-03-09 01:30:28 -0500
commit04a378f36d9dc9e242ff206fcad23ba258dba818 (patch)
treeb28e1ad06cffbdb07190eb83a6259485bbc99a82 /drivers/usb/wusbcore
parent7338a0659365ec0fbdc6f79de8b9fba2280fd155 (diff)
usb: wusbcore: combine iso transfer result frame reads when possible
When reading the transfer result data for an isochronous in request, if the current frame actual_length is contiguous with the next frame and actual_length is a multiple of the DTI endpoint max packet size, combine the current frame with the next frame in a single URB. This reduces the number of URBs that must be submitted in that case which increases performance and reduces CPU interrupt overhead. Signed-off-by: Thomas Pugliese <thomas.pugliese@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/wusbcore')
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c106
1 files changed, 76 insertions, 30 deletions
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 52c7259705e6..f930bbb1a0ff 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -2160,22 +2160,59 @@ static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
2160} 2160}
2161 2161
2162/* Populate the wa->buf_in_urb based on the current isoc transfer state. */ 2162/* Populate the wa->buf_in_urb based on the current isoc transfer state. */
2163static void __wa_populate_buf_in_urb_isoc(struct wahc *wa, struct wa_xfer *xfer, 2163static int __wa_populate_buf_in_urb_isoc(struct wahc *wa, struct wa_xfer *xfer,
2164 struct wa_seg *seg, int curr_iso_frame) 2164 struct wa_seg *seg)
2165{ 2165{
2166 int urb_start_frame = seg->isoc_frame_index + seg->isoc_frame_offset;
2167 int seg_index, total_len = 0, urb_frame_index = urb_start_frame;
2168 struct usb_iso_packet_descriptor *iso_frame_desc =
2169 xfer->urb->iso_frame_desc;
2170 const int dti_packet_size = usb_endpoint_maxp(wa->dti_epd);
2171 int next_frame_contiguous;
2172 struct usb_iso_packet_descriptor *iso_frame;
2173
2166 BUG_ON(wa->buf_in_urb->status == -EINPROGRESS); 2174 BUG_ON(wa->buf_in_urb->status == -EINPROGRESS);
2167 2175
2176 /*
2177 * If the current frame actual_length is contiguous with the next frame
2178 * and actual_length is a multiple of the DTI endpoint max packet size,
2179 * combine the current frame with the next frame in a single URB. This
2180 * reduces the number of URBs that must be submitted in that case.
2181 */
2182 seg_index = seg->isoc_frame_index;
2183 do {
2184 next_frame_contiguous = 0;
2185
2186 iso_frame = &iso_frame_desc[urb_frame_index];
2187 total_len += iso_frame->actual_length;
2188 ++urb_frame_index;
2189 ++seg_index;
2190
2191 if (seg_index < seg->isoc_frame_count) {
2192 struct usb_iso_packet_descriptor *next_iso_frame;
2193
2194 next_iso_frame = &iso_frame_desc[urb_frame_index];
2195
2196 if ((iso_frame->offset + iso_frame->actual_length) ==
2197 next_iso_frame->offset)
2198 next_frame_contiguous = 1;
2199 }
2200 } while (next_frame_contiguous
2201 && ((iso_frame->actual_length % dti_packet_size) == 0));
2202
2168 /* this should always be 0 before a resubmit. */ 2203 /* this should always be 0 before a resubmit. */
2169 wa->buf_in_urb->num_mapped_sgs = 0; 2204 wa->buf_in_urb->num_mapped_sgs = 0;
2170 wa->buf_in_urb->transfer_dma = xfer->urb->transfer_dma + 2205 wa->buf_in_urb->transfer_dma = xfer->urb->transfer_dma +
2171 xfer->urb->iso_frame_desc[curr_iso_frame].offset; 2206 iso_frame_desc[urb_start_frame].offset;
2172 wa->buf_in_urb->transfer_buffer_length = 2207 wa->buf_in_urb->transfer_buffer_length = total_len;
2173 xfer->urb->iso_frame_desc[curr_iso_frame].actual_length;
2174 wa->buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 2208 wa->buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
2175 wa->buf_in_urb->transfer_buffer = NULL; 2209 wa->buf_in_urb->transfer_buffer = NULL;
2176 wa->buf_in_urb->sg = NULL; 2210 wa->buf_in_urb->sg = NULL;
2177 wa->buf_in_urb->num_sgs = 0; 2211 wa->buf_in_urb->num_sgs = 0;
2178 wa->buf_in_urb->context = seg; 2212 wa->buf_in_urb->context = seg;
2213
2214 /* return the number of frames included in this URB. */
2215 return seg_index - seg->isoc_frame_index;
2179} 2216}
2180 2217
2181/* Populate the wa->buf_in_urb based on the current transfer state. */ 2218/* Populate the wa->buf_in_urb based on the current transfer state. */
@@ -2458,19 +2495,20 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb)
2458 } 2495 }
2459 2496
2460 if (xfer->is_inbound && data_frame_count) { 2497 if (xfer->is_inbound && data_frame_count) {
2461 int result; 2498 int result, urb_frame_count;
2462 2499
2463 seg->isoc_frame_index = first_frame_index; 2500 seg->isoc_frame_index = first_frame_index;
2464 /* submit a read URB for the first frame with data. */ 2501 /* submit a read URB for the first frame with data. */
2465 __wa_populate_buf_in_urb_isoc(wa, xfer, seg, 2502 urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, xfer, seg);
2466 seg->isoc_frame_index + seg->isoc_frame_offset); 2503 /* advance index to start of next read URB. */
2504 seg->isoc_frame_index += urb_frame_count;
2467 2505
2468 result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC); 2506 result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC);
2469 if (result < 0) { 2507 if (result < 0) {
2470 dev_err(dev, "DTI Error: Could not submit buf in URB (%d)", 2508 dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
2471 result); 2509 result);
2472 wa_reset_all(wa); 2510 wa_reset_all(wa);
2473 } else if (data_frame_count > 1) 2511 } else if (data_frame_count > urb_frame_count)
2474 /* If we need to read multiple frames, set DTI busy. */ 2512 /* If we need to read multiple frames, set DTI busy. */
2475 dti_busy = 1; 2513 dti_busy = 1;
2476 } else { 2514 } else {
@@ -2511,8 +2549,9 @@ static void wa_buf_in_cb(struct urb *urb)
2511 struct wahc *wa; 2549 struct wahc *wa;
2512 struct device *dev; 2550 struct device *dev;
2513 struct wa_rpipe *rpipe; 2551 struct wa_rpipe *rpipe;
2514 unsigned rpipe_ready = 0, seg_index, isoc_data_frame_count = 0; 2552 unsigned rpipe_ready = 0, isoc_data_frame_count = 0;
2515 unsigned long flags; 2553 unsigned long flags;
2554 int resubmit_dti = 0;
2516 u8 done = 0; 2555 u8 done = 0;
2517 2556
2518 /* free the sg if it was used. */ 2557 /* free the sg if it was used. */
@@ -2524,17 +2563,16 @@ static void wa_buf_in_cb(struct urb *urb)
2524 dev = &wa->usb_iface->dev; 2563 dev = &wa->usb_iface->dev;
2525 2564
2526 if (usb_pipeisoc(xfer->urb->pipe)) { 2565 if (usb_pipeisoc(xfer->urb->pipe)) {
2566 struct usb_iso_packet_descriptor *iso_frame_desc =
2567 xfer->urb->iso_frame_desc;
2568 int seg_index;
2569
2527 /* 2570 /*
2528 * Find the next isoc frame with data. Bail out after 2571 * Find the next isoc frame with data and count how many
2529 * isoc_data_frame_count > 1 since there is no need to walk 2572 * frames with data remain.
2530 * the entire frame array. We just need to know if
2531 * isoc_data_frame_count is 0, 1, or >1.
2532 */ 2573 */
2533 seg_index = seg->isoc_frame_index + 1; 2574 seg_index = seg->isoc_frame_index;
2534 while ((seg_index < seg->isoc_frame_count) 2575 while (seg_index < seg->isoc_frame_count) {
2535 && (isoc_data_frame_count <= 1)) {
2536 struct usb_iso_packet_descriptor *iso_frame_desc =
2537 xfer->urb->iso_frame_desc;
2538 const int urb_frame_index = 2576 const int urb_frame_index =
2539 seg->isoc_frame_offset + seg_index; 2577 seg->isoc_frame_offset + seg_index;
2540 2578
@@ -2555,16 +2593,28 @@ static void wa_buf_in_cb(struct urb *urb)
2555 2593
2556 seg->result += urb->actual_length; 2594 seg->result += urb->actual_length;
2557 if (isoc_data_frame_count > 0) { 2595 if (isoc_data_frame_count > 0) {
2558 int result; 2596 int result, urb_frame_count;
2559 /* submit a read URB for the first frame with data. */ 2597
2560 __wa_populate_buf_in_urb_isoc(wa, xfer, seg, 2598 /* submit a read URB for the next frame with data. */
2561 seg->isoc_frame_index + seg->isoc_frame_offset); 2599 urb_frame_count = __wa_populate_buf_in_urb_isoc(wa,
2600 xfer, seg);
2601 /* advance index to start of next read URB. */
2602 seg->isoc_frame_index += urb_frame_count;
2562 result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC); 2603 result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC);
2563 if (result < 0) { 2604 if (result < 0) {
2564 dev_err(dev, "DTI Error: Could not submit buf in URB (%d)", 2605 dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
2565 result); 2606 result);
2566 wa_reset_all(wa); 2607 wa_reset_all(wa);
2567 } 2608 }
2609 /*
2610 * If we are in this callback and
2611 * isoc_data_frame_count > 0, it means that the dti_urb
2612 * submission was delayed in wa_dti_cb. Once
2613 * we submit the last buf_in_urb, we can submit the
2614 * delayed dti_urb.
2615 */
2616 resubmit_dti = (isoc_data_frame_count ==
2617 urb_frame_count);
2568 } else { 2618 } else {
2569 rpipe = xfer->ep->hcpriv; 2619 rpipe = xfer->ep->hcpriv;
2570 dev_dbg(dev, 2620 dev_dbg(dev,
@@ -2585,6 +2635,7 @@ static void wa_buf_in_cb(struct urb *urb)
2585 case -ENOENT: /* as it was done by the who unlinked us */ 2635 case -ENOENT: /* as it was done by the who unlinked us */
2586 break; 2636 break;
2587 default: /* Other errors ... */ 2637 default: /* Other errors ... */
2638 resubmit_dti = 1;
2588 spin_lock_irqsave(&xfer->lock, flags); 2639 spin_lock_irqsave(&xfer->lock, flags);
2589 rpipe = xfer->ep->hcpriv; 2640 rpipe = xfer->ep->hcpriv;
2590 if (printk_ratelimit()) 2641 if (printk_ratelimit())
@@ -2607,13 +2658,8 @@ static void wa_buf_in_cb(struct urb *urb)
2607 if (rpipe_ready) 2658 if (rpipe_ready)
2608 wa_xfer_delayed_run(rpipe); 2659 wa_xfer_delayed_run(rpipe);
2609 } 2660 }
2610 /* 2661
2611 * If we are in this callback and isoc_data_frame_count > 0, it means 2662 if (resubmit_dti) {
2612 * that the dti_urb submission was delayed in wa_dti_cb. Once
2613 * isoc_data_frame_count gets to 1, we can submit the deferred URB
2614 * since the last buf_in_urb was just submitted.
2615 */
2616 if (isoc_data_frame_count == 1) {
2617 int result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC); 2663 int result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
2618 if (result < 0) { 2664 if (result < 0) {
2619 dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n", 2665 dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",