aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/wusbcore
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2014-03-06 13:53:37 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-03-07 15:52:04 -0500
commit86e2864d7e9d429b94624a28ba3f05fc2db89051 (patch)
tree9fc5d8fb13a0c3e7ce84af669e6f7114f76d4d4d /drivers/usb/wusbcore
parent5090ecea133325f762704f00963bca1b024ee691 (diff)
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.h11
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c83
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 {
134 * requests to be concatenated and not sent as separate packets. 134 * requests to be concatenated and not sent as separate packets.
135 */ 135 */
136 WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC = 0x01, 136 WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC = 0x01,
137 /*
138 * The Alereon HWA can be instructed to not send transfer notifications
139 * as an optimization.
140 */
141 WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS = 0x02,
137}; 142};
138 143
144enum wa_vendor_specific_requests {
145 WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C,
146 WA_REQ_ALEREON_FEATURE_SET = 0x01,
147 WA_REQ_ALEREON_FEATURE_CLEAR = 0x00,
148};
139/** 149/**
140 * Instance of a HWA Host Controller 150 * Instance of a HWA Host Controller
141 * 151 *
@@ -234,6 +244,7 @@ struct wahc {
234extern int wa_create(struct wahc *wa, struct usb_interface *iface, 244extern int wa_create(struct wahc *wa, struct usb_interface *iface,
235 kernel_ulong_t); 245 kernel_ulong_t);
236extern void __wa_destroy(struct wahc *wa); 246extern void __wa_destroy(struct wahc *wa);
247extern int wa_dti_start(struct wahc *wa);
237void wa_reset_all(struct wahc *wa); 248void wa_reset_all(struct wahc *wa);
238 249
239 250
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:
2741} 2741}
2742 2742
2743/* 2743/*
2744 * Transfer complete notification 2744 * Initialize the DTI URB for reading transfer result notifications and also
2745 * 2745 * the buffer-in URB, for reading buffers. Then we just submit the DTI URB.
2746 * Called from the notif.c code. We get a notification on EP2 saying
2747 * that some endpoint has some transfer result data available. We are
2748 * about to read it.
2749 *
2750 * To speed up things, we always have a URB reading the DTI URB; we
2751 * don't really set it up and start it until the first xfer complete
2752 * notification arrives, which is what we do here.
2753 *
2754 * Follow up in wa_dti_cb(), as that's where the whole state
2755 * machine starts.
2756 *
2757 * So here we just initialize the DTI URB for reading transfer result
2758 * notifications and also the buffer-in URB, for reading buffers. Then
2759 * we just submit the DTI URB.
2760 *
2761 * @wa shall be referenced
2762 */ 2746 */
2763void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) 2747int wa_dti_start(struct wahc *wa)
2764{ 2748{
2765 int result;
2766 struct device *dev = &wa->usb_iface->dev;
2767 struct wa_notif_xfer *notif_xfer;
2768 const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; 2749 const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
2750 struct device *dev = &wa->usb_iface->dev;
2751 int result = -ENOMEM;
2769 2752
2770 notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr);
2771 BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER);
2772
2773 if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) {
2774 /* FIXME: hardcoded limitation, adapt */
2775 dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n",
2776 notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
2777 goto error;
2778 }
2779 if (wa->dti_urb != NULL) /* DTI URB already started */ 2753 if (wa->dti_urb != NULL) /* DTI URB already started */
2780 goto out; 2754 goto out;
2781 2755
@@ -2786,7 +2760,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
2786 } 2760 }
2787 usb_fill_bulk_urb( 2761 usb_fill_bulk_urb(
2788 wa->dti_urb, wa->usb_dev, 2762 wa->dti_urb, wa->usb_dev,
2789 usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), 2763 usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress),
2790 wa->dti_buf, wa->dti_buf_size, 2764 wa->dti_buf, wa->dti_buf_size,
2791 wa_dti_cb, wa); 2765 wa_dti_cb, wa);
2792 2766
@@ -2797,7 +2771,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
2797 } 2771 }
2798 usb_fill_bulk_urb( 2772 usb_fill_bulk_urb(
2799 wa->buf_in_urb, wa->usb_dev, 2773 wa->buf_in_urb, wa->usb_dev,
2800 usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), 2774 usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress),
2801 NULL, 0, wa_buf_in_cb, wa); 2775 NULL, 0, wa_buf_in_cb, wa);
2802 result = usb_submit_urb(wa->dti_urb, GFP_KERNEL); 2776 result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
2803 if (result < 0) { 2777 if (result < 0) {
@@ -2806,7 +2780,7 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
2806 goto error_dti_urb_submit; 2780 goto error_dti_urb_submit;
2807 } 2781 }
2808out: 2782out:
2809 return; 2783 return 0;
2810 2784
2811error_dti_urb_submit: 2785error_dti_urb_submit:
2812 usb_put_urb(wa->buf_in_urb); 2786 usb_put_urb(wa->buf_in_urb);
@@ -2815,6 +2789,47 @@ error_buf_in_urb_alloc:
2815 usb_put_urb(wa->dti_urb); 2789 usb_put_urb(wa->dti_urb);
2816 wa->dti_urb = NULL; 2790 wa->dti_urb = NULL;
2817error_dti_urb_alloc: 2791error_dti_urb_alloc:
2792 return result;
2793}
2794EXPORT_SYMBOL_GPL(wa_dti_start);
2795/*
2796 * Transfer complete notification
2797 *
2798 * Called from the notif.c code. We get a notification on EP2 saying
2799 * that some endpoint has some transfer result data available. We are
2800 * about to read it.
2801 *
2802 * To speed up things, we always have a URB reading the DTI URB; we
2803 * don't really set it up and start it until the first xfer complete
2804 * notification arrives, which is what we do here.
2805 *
2806 * Follow up in wa_dti_cb(), as that's where the whole state
2807 * machine starts.
2808 *
2809 * @wa shall be referenced
2810 */
2811void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
2812{
2813 struct device *dev = &wa->usb_iface->dev;
2814 struct wa_notif_xfer *notif_xfer;
2815 const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
2816
2817 notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr);
2818 BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER);
2819
2820 if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) {
2821 /* FIXME: hardcoded limitation, adapt */
2822 dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n",
2823 notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
2824 goto error;
2825 }
2826
2827 /* attempt to start the DTI ep processing. */
2828 if (wa_dti_start(wa) < 0)
2829 goto error;
2830
2831 return;
2832
2818error: 2833error:
2819 wa_reset_all(wa); 2834 wa_reset_all(wa);
2820} 2835}