diff options
author | Thomas Pugliese <thomas.pugliese@gmail.com> | 2014-03-07 16:37:34 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-03-09 01:30:28 -0500 |
commit | 04a378f36d9dc9e242ff206fcad23ba258dba818 (patch) | |
tree | b28e1ad06cffbdb07190eb83a6259485bbc99a82 /drivers/usb/wusbcore | |
parent | 7338a0659365ec0fbdc6f79de8b9fba2280fd155 (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.c | 106 |
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. */ |
2163 | static void __wa_populate_buf_in_urb_isoc(struct wahc *wa, struct wa_xfer *xfer, | 2163 | static 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", |