aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/wusbcore
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2013-12-09 15:15:14 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-09 16:29:21 -0500
commitea1af42d3d4da73c9d75984f24e569515261b3fd (patch)
tree630fe9460c6de8ea29ca83248777dfe145df7408 /drivers/usb/wusbcore
parent7b3e3740f2d0faca9351db88974be534009a3d8d (diff)
usb: wusbcore: move isoc_frame_index from wa_xfer to wa_seg
If multiple segments belonging to an isoc transfer are submitted concurrently, the isoc_frame_index field in struct wa_xfer can get corrupted. This patch moves the isoc_frame_index field from struct wa_xfer to struct wa_seg to prevent this from happening. 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.c21
1 files changed, 10 insertions, 11 deletions
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 673ad80c1b55..6aeb52cdc3fb 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -124,6 +124,8 @@ struct wa_seg {
124 u8 index; /* which segment we are */ 124 u8 index; /* which segment we are */
125 int isoc_frame_count; /* number of isoc frames in this segment. */ 125 int isoc_frame_count; /* number of isoc frames in this segment. */
126 int isoc_frame_offset; /* starting frame offset in the xfer URB. */ 126 int isoc_frame_offset; /* starting frame offset in the xfer URB. */
127 /* Isoc frame that the current transfer buffer corresponds to. */
128 int isoc_frame_index;
127 int isoc_size; /* size of all isoc frames sent by this seg. */ 129 int isoc_size; /* size of all isoc frames sent by this seg. */
128 enum wa_seg_status status; 130 enum wa_seg_status status;
129 ssize_t result; /* bytes xfered or error */ 131 ssize_t result; /* bytes xfered or error */
@@ -158,8 +160,6 @@ struct wa_xfer {
158 unsigned is_dma:1; 160 unsigned is_dma:1;
159 size_t seg_size; 161 size_t seg_size;
160 int result; 162 int result;
161 /* Isoc frame that the current transfer buffer corresponds to. */
162 int dto_isoc_frame_index;
163 163
164 gfp_t gfp; /* allocation mask */ 164 gfp_t gfp; /* allocation mask */
165 165
@@ -701,23 +701,23 @@ static void wa_seg_dto_cb(struct urb *urb)
701 if (usb_pipeisoc(xfer->urb->pipe)) { 701 if (usb_pipeisoc(xfer->urb->pipe)) {
702 /* Alereon HWA sends all isoc frames in a single transfer. */ 702 /* Alereon HWA sends all isoc frames in a single transfer. */
703 if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) 703 if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
704 xfer->dto_isoc_frame_index += seg->isoc_frame_count; 704 seg->isoc_frame_index += seg->isoc_frame_count;
705 else 705 else
706 xfer->dto_isoc_frame_index += 1; 706 seg->isoc_frame_index += 1;
707 if (xfer->dto_isoc_frame_index < seg->isoc_frame_count) { 707 if (seg->isoc_frame_index < seg->isoc_frame_count) {
708 data_send_done = 0; 708 data_send_done = 0;
709 holding_dto = 1; /* checked in error cases. */ 709 holding_dto = 1; /* checked in error cases. */
710 /* 710 /*
711 * if this is the last isoc frame of the segment, we 711 * if this is the last isoc frame of the segment, we
712 * can release DTO after sending this frame. 712 * can release DTO after sending this frame.
713 */ 713 */
714 if ((xfer->dto_isoc_frame_index + 1) >= 714 if ((seg->isoc_frame_index + 1) >=
715 seg->isoc_frame_count) 715 seg->isoc_frame_count)
716 release_dto = 1; 716 release_dto = 1;
717 } 717 }
718 dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n", 718 dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n",
719 wa_xfer_id(xfer), seg->index, 719 wa_xfer_id(xfer), seg->index, seg->isoc_frame_index,
720 xfer->dto_isoc_frame_index, holding_dto, release_dto); 720 holding_dto, release_dto);
721 } 721 }
722 spin_unlock_irqrestore(&xfer->lock, flags); 722 spin_unlock_irqrestore(&xfer->lock, flags);
723 723
@@ -737,8 +737,7 @@ static void wa_seg_dto_cb(struct urb *urb)
737 * send the URB and release DTO if we no longer need it. 737 * send the URB and release DTO if we no longer need it.
738 */ 738 */
739 __wa_populate_dto_urb_isoc(xfer, seg, 739 __wa_populate_dto_urb_isoc(xfer, seg,
740 seg->isoc_frame_offset + 740 seg->isoc_frame_offset + seg->isoc_frame_index);
741 xfer->dto_isoc_frame_index);
742 741
743 /* resubmit the URB with the next isoc frame. */ 742 /* resubmit the URB with the next isoc frame. */
744 result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC); 743 result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
@@ -1324,12 +1323,12 @@ static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
1324 struct wahc *wa = xfer->wa; 1323 struct wahc *wa = xfer->wa;
1325 1324
1326 result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC); 1325 result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
1326 seg->isoc_frame_index = 0;
1327 if (result < 0) { 1327 if (result < 0) {
1328 pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n", 1328 pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
1329 __func__, xfer, seg->index, result); 1329 __func__, xfer, seg->index, result);
1330 goto error_iso_pack_desc_submit; 1330 goto error_iso_pack_desc_submit;
1331 } 1331 }
1332 xfer->dto_isoc_frame_index = 0;
1333 /* 1332 /*
1334 * If this segment contains more than one isoc frame, hold 1333 * If this segment contains more than one isoc frame, hold
1335 * onto the dto resource until we send all frames. 1334 * onto the dto resource until we send all frames.