usb: serial: baseband: buffer allocations at init
Vinayak Pane [Wed, 21 Mar 2012 22:06:43 +0000 (15:06 -0700)]
The usb transaction buffers are allocated in module init.
In device open, close and disconnect the buffers will not be
freed. Instead they will be reused to avoid allocation failure
in low-mem conditions.

The usb driver register moved to init so that rmmod and
insmod is not required.

Bug 956211

Signed-off-by: Vinayak Pane <vpane@nvidia.com>
Reviewed-on: http://git-master/r/109935
(cherry picked from commit a4e8219a86f80fd06aaaae2c40a657098d5dcfa5)

Change-Id: Id88cfe3b0a75cb2e6f39176b5297f81f4f9e978b
Reviewed-on: http://git-master/r/115609
Tested-by: Vinayak Pane <vpane@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Steve Lin <stlin@nvidia.com>

drivers/usb/serial/baseband_usb_chr.c

index 96db927..c4eda3f 100644 (file)
@@ -74,6 +74,13 @@ static struct workqueue_struct *chr_ipc_wq;
 
 static atomic_t g_rx_count = ATOMIC_INIT(0);
 
+struct usb_chr_resource {
+       unsigned char *ipc_rx;
+       unsigned char *ipc_tx;
+       unsigned char *rx_buf;
+};
+static struct usb_chr_resource usb_chr_res;
+
 /* baseband ipc functions */
 
 static void baseband_ipc_dump(const char *prefix, unsigned long int offset,
@@ -521,9 +528,7 @@ static void baseband_ipc_close(struct baseband_ipc *ipc)
        memset(&ipc->rx.wait, 0, sizeof(ipc->rx.wait));
 
        /* destroy data buffers */
-       kfree(ipc->ipc_tx);
        ipc->ipc_tx = (unsigned char *) 0;
-       kfree(ipc->ipc_rx);
        ipc->ipc_rx = (unsigned char *) 0;
        list_for_each_entry_safe(ipc_buf, ipc_buf_next, &ipc->tx_free.buf, list)
        {
@@ -601,16 +606,14 @@ static struct baseband_ipc *baseband_ipc_open(work_func_t work_func,
                        ipc_buf);
                list_add_tail(&ipc_buf->list, &ipc->tx_free.buf);
        }
-       ipc->ipc_rx = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+       ipc->ipc_rx = usb_chr_res.ipc_rx;
        if (!ipc->ipc_rx) {
-               pr_err("baseband_ipc_open - "
-                       "cannot allocate ipc->ipc_rx\n");
+               pr_err("%s: cannot find ipc->ipc_rx\n", __func__);
                goto error_exit;
        }
-       ipc->ipc_tx = kmalloc(USB_CHR_TX_BUFSIZ, GFP_KERNEL);
+       ipc->ipc_tx = usb_chr_res.ipc_tx;
        if (!ipc->ipc_tx) {
-               pr_err("baseband_ipc_open - "
-                       "cannot allocate ipc->ipc_tx\n");
+               pr_err("%s: cannot find ipc->ipc_tx\n", __func__);
                goto error_exit;
        }
 
@@ -867,6 +870,7 @@ static void baseband_usb_driver_disconnect(struct usb_interface *intf)
                        && baseband_usb_chr->ipc->workqueue)
                        flush_workqueue(baseband_usb_chr->ipc->workqueue);
                usb_device_connection = false;
+               probe_usb_intf = NULL;
        }
        pr_debug("%s(%d) }\n", __func__, __LINE__);
 }
@@ -956,7 +960,6 @@ static void baseband_usb_close(struct baseband_usb *usb)
                usb_kill_urb(usb->usb.rx_urb);
                if (usb->usb.rx_urb->transfer_buffer) {
                        pr_debug("%s: free rx urb transfer buffer\n", __func__);
-                       kfree(usb->usb.rx_urb->transfer_buffer);
                        usb->usb.rx_urb->transfer_buffer = (void *) 0;
                }
        }
@@ -966,13 +969,6 @@ static void baseband_usb_close(struct baseband_usb *usb)
                flush_work_sync(&usb->ipc->rx_work);
        }
 
-       /* close usb driver */
-       if (usb->usb.driver) {
-               pr_debug("close usb driver {\n");
-               usb_deregister(usb->usb.driver);
-               usb->usb.driver = (struct usb_driver *) 0;
-               pr_debug("close usb driver }\n");
-       }
 
        /* close baseband ipc */
        if (usb->ipc) {
@@ -1014,24 +1010,17 @@ static struct baseband_usb *baseband_usb_open(work_func_t work_func,
                goto error_exit;
        }
 
-       /* open usb driver */
-       probe_usb_intf = (struct usb_interface *) 0;
        usb->usb.driver = &baseband_usb_driver;
-       err = usb_register(&baseband_usb_driver);
-       if (err < 0) {
-               pr_err("cannot open usb driver - err %d\n", err);
-               goto error_exit;
-       }
 
-       /* wait for probe */
-       pr_info("%s: waiting for usb probe...\n", __func__);
-       for (i = 0; i < 5 * 10; i++) {
+       for (i = 0; i < 5 * 50; i++) {
                if (probe_usb_intf && usb_device_connection)
                        break;
-               msleep(100);
+               /* wait for probe */
+               pr_debug("%s: waiting for usb probe...\n", __func__);
+               msleep(20);
        }
        if (!probe_usb_intf || !usb_device_connection) {
-               pr_info("%s: probe timed out!\n", __func__);
+               pr_err("%s: probe timed out!\n", __func__);
                goto error_exit;
        }
 
@@ -1066,9 +1055,9 @@ static struct baseband_usb *baseband_usb_open(work_func_t work_func,
                pr_err("usb_alloc_urb() failed\n");
                goto error_exit;
        }
-       buf = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+       buf = usb_chr_res.rx_buf;
        if (!buf) {
-               pr_err("%s: usb buffer kmalloc() failed\n", __func__);
+               pr_err("%s: usb rx buffer not found\n", __func__);
                usb_free_urb(urb);
                goto error_exit;
        }
@@ -1222,17 +1211,33 @@ static const struct file_operations baseband_usb_chr_fops = {
 
 static int baseband_usb_chr_init(void)
 {
-       int err;
+       int err = -ENOMEM;
 
        pr_debug("baseband_usb_chr_init {\n");
 
+       usb_chr_res.ipc_rx = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+       if (!usb_chr_res.ipc_rx) {
+               pr_err("cannot allocate ipc_rx\n");
+               goto error;
+       }
+       usb_chr_res.ipc_tx = kmalloc(USB_CHR_TX_BUFSIZ, GFP_KERNEL);
+       if (!usb_chr_res.ipc_tx) {
+               pr_err("cannot allocate ipc_tx\n");
+               goto error;
+       }
+       usb_chr_res.rx_buf = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+       if (!usb_chr_res.rx_buf) {
+               pr_err("%s: usb buffer kmalloc() failed\n", __func__);
+               goto error;
+       }
+
        /* register character device */
        err = register_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
                BASEBAND_USB_CHR_DEV_NAME,
                &baseband_usb_chr_fops);
        if (err < 0) {
                pr_err("cannot register character device - %d\n", err);
-               return err;
+               goto error;
        }
        pr_debug("registered baseband usb character device - major %d\n",
                BASEBAND_USB_CHR_DEV_MAJOR);
@@ -1243,11 +1248,30 @@ static int baseband_usb_chr_init(void)
                pr_err("cannot create workqueue\n");
                unregister_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
                        BASEBAND_USB_CHR_DEV_NAME);
-               return -ENODEV;
+               err = -ENODEV;
+               goto error;
+       }
+
+       /* register usb driver */
+       err = usb_register(&baseband_usb_driver);
+       if (err < 0) {
+               pr_err("%s: cannot register usb driver %d\n", __func__, err);
+               goto error2;
        }
 
        pr_debug("baseband_usb_chr_init }\n");
        return 0;
+
+error2:
+       unregister_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
+                       BASEBAND_USB_CHR_DEV_NAME);
+       destroy_workqueue(chr_ipc_wq);
+       chr_ipc_wq = NULL;
+error:
+       kfree(usb_chr_res.ipc_rx);
+       kfree(usb_chr_res.ipc_tx);
+       kfree(usb_chr_res.rx_buf);
+       return err;
 }
 
 static void baseband_usb_chr_exit(void)
@@ -1262,6 +1286,14 @@ static void baseband_usb_chr_exit(void)
                destroy_workqueue(chr_ipc_wq);
                chr_ipc_wq = NULL;
        }
+
+       /* close usb driver */
+       usb_deregister(&baseband_usb_driver);
+
+       kfree(usb_chr_res.ipc_rx);
+       kfree(usb_chr_res.ipc_tx);
+       kfree(usb_chr_res.rx_buf);
+
        pr_debug("baseband_usb_chr_exit }\n");
 }