[PATCH 001/001] USB: serial: sierra driver memory reduction

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Subject: [PATCH 001/001] USB: serial: sierra driver memory reduction
From: Elina Pasheva <epasheva@xxxxxxxxxxxxxxxxxx>
This patch deals with reducing the memory footprint for sierra driver.
This optimization is aimed for embedded software customers. 
The interfaces with low memory requirements are assigned less memory 
(in number of urbs) thus reducing the overall memory footprint of the driver.
Applying this patch to the current sierra.c driver in the kernel will make
the source identical with the version available from the sierra wireless 
knowledgebase website. That is why the version number is being changed 
to 1.7.12 as part of this patch.
Signed-off-by: Elina Pasheva <epasheva@xxxxxxxxxxxxxxxxxx>
---

 drivers/usb/serial/sierra.c |   96 +++++++++++++++++++++++++++++-----
 1 file changed, 82 insertions(+), 14 deletions(-)

--- a/drivers/usb/serial/sierra.c	2009-10-08 14:37:01.000000000 -0700
+++ b/drivers/usb/serial/sierra.c	2009-10-08 14:52:39.000000000 -0700
@@ -16,8 +16,9 @@
   Portions based on the option driver by Matthias Urlichs <smurf@xxxxxxxxxxxxxx>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@xxxxxxxxxxxx>
 */
-
-#define DRIVER_VERSION "v.1.3.7"
+/* Uncomment to log function calls */
+/* #define DEBUG */
+#define DRIVER_VERSION "v.1.7.12"
 #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
@@ -33,8 +34,10 @@
 #define SWIMS_USB_REQUEST_SetPower	0x00
 #define SWIMS_USB_REQUEST_SetNmea	0x07
 
-#define N_IN_URB	8
-#define N_OUT_URB	64
+#define N_IN_URB_HM	8
+#define N_OUT_URB_HM	64
+#define N_IN_URB	4
+#define N_OUT_URB	4
 #define IN_BUFLEN	4096
 
 #define MAX_TRANSFER		(PAGE_SIZE - 512)
@@ -124,6 +127,23 @@ static int is_blacklisted(const u8 ifnum
 	return 0;
 }
 
+static int is_himemory(const u8 ifnum,
+				const struct sierra_iface_info *himemorylist)
+{
+	const u8  *info;
+	int i;
+
+	if (himemorylist) {
+		info = himemorylist->ifaceinfo;
+
+		for (i=0; i < himemorylist->infolen; i++) {
+			if (info[i] == ifnum)
+				return 1;
+		}
+	}
+	return 0;
+}
+
 static int sierra_calc_interface(struct usb_serial *serial)
 {
 	int interface;
@@ -186,6 +206,20 @@ static int sierra_probe(struct usb_seria
 	return result;
 }
 
+/* interfaces with higher memory requirements */
+static const u8 hi_memory_typeA_ifaces[] = { 0, 2 };
+static const struct sierra_iface_info typeA_interface_list = {
+	.infolen = ARRAY_SIZE(hi_memory_typeA_ifaces),
+	.ifaceinfo = hi_memory_typeA_ifaces,
+};
+
+static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 };
+static const struct sierra_iface_info typeB_interface_list = {
+	.infolen = ARRAY_SIZE(hi_memory_typeB_ifaces),
+	.ifaceinfo = hi_memory_typeB_ifaces,
+};
+
+/* 'blacklist' of interfaces not served by this driver */
 static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 };
 static const struct sierra_iface_info direct_ip_interface_blacklist = {
 	.infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces),
@@ -286,8 +320,10 @@ struct sierra_port_private {
 	struct usb_anchor active;
 	struct usb_anchor delayed;
 
+	int num_out_urbs;
+	int num_in_urbs;
 	/* Input endpoints and buffers for this port */
-	struct urb *in_urbs[N_IN_URB];
+	struct urb *in_urbs[N_IN_URB_HM];
 
 	/* Settings for the port */
 	int rts_state;	/* Handshaking pins (outputs) */
@@ -456,7 +492,7 @@ static int sierra_write(struct tty_struc
 	spin_lock_irqsave(&portdata->lock, flags);
 	dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__,
 		portdata->outstanding_urbs);
-	if (portdata->outstanding_urbs > N_OUT_URB) {
+	if (portdata->outstanding_urbs > portdata->num_out_urbs) {
 		spin_unlock_irqrestore(&portdata->lock, flags);
 		dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
 		return 0;
@@ -661,7 +697,9 @@ static int sierra_write_room(struct tty_
 	/* try to give a good number back based on if we have any free urbs at
 	 * this point in time */
 	spin_lock_irqsave(&portdata->lock, flags);
-	if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) {
+	dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, 
+		portdata->outstanding_urbs);
+	if (portdata->outstanding_urbs > (portdata->num_out_urbs * 2) / 3) {
 		spin_unlock_irqrestore(&portdata->lock, flags);
 		dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
 		return 0;
@@ -676,7 +714,7 @@ static void sierra_stop_rx_urbs(struct u
 	int i;
 	struct sierra_port_private *portdata = usb_get_serial_port_data(port);
 
-	for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++)
+	for (i = 0; i < portdata->num_in_urbs; i++)
 		usb_kill_urb(portdata->in_urbs[i]);
 
 	usb_kill_urb(port->interrupt_in_urb);
@@ -691,7 +729,7 @@ static int sierra_submit_rx_urbs(struct 
 	struct sierra_port_private *portdata = usb_get_serial_port_data(port);
 
 	ok_cnt = 0;
-	for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) {
+	for (i = 0; i < portdata->num_in_urbs; i++) {
 		urb = portdata->in_urbs[i];
 		if (!urb)
 			continue;
@@ -784,7 +822,7 @@ static void sierra_close(struct usb_seri
 		/* Stop reading urbs */
 		sierra_stop_rx_urbs(port);
 		/* .. and release them */
-		for (i = 0; i < N_IN_URB; i++) {
+		for (i = 0; i < portdata->num_in_urbs; i++) {
 			sierra_release_urb(portdata->in_urbs[i]);
 			portdata->in_urbs[i] = NULL;
 		}
@@ -813,7 +851,7 @@ static int sierra_open(struct tty_struct
 
 
 	endpoint = port->bulk_in_endpointAddress;
-	for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) {
+	for (i = 0; i < portdata->num_in_urbs; i++) {
 		urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port,
 					IN_BUFLEN, GFP_KERNEL,
 					sierra_indat_callback);
@@ -825,6 +863,8 @@ static int sierra_open(struct tty_struct
 
 	err = sierra_submit_rx_urbs(port, GFP_KERNEL);
 	if (err) {
+		/* restore balance for autopm */
+		usb_autopm_put_interface(serial->interface);
 		/* get rid of everything as in close */
 		sierra_close(port);
 		return err;
@@ -862,7 +902,9 @@ static int sierra_startup(struct usb_ser
 {
 	struct usb_serial_port *port;
 	struct sierra_port_private *portdata;
+	struct sierra_iface_info *himemoryp = NULL;
 	int i;
+	u8 ifnum;
 
 	dev_dbg(&serial->dev->dev, "%s\n", __func__);
 
@@ -886,6 +928,33 @@ static int sierra_startup(struct usb_ser
 		spin_lock_init(&portdata->lock);
 		init_usb_anchor(&portdata->active);
 		init_usb_anchor(&portdata->delayed);
+		ifnum = i;
+		/* Assume low memory requirements */
+		portdata->num_out_urbs = N_OUT_URB;
+		portdata->num_in_urbs  = N_IN_URB;
+
+		/* Determine actual memory requirements */
+		if (serial->num_ports == 1) {
+			/* Get interface number for composite device */
+			ifnum = sierra_calc_interface(serial);
+			himemoryp =
+			    (struct sierra_iface_info *)&typeB_interface_list;
+			if (is_himemory(ifnum, himemoryp)) {
+				portdata->num_out_urbs = N_OUT_URB_HM;
+				portdata->num_in_urbs  = N_IN_URB_HM;
+			}
+		}
+		else {
+			himemoryp =
+			    (struct sierra_iface_info *)&typeA_interface_list;
+			if (is_himemory(i, himemoryp)) {
+				portdata->num_out_urbs = N_OUT_URB_HM;
+				portdata->num_in_urbs  = N_IN_URB_HM;
+			}
+		}
+		dev_dbg(&serial->dev->dev, 
+			"Memory usage (urbs) interface #%d, in=%d, out=%d\n",
+			ifnum,portdata->num_in_urbs, portdata->num_out_urbs );
 		/* Set the port private data pointer */
 		usb_set_serial_port_data(port, portdata);
 	}
@@ -915,7 +984,7 @@ static void sierra_release(struct usb_se
 #ifdef CONFIG_PM
 static void stop_read_write_urbs(struct usb_serial *serial)
 {
-	int i, j;
+	int i;
 	struct usb_serial_port *port;
 	struct sierra_port_private *portdata;
 
@@ -923,8 +992,7 @@ static void stop_read_write_urbs(struct 
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		portdata = usb_get_serial_port_data(port);
-		for (j = 0; j < N_IN_URB; j++)
-			usb_kill_urb(portdata->in_urbs[j]);
+		sierra_stop_rx_urbs(port);
 		usb_kill_anchored_urbs(&portdata->active);
 	}
 }


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux