diff options
author | Thomas Pugliese <thomas.pugliese@gmail.com> | 2013-12-09 15:15:14 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-12-09 16:29:21 -0500 |
commit | ea1af42d3d4da73c9d75984f24e569515261b3fd (patch) | |
tree | 630fe9460c6de8ea29ca83248777dfe145df7408 /drivers/usb/wusbcore | |
parent | 7b3e3740f2d0faca9351db88974be534009a3d8d (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.c | 21 |
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. |