aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/sierra.c
diff options
context:
space:
mode:
authorElina Pasheva <epasheva@sierrawireless.com>2009-11-04 13:25:48 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:55:19 -0500
commit3a2b808e95287c8235e25a833fda3dad3e9853ef (patch)
tree5cb2af791049ef8c7c949d2e0027863dffdaea00 /drivers/usb/serial/sierra.c
parentb97503ffa79f0a4aa13c7cd8b449b98d3077c78f (diff)
USB: serial: sierra driver memory reduction
This patch deals with reducing the memory footprint for sierra driver. This optimization is aimed for embedded software customers. Some sierra modems can expose upwards of 7 USB interfaces, each possibly offering different services. In general, interfaces used for the exchange of wireless data require much higher throughput, hence require more memory (i.e. more URBs) than lower performance interfaces. URBs used for the IN direction are pre-allocated by the driver and this patch introduces a way to configure the number of IN URBs allocated on a per-interface basis. Interfaces with lower throughput requirements receive fewer URBs, thereby reducing the RAM memory consumed by the driver. NOTE1: This driver has always pre-allocated URBs for the IN direction. NOTE2: The number of URBs pre-allocated for the low-performance interfaces has already been extensively tested in previous versions of this driver. We also added the capability to log function calls by adding DEBUG flag. Please note that this flag is commented out because this is the default state for it. Signed-off-by: Elina Pasheva <epasheva@sierrawireless.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/sierra.c')
-rw-r--r--drivers/usb/serial/sierra.c89
1 files changed, 77 insertions, 12 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 5019325ba25d..c5c41aed106d 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -16,8 +16,9 @@
16 Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> 16 Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
17 Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> 17 Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
18*/ 18*/
19 19/* Uncomment to log function calls */
20#define DRIVER_VERSION "v.1.3.8" 20/* #define DEBUG */
21#define DRIVER_VERSION "v.1.7.16"
21#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" 22#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
22#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" 23#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
23 24
@@ -33,8 +34,10 @@
33#define SWIMS_USB_REQUEST_SetPower 0x00 34#define SWIMS_USB_REQUEST_SetPower 0x00
34#define SWIMS_USB_REQUEST_SetNmea 0x07 35#define SWIMS_USB_REQUEST_SetNmea 0x07
35 36
36#define N_IN_URB 8 37#define N_IN_URB_HM 8
37#define N_OUT_URB 64 38#define N_OUT_URB_HM 64
39#define N_IN_URB 4
40#define N_OUT_URB 4
38#define IN_BUFLEN 4096 41#define IN_BUFLEN 4096
39 42
40#define MAX_TRANSFER (PAGE_SIZE - 512) 43#define MAX_TRANSFER (PAGE_SIZE - 512)
@@ -124,6 +127,23 @@ static int is_blacklisted(const u8 ifnum,
124 return 0; 127 return 0;
125} 128}
126 129
130static int is_himemory(const u8 ifnum,
131 const struct sierra_iface_info *himemorylist)
132{
133 const u8 *info;
134 int i;
135
136 if (himemorylist) {
137 info = himemorylist->ifaceinfo;
138
139 for (i=0; i < himemorylist->infolen; i++) {
140 if (info[i] == ifnum)
141 return 1;
142 }
143 }
144 return 0;
145}
146
127static int sierra_calc_interface(struct usb_serial *serial) 147static int sierra_calc_interface(struct usb_serial *serial)
128{ 148{
129 int interface; 149 int interface;
@@ -186,6 +206,20 @@ static int sierra_probe(struct usb_serial *serial,
186 return result; 206 return result;
187} 207}
188 208
209/* interfaces with higher memory requirements */
210static const u8 hi_memory_typeA_ifaces[] = { 0, 2 };
211static const struct sierra_iface_info typeA_interface_list = {
212 .infolen = ARRAY_SIZE(hi_memory_typeA_ifaces),
213 .ifaceinfo = hi_memory_typeA_ifaces,
214};
215
216static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 };
217static const struct sierra_iface_info typeB_interface_list = {
218 .infolen = ARRAY_SIZE(hi_memory_typeB_ifaces),
219 .ifaceinfo = hi_memory_typeB_ifaces,
220};
221
222/* 'blacklist' of interfaces not served by this driver */
189static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 }; 223static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 };
190static const struct sierra_iface_info direct_ip_interface_blacklist = { 224static const struct sierra_iface_info direct_ip_interface_blacklist = {
191 .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), 225 .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces),
@@ -286,8 +320,10 @@ struct sierra_port_private {
286 struct usb_anchor active; 320 struct usb_anchor active;
287 struct usb_anchor delayed; 321 struct usb_anchor delayed;
288 322
323 int num_out_urbs;
324 int num_in_urbs;
289 /* Input endpoints and buffers for this port */ 325 /* Input endpoints and buffers for this port */
290 struct urb *in_urbs[N_IN_URB]; 326 struct urb *in_urbs[N_IN_URB_HM];
291 327
292 /* Settings for the port */ 328 /* Settings for the port */
293 int rts_state; /* Handshaking pins (outputs) */ 329 int rts_state; /* Handshaking pins (outputs) */
@@ -460,7 +496,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
460 spin_lock_irqsave(&portdata->lock, flags); 496 spin_lock_irqsave(&portdata->lock, flags);
461 dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, 497 dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__,
462 portdata->outstanding_urbs); 498 portdata->outstanding_urbs);
463 if (portdata->outstanding_urbs > N_OUT_URB) { 499 if (portdata->outstanding_urbs > portdata->num_out_urbs) {
464 spin_unlock_irqrestore(&portdata->lock, flags); 500 spin_unlock_irqrestore(&portdata->lock, flags);
465 dev_dbg(&port->dev, "%s - write limit hit\n", __func__); 501 dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
466 return 0; 502 return 0;
@@ -665,7 +701,7 @@ static int sierra_write_room(struct tty_struct *tty)
665 /* try to give a good number back based on if we have any free urbs at 701 /* try to give a good number back based on if we have any free urbs at
666 * this point in time */ 702 * this point in time */
667 spin_lock_irqsave(&portdata->lock, flags); 703 spin_lock_irqsave(&portdata->lock, flags);
668 if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) { 704 if (portdata->outstanding_urbs > (portdata->num_out_urbs * 2) / 3) {
669 spin_unlock_irqrestore(&portdata->lock, flags); 705 spin_unlock_irqrestore(&portdata->lock, flags);
670 dev_dbg(&port->dev, "%s - write limit hit\n", __func__); 706 dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
671 return 0; 707 return 0;
@@ -680,7 +716,7 @@ static void sierra_stop_rx_urbs(struct usb_serial_port *port)
680 int i; 716 int i;
681 struct sierra_port_private *portdata = usb_get_serial_port_data(port); 717 struct sierra_port_private *portdata = usb_get_serial_port_data(port);
682 718
683 for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) 719 for (i = 0; i < portdata->num_in_urbs; i++)
684 usb_kill_urb(portdata->in_urbs[i]); 720 usb_kill_urb(portdata->in_urbs[i]);
685 721
686 usb_kill_urb(port->interrupt_in_urb); 722 usb_kill_urb(port->interrupt_in_urb);
@@ -695,7 +731,7 @@ static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags)
695 struct sierra_port_private *portdata = usb_get_serial_port_data(port); 731 struct sierra_port_private *portdata = usb_get_serial_port_data(port);
696 732
697 ok_cnt = 0; 733 ok_cnt = 0;
698 for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { 734 for (i = 0; i < portdata->num_in_urbs; i++) {
699 urb = portdata->in_urbs[i]; 735 urb = portdata->in_urbs[i];
700 if (!urb) 736 if (!urb)
701 continue; 737 continue;
@@ -791,7 +827,7 @@ static void sierra_close(struct usb_serial_port *port)
791 /* Stop reading urbs */ 827 /* Stop reading urbs */
792 sierra_stop_rx_urbs(port); 828 sierra_stop_rx_urbs(port);
793 /* .. and release them */ 829 /* .. and release them */
794 for (i = 0; i < N_IN_URB; i++) { 830 for (i = 0; i < portdata->num_in_urbs; i++) {
795 sierra_release_urb(portdata->in_urbs[i]); 831 sierra_release_urb(portdata->in_urbs[i]);
796 portdata->in_urbs[i] = NULL; 832 portdata->in_urbs[i] = NULL;
797 } 833 }
@@ -818,7 +854,7 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
818 854
819 855
820 endpoint = port->bulk_in_endpointAddress; 856 endpoint = port->bulk_in_endpointAddress;
821 for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { 857 for (i = 0; i < portdata->num_in_urbs; i++) {
822 urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, 858 urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port,
823 IN_BUFLEN, GFP_KERNEL, 859 IN_BUFLEN, GFP_KERNEL,
824 sierra_indat_callback); 860 sierra_indat_callback);
@@ -869,7 +905,9 @@ static int sierra_startup(struct usb_serial *serial)
869{ 905{
870 struct usb_serial_port *port; 906 struct usb_serial_port *port;
871 struct sierra_port_private *portdata; 907 struct sierra_port_private *portdata;
908 struct sierra_iface_info *himemoryp = NULL;
872 int i; 909 int i;
910 u8 ifnum;
873 911
874 dev_dbg(&serial->dev->dev, "%s\n", __func__); 912 dev_dbg(&serial->dev->dev, "%s\n", __func__);
875 913
@@ -886,13 +924,40 @@ static int sierra_startup(struct usb_serial *serial)
886 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); 924 portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
887 if (!portdata) { 925 if (!portdata) {
888 dev_dbg(&port->dev, "%s: kmalloc for " 926 dev_dbg(&port->dev, "%s: kmalloc for "
889 "sierra_port_private (%d) failed!.\n", 927 "sierra_port_private (%d) failed!\n",
890 __func__, i); 928 __func__, i);
891 return -ENOMEM; 929 return -ENOMEM;
892 } 930 }
893 spin_lock_init(&portdata->lock); 931 spin_lock_init(&portdata->lock);
894 init_usb_anchor(&portdata->active); 932 init_usb_anchor(&portdata->active);
895 init_usb_anchor(&portdata->delayed); 933 init_usb_anchor(&portdata->delayed);
934 ifnum = i;
935 /* Assume low memory requirements */
936 portdata->num_out_urbs = N_OUT_URB;
937 portdata->num_in_urbs = N_IN_URB;
938
939 /* Determine actual memory requirements */
940 if (serial->num_ports == 1) {
941 /* Get interface number for composite device */
942 ifnum = sierra_calc_interface(serial);
943 himemoryp =
944 (struct sierra_iface_info *)&typeB_interface_list;
945 if (is_himemory(ifnum, himemoryp)) {
946 portdata->num_out_urbs = N_OUT_URB_HM;
947 portdata->num_in_urbs = N_IN_URB_HM;
948 }
949 }
950 else {
951 himemoryp =
952 (struct sierra_iface_info *)&typeA_interface_list;
953 if (is_himemory(i, himemoryp)) {
954 portdata->num_out_urbs = N_OUT_URB_HM;
955 portdata->num_in_urbs = N_IN_URB_HM;
956 }
957 }
958 dev_dbg(&serial->dev->dev,
959 "Memory usage (urbs) interface #%d, in=%d, out=%d\n",
960 ifnum,portdata->num_in_urbs, portdata->num_out_urbs );
896 /* Set the port private data pointer */ 961 /* Set the port private data pointer */
897 usb_set_serial_port_data(port, portdata); 962 usb_set_serial_port_data(port, portdata);
898 } 963 }