summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorVinayak Pane <vpane@nvidia.com>2012-03-21 15:06:43 -0700
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-07-17 11:16:17 -0700
commit2a498649ecd1743756a42ff393cbe40795ac5180 (patch)
tree4d45dfef5bf42882297043c8005a4a793829ebca /drivers/usb
parent969361b41f95efb349da4ed7a0e8834cc9c2ab89 (diff)
usb: serial: baseband: buffer allocations at init
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/baseband_usb_chr.c98
1 files changed, 65 insertions, 33 deletions
diff --git a/drivers/usb/serial/baseband_usb_chr.c b/drivers/usb/serial/baseband_usb_chr.c
index 96db92715207..c4eda3fe1ab7 100644
--- a/drivers/usb/serial/baseband_usb_chr.c
+++ b/drivers/usb/serial/baseband_usb_chr.c
@@ -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");
}