diff options
author | Thomas Pugliese <thomas.pugliese@gmail.com> | 2014-03-06 19:53:37 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-03-07 21:52:04 +0100 |
commit | 86e2864d7e9d429b94624a28ba3f05fc2db89051 (patch) | |
tree | 9fc5d8fb13a0c3e7ce84af669e6f7114f76d4d4d /drivers/usb/wusbcore | |
parent | usb: wusbcore: don't mark WA_SEG_DTI_PENDING segs as done in urb_dequeue (diff) | |
download | linux-86e2864d7e9d429b94624a28ba3f05fc2db89051.tar.xz linux-86e2864d7e9d429b94624a28ba3f05fc2db89051.zip |
usb: wusbcore: disable transfer notifications for Alereon HWAs
The HWA driver does not do anything with transfer notifications after
receiving the first one and the Alereon HWA allows them to be disabled
as a performance optimization. This patch sends a vendor specific
command to the Alereon HWA on startup to disable transfer notifications.
If the command is successful, the DTI system is started immediately
since that would normally be started upon the first reception of a
transfer notification which will no longer be sent.
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-hc.h | 11 | ||||
-rw-r--r-- | drivers/usb/wusbcore/wa-xfer.c | 83 |
2 files changed, 60 insertions, 34 deletions
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h index a2ef84b8397e..7510960588dc 100644 --- a/drivers/usb/wusbcore/wa-hc.h +++ b/drivers/usb/wusbcore/wa-hc.h @@ -134,8 +134,18 @@ enum wa_quirks { * requests to be concatenated and not sent as separate packets. */ WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC = 0x01, + /* + * The Alereon HWA can be instructed to not send transfer notifications + * as an optimization. + */ + WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS = 0x02, }; +enum wa_vendor_specific_requests { + WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C, + WA_REQ_ALEREON_FEATURE_SET = 0x01, + WA_REQ_ALEREON_FEATURE_CLEAR = 0x00, +}; /** * Instance of a HWA Host Controller * @@ -234,6 +244,7 @@ struct wahc { extern int wa_create(struct wahc *wa, struct usb_interface *iface, kernel_ulong_t); extern void __wa_destroy(struct wahc *wa); +extern int wa_dti_start(struct wahc *wa); void wa_reset_all(struct wahc *wa); diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index cf7c95ceebe0..52c7259705e6 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -2741,41 +2741,15 @@ out: } /* - * Transfer complete notification - * - * Called from the notif.c code. We get a notification on EP2 saying - * that some endpoint has some transfer result data available. We are - * about to read it. - * - * To speed up things, we always have a URB reading the DTI URB; we - * don't really set it up and start it until the first xfer complete - * notification arrives, which is what we do here. - * - * Follow up in wa_dti_cb(), as that's where the whole state - * machine starts. - * - * So here we just initialize the DTI URB for reading transfer result - * notifications and also the buffer-in URB, for reading buffers. Then - * we just submit the DTI URB. - * - * @wa shall be referenced + * Initialize the DTI URB for reading transfer result notifications and also + * the buffer-in URB, for reading buffers. Then we just submit the DTI URB. */ -void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) +int wa_dti_start(struct wahc *wa) { - int result; - struct device *dev = &wa->usb_iface->dev; - struct wa_notif_xfer *notif_xfer; const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; + struct device *dev = &wa->usb_iface->dev; + int result = -ENOMEM; - notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr); - BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER); - - if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) { - /* FIXME: hardcoded limitation, adapt */ - dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n", - notif_xfer->bEndpoint, dti_epd->bEndpointAddress); - goto error; - } if (wa->dti_urb != NULL) /* DTI URB already started */ goto out; @@ -2786,7 +2760,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) } usb_fill_bulk_urb( wa->dti_urb, wa->usb_dev, - usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), + usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress), wa->dti_buf, wa->dti_buf_size, wa_dti_cb, wa); @@ -2797,7 +2771,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) } usb_fill_bulk_urb( wa->buf_in_urb, wa->usb_dev, - usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), + usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress), NULL, 0, wa_buf_in_cb, wa); result = usb_submit_urb(wa->dti_urb, GFP_KERNEL); if (result < 0) { @@ -2806,7 +2780,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) goto error_dti_urb_submit; } out: - return; + return 0; error_dti_urb_submit: usb_put_urb(wa->buf_in_urb); @@ -2815,6 +2789,47 @@ error_buf_in_urb_alloc: usb_put_urb(wa->dti_urb); wa->dti_urb = NULL; error_dti_urb_alloc: + return result; +} +EXPORT_SYMBOL_GPL(wa_dti_start); +/* + * Transfer complete notification + * + * Called from the notif.c code. We get a notification on EP2 saying + * that some endpoint has some transfer result data available. We are + * about to read it. + * + * To speed up things, we always have a URB reading the DTI URB; we + * don't really set it up and start it until the first xfer complete + * notification arrives, which is what we do here. + * + * Follow up in wa_dti_cb(), as that's where the whole state + * machine starts. + * + * @wa shall be referenced + */ +void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) +{ + struct device *dev = &wa->usb_iface->dev; + struct wa_notif_xfer *notif_xfer; + const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; + + notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr); + BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER); + + if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) { + /* FIXME: hardcoded limitation, adapt */ + dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n", + notif_xfer->bEndpoint, dti_epd->bEndpointAddress); + goto error; + } + + /* attempt to start the DTI ep processing. */ + if (wa_dti_start(wa) < 0) + goto error; + + return; + error: wa_reset_all(wa); } |