aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2013-10-23 15:44:28 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-29 19:44:49 -0400
commitf07ddb9ef5c25c1044ab5b6509241320fb5e831a (patch)
tree6f7bb348ad03cc4e7e52634de48deaeecd468ae2
parent2101242cef04991a580c3debb46972dbfaaaf138 (diff)
usb: wusbcore: add a quirk for Alereon HWA device isoc behavior
Add a quirk for Alereon HWA devices to concatenate the frames of isoc transfer requests. Signed-off-by: Thomas Pugliese <thomas.pugliese@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/hwa-hc.c13
-rw-r--r--drivers/usb/wusbcore/wa-hc.c4
-rw-r--r--drivers/usb/wusbcore/wa-hc.h13
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c49
4 files changed, 62 insertions, 17 deletions
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index e5fb3cfd57a9..ada0a52797b1 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -679,7 +679,8 @@ static void hwahc_security_release(struct hwahc *hwahc)
679 /* nothing to do here so far... */ 679 /* nothing to do here so far... */
680} 680}
681 681
682static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) 682static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface,
683 kernel_ulong_t quirks)
683{ 684{
684 int result; 685 int result;
685 struct device *dev = &iface->dev; 686 struct device *dev = &iface->dev;
@@ -724,7 +725,7 @@ static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface)
724 dev_err(dev, "Can't create WUSB HC structures: %d\n", result); 725 dev_err(dev, "Can't create WUSB HC structures: %d\n", result);
725 goto error_wusbhc_create; 726 goto error_wusbhc_create;
726 } 727 }
727 result = wa_create(&hwahc->wa, iface); 728 result = wa_create(&hwahc->wa, iface, quirks);
728 if (result < 0) 729 if (result < 0)
729 goto error_wa_create; 730 goto error_wa_create;
730 return 0; 731 return 0;
@@ -780,7 +781,7 @@ static int hwahc_probe(struct usb_interface *usb_iface,
780 wusbhc = usb_hcd_to_wusbhc(usb_hcd); 781 wusbhc = usb_hcd_to_wusbhc(usb_hcd);
781 hwahc = container_of(wusbhc, struct hwahc, wusbhc); 782 hwahc = container_of(wusbhc, struct hwahc, wusbhc);
782 hwahc_init(hwahc); 783 hwahc_init(hwahc);
783 result = hwahc_create(hwahc, usb_iface); 784 result = hwahc_create(hwahc, usb_iface, id->driver_info);
784 if (result < 0) { 785 if (result < 0) {
785 dev_err(dev, "Cannot initialize internals: %d\n", result); 786 dev_err(dev, "Cannot initialize internals: %d\n", result);
786 goto error_hwahc_create; 787 goto error_hwahc_create;
@@ -824,6 +825,12 @@ static void hwahc_disconnect(struct usb_interface *usb_iface)
824} 825}
825 826
826static struct usb_device_id hwahc_id_table[] = { 827static struct usb_device_id hwahc_id_table[] = {
828 /* Alereon 5310 */
829 { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),
830 .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC },
831 /* Alereon 5611 */
832 { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01),
833 .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC },
827 /* FIXME: use class labels for this */ 834 /* FIXME: use class labels for this */
828 { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), }, 835 { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
829 {}, 836 {},
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
index 6c09b0e4672b..368360f9a93a 100644
--- a/drivers/usb/wusbcore/wa-hc.c
+++ b/drivers/usb/wusbcore/wa-hc.c
@@ -33,7 +33,8 @@
33 * wa->usb_dev and wa->usb_iface initialized and refcounted, 33 * wa->usb_dev and wa->usb_iface initialized and refcounted,
34 * wa->wa_descr initialized. 34 * wa->wa_descr initialized.
35 */ 35 */
36int wa_create(struct wahc *wa, struct usb_interface *iface) 36int wa_create(struct wahc *wa, struct usb_interface *iface,
37 kernel_ulong_t quirks)
37{ 38{
38 int result; 39 int result;
39 struct device *dev = &iface->dev; 40 struct device *dev = &iface->dev;
@@ -41,6 +42,7 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)
41 result = wa_rpipes_create(wa); 42 result = wa_rpipes_create(wa);
42 if (result < 0) 43 if (result < 0)
43 goto error_rpipes_create; 44 goto error_rpipes_create;
45 wa->quirks = quirks;
44 /* Fill up Data Transfer EP pointers */ 46 /* Fill up Data Transfer EP pointers */
45 wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc; 47 wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
46 wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc; 48 wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h
index 41afaa6d01d2..e614f02f0cf2 100644
--- a/drivers/usb/wusbcore/wa-hc.h
+++ b/drivers/usb/wusbcore/wa-hc.h
@@ -128,6 +128,14 @@ enum wa_dti_state {
128 WA_DTI_ISOC_PACKET_STATUS_PENDING 128 WA_DTI_ISOC_PACKET_STATUS_PENDING
129}; 129};
130 130
131enum wa_quirks {
132 /*
133 * The Alereon HWA expects the data frames in isochronous transfer
134 * requests to be concatenated and not sent as separate packets.
135 */
136 WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC = 0x01,
137};
138
131/** 139/**
132 * Instance of a HWA Host Controller 140 * Instance of a HWA Host Controller
133 * 141 *
@@ -218,10 +226,13 @@ struct wahc {
218 struct work_struct xfer_enqueue_work; 226 struct work_struct xfer_enqueue_work;
219 struct work_struct xfer_error_work; 227 struct work_struct xfer_error_work;
220 atomic_t xfer_id_count; 228 atomic_t xfer_id_count;
229
230 kernel_ulong_t quirks;
221}; 231};
222 232
223 233
224extern int wa_create(struct wahc *wa, struct usb_interface *iface); 234extern int wa_create(struct wahc *wa, struct usb_interface *iface,
235 kernel_ulong_t);
225extern void __wa_destroy(struct wahc *wa); 236extern void __wa_destroy(struct wahc *wa);
226void wa_reset_all(struct wahc *wa); 237void wa_reset_all(struct wahc *wa);
227 238
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 9325d27453c4..090ac308c756 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -479,13 +479,29 @@ static int __wa_seg_calculate_isoc_frame_count(struct wa_xfer *xfer,
479{ 479{
480 int segment_size = 0, frame_count = 0; 480 int segment_size = 0, frame_count = 0;
481 int index = isoc_frame_offset; 481 int index = isoc_frame_offset;
482 struct usb_iso_packet_descriptor *iso_frame_desc =
483 xfer->urb->iso_frame_desc;
482 484
483 while ((index < xfer->urb->number_of_packets) 485 while ((index < xfer->urb->number_of_packets)
484 && ((segment_size + xfer->urb->iso_frame_desc[index].length) 486 && ((segment_size + iso_frame_desc[index].length)
485 <= xfer->seg_size)) { 487 <= xfer->seg_size)) {
488 /*
489 * For Alereon HWA devices, only include an isoc frame in a
490 * segment if it is physically contiguous with the previous
491 * frame. This is required because those devices expect
492 * the isoc frames to be sent as a single USB transaction as
493 * opposed to one transaction per frame with standard HWA.
494 */
495 if ((xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
496 && (index > isoc_frame_offset)
497 && ((iso_frame_desc[index - 1].offset +
498 iso_frame_desc[index - 1].length) !=
499 iso_frame_desc[index].offset))
500 break;
501
486 /* this frame fits. count it. */ 502 /* this frame fits. count it. */
487 ++frame_count; 503 ++frame_count;
488 segment_size += xfer->urb->iso_frame_desc[index].length; 504 segment_size += iso_frame_desc[index].length;
489 505
490 /* move to the next isoc frame. */ 506 /* move to the next isoc frame. */
491 ++index; 507 ++index;
@@ -681,7 +697,11 @@ static void wa_seg_dto_cb(struct urb *urb)
681 wa = xfer->wa; 697 wa = xfer->wa;
682 dev = &wa->usb_iface->dev; 698 dev = &wa->usb_iface->dev;
683 if (usb_pipeisoc(xfer->urb->pipe)) { 699 if (usb_pipeisoc(xfer->urb->pipe)) {
684 xfer->dto_isoc_frame_index += 1; 700 /* Alereon HWA sends all isoc frames in a single transfer. */
701 if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
702 xfer->dto_isoc_frame_index += seg->isoc_frame_count;
703 else
704 xfer->dto_isoc_frame_index += 1;
685 if (xfer->dto_isoc_frame_index < seg->isoc_frame_count) { 705 if (xfer->dto_isoc_frame_index < seg->isoc_frame_count) {
686 data_send_done = 0; 706 data_send_done = 0;
687 holding_dto = 1; /* checked in error cases. */ 707 holding_dto = 1; /* checked in error cases. */
@@ -1007,17 +1027,18 @@ static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
1007static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer, 1027static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
1008 struct wa_seg *seg, int curr_iso_frame) 1028 struct wa_seg *seg, int curr_iso_frame)
1009{ 1029{
1010 /*
1011 * dto urb buffer address and size pulled from
1012 * iso_frame_desc.
1013 */
1014 seg->dto_urb->transfer_dma = xfer->urb->transfer_dma +
1015 xfer->urb->iso_frame_desc[curr_iso_frame].offset;
1016 seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1030 seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1017 seg->dto_urb->sg = NULL; 1031 seg->dto_urb->sg = NULL;
1018 seg->dto_urb->num_sgs = 0; 1032 seg->dto_urb->num_sgs = 0;
1019 seg->dto_urb->transfer_buffer_length = 1033 /* dto urb buffer address pulled from iso_frame_desc. */
1020 xfer->urb->iso_frame_desc[curr_iso_frame].length; 1034 seg->dto_urb->transfer_dma = xfer->urb->transfer_dma +
1035 xfer->urb->iso_frame_desc[curr_iso_frame].offset;
1036 /* The Alereon HWA sends a single URB with all isoc segs. */
1037 if (xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
1038 seg->dto_urb->transfer_buffer_length = seg->isoc_size;
1039 else
1040 seg->dto_urb->transfer_buffer_length =
1041 xfer->urb->iso_frame_desc[curr_iso_frame].length;
1021} 1042}
1022 1043
1023/* 1044/*
@@ -1298,6 +1319,8 @@ static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
1298 } 1319 }
1299 /* submit the isoc packet descriptor if present. */ 1320 /* submit the isoc packet descriptor if present. */
1300 if (seg->isoc_pack_desc_urb) { 1321 if (seg->isoc_pack_desc_urb) {
1322 struct wahc *wa = xfer->wa;
1323
1301 result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC); 1324 result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
1302 if (result < 0) { 1325 if (result < 0) {
1303 pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n", 1326 pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
@@ -1308,8 +1331,10 @@ static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
1308 /* 1331 /*
1309 * If this segment contains more than one isoc frame, hold 1332 * If this segment contains more than one isoc frame, hold
1310 * onto the dto resource until we send all frames. 1333 * onto the dto resource until we send all frames.
1334 * Only applies to non-Alereon devices.
1311 */ 1335 */
1312 if (seg->isoc_frame_count > 1) 1336 if (((wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) == 0)
1337 && (seg->isoc_frame_count > 1))
1313 *dto_done = 0; 1338 *dto_done = 0;
1314 } 1339 }
1315 /* submit the out data if this is an out request. */ 1340 /* submit the out data if this is an out request. */