Commit ea1af42d authored by Thomas Pugliese's avatar Thomas Pugliese Committed by Greg Kroah-Hartman

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: default avatarThomas Pugliese <thomas.pugliese@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7b3e3740
...@@ -124,6 +124,8 @@ struct wa_seg { ...@@ -124,6 +124,8 @@ struct wa_seg {
u8 index; /* which segment we are */ u8 index; /* which segment we are */
int isoc_frame_count; /* number of isoc frames in this segment. */ int isoc_frame_count; /* number of isoc frames in this segment. */
int isoc_frame_offset; /* starting frame offset in the xfer URB. */ int isoc_frame_offset; /* starting frame offset in the xfer URB. */
/* Isoc frame that the current transfer buffer corresponds to. */
int isoc_frame_index;
int isoc_size; /* size of all isoc frames sent by this seg. */ int isoc_size; /* size of all isoc frames sent by this seg. */
enum wa_seg_status status; enum wa_seg_status status;
ssize_t result; /* bytes xfered or error */ ssize_t result; /* bytes xfered or error */
...@@ -158,8 +160,6 @@ struct wa_xfer { ...@@ -158,8 +160,6 @@ struct wa_xfer {
unsigned is_dma:1; unsigned is_dma:1;
size_t seg_size; size_t seg_size;
int result; int result;
/* Isoc frame that the current transfer buffer corresponds to. */
int dto_isoc_frame_index;
gfp_t gfp; /* allocation mask */ gfp_t gfp; /* allocation mask */
...@@ -701,23 +701,23 @@ static void wa_seg_dto_cb(struct urb *urb) ...@@ -701,23 +701,23 @@ static void wa_seg_dto_cb(struct urb *urb)
if (usb_pipeisoc(xfer->urb->pipe)) { if (usb_pipeisoc(xfer->urb->pipe)) {
/* Alereon HWA sends all isoc frames in a single transfer. */ /* Alereon HWA sends all isoc frames in a single transfer. */
if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
xfer->dto_isoc_frame_index += seg->isoc_frame_count; seg->isoc_frame_index += seg->isoc_frame_count;
else else
xfer->dto_isoc_frame_index += 1; seg->isoc_frame_index += 1;
if (xfer->dto_isoc_frame_index < seg->isoc_frame_count) { if (seg->isoc_frame_index < seg->isoc_frame_count) {
data_send_done = 0; data_send_done = 0;
holding_dto = 1; /* checked in error cases. */ holding_dto = 1; /* checked in error cases. */
/* /*
* if this is the last isoc frame of the segment, we * if this is the last isoc frame of the segment, we
* can release DTO after sending this frame. * can release DTO after sending this frame.
*/ */
if ((xfer->dto_isoc_frame_index + 1) >= if ((seg->isoc_frame_index + 1) >=
seg->isoc_frame_count) seg->isoc_frame_count)
release_dto = 1; release_dto = 1;
} }
dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n", dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n",
wa_xfer_id(xfer), seg->index, wa_xfer_id(xfer), seg->index, seg->isoc_frame_index,
xfer->dto_isoc_frame_index, holding_dto, release_dto); holding_dto, release_dto);
} }
spin_unlock_irqrestore(&xfer->lock, flags); spin_unlock_irqrestore(&xfer->lock, flags);
...@@ -737,8 +737,7 @@ static void wa_seg_dto_cb(struct urb *urb) ...@@ -737,8 +737,7 @@ static void wa_seg_dto_cb(struct urb *urb)
* send the URB and release DTO if we no longer need it. * send the URB and release DTO if we no longer need it.
*/ */
__wa_populate_dto_urb_isoc(xfer, seg, __wa_populate_dto_urb_isoc(xfer, seg,
seg->isoc_frame_offset + seg->isoc_frame_offset + seg->isoc_frame_index);
xfer->dto_isoc_frame_index);
/* resubmit the URB with the next isoc frame. */ /* resubmit the URB with the next isoc frame. */
result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC); 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,12 +1323,12 @@ static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
struct wahc *wa = xfer->wa; struct wahc *wa = xfer->wa;
result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC); result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
seg->isoc_frame_index = 0;
if (result < 0) { if (result < 0) {
pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n", pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
__func__, xfer, seg->index, result); __func__, xfer, seg->index, result);
goto error_iso_pack_desc_submit; goto error_iso_pack_desc_submit;
} }
xfer->dto_isoc_frame_index = 0;
/* /*
* If this segment contains more than one isoc frame, hold * If this segment contains more than one isoc frame, hold
* onto the dto resource until we send all frames. * onto the dto resource until we send all frames.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment