usb: ks_bridge: Avoid allocating large buffers in atomic context

The current code allocates a new Rx buffer in Rx completion handler.
Rx buffers are freed after user space consumes them.  This results in
allocating larger buffers in atomic context which may fail some times.
Don't queue the Rx buffer immediately. Defer it till user space consumes
it and reuse the same buffer.  The test results indicate no throughput
degradation.  The Rx buffers will be freed when interface is suspended
or disconnected.

CRs-Fixed: 430595
Change-Id: I8e69e27df2e11b38497e0384a8edd87ecedcb24b
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
(cherry picked from commit 5c915c1949b79bc59d2b222bfcce02cd429619b2)
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index c91cd68..591440d 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -69,7 +69,6 @@
 	struct usb_anchor	submitted;
 
 	unsigned long		flags;
-	unsigned int		alloced_read_pkts;
 
 #define DBG_MSG_LEN   40
 #define DBG_MAX_MSG   500
@@ -136,6 +135,8 @@
 }
 
 
+static void
+submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt);
 static ssize_t ksb_fs_read(struct file *fp, char __user *buf,
 				size_t count, loff_t *pos)
 {
@@ -174,7 +175,6 @@
 		if (ret) {
 			pr_err("copy_to_user failed err:%d\n", ret);
 			ksb_free_data_pkt(pkt);
-			ksb->alloced_read_pkts--;
 			return ret;
 		}
 
@@ -184,9 +184,16 @@
 
 		spin_lock_irqsave(&ksb->lock, flags);
 		if (pkt->n_read == pkt->len) {
+			/*
+			 * re-init the packet and queue it
+			 * for more data.
+			 */
 			list_del_init(&pkt->list);
-			ksb_free_data_pkt(pkt);
-			ksb->alloced_read_pkts--;
+			pkt->n_read = 0;
+			pkt->len = MAX_DATA_PKT_SIZE;
+			spin_unlock_irqrestore(&ksb->lock, flags);
+			submit_one_urb(ksb, GFP_KERNEL, pkt);
+			spin_lock_irqsave(&ksb->lock, flags);
 		}
 	}
 	spin_unlock_irqrestore(&ksb->lock, flags);
@@ -394,25 +401,18 @@
 MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
 
 static void ksb_rx_cb(struct urb *urb);
-static void submit_one_urb(struct ks_bridge *ksb)
+static void
+submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt)
 {
-	struct data_pkt	*pkt;
 	struct urb *urb;
 	int ret;
 
-	pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_ATOMIC, ksb);
-	if (IS_ERR(pkt)) {
-		pr_err("unable to allocate data pkt");
-		return;
-	}
-
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	urb = usb_alloc_urb(0, flags);
 	if (!urb) {
 		pr_err("unable to allocate urb");
 		ksb_free_data_pkt(pkt);
 		return;
 	}
-	ksb->alloced_read_pkts++;
 
 	usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
 			pkt->buf, pkt->len,
@@ -421,13 +421,12 @@
 
 	dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
 
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	ret = usb_submit_urb(urb, flags);
 	if (ret) {
 		pr_err("in urb submission failed");
 		usb_unanchor_urb(urb);
 		usb_free_urb(urb);
 		ksb_free_data_pkt(pkt);
-		ksb->alloced_read_pkts--;
 		return;
 	}
 
@@ -452,14 +451,12 @@
 			pr_err_ratelimited("urb failed with err:%d",
 					urb->status);
 		ksb_free_data_pkt(pkt);
-		ksb->alloced_read_pkts--;
 		return;
 	}
 
 	if (urb->actual_length == 0) {
-		ksb_free_data_pkt(pkt);
-		ksb->alloced_read_pkts--;
-		goto resubmit_urb;
+		submit_one_urb(ksb, GFP_ATOMIC, pkt);
+		return;
 	}
 
 add_to_list:
@@ -470,10 +467,6 @@
 
 	/* wake up read thread */
 	wake_up(&ksb->ks_wait_q);
-
-resubmit_urb:
-	submit_one_urb(ksb);
-
 }
 
 static void ksb_start_rx_work(struct work_struct *w)
@@ -506,7 +499,6 @@
 			ksb_free_data_pkt(pkt);
 			return;
 		}
-		ksb->alloced_read_pkts++;
 
 		usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
 				pkt->buf, pkt->len,
@@ -521,7 +513,6 @@
 			usb_unanchor_urb(urb);
 			usb_free_urb(urb);
 			ksb_free_data_pkt(pkt);
-			ksb->alloced_read_pkts--;
 			usb_autopm_put_interface(ksb->ifc);
 			return;
 		}
@@ -610,8 +601,6 @@
 
 	dbg_log_event(ksb, "SUSPEND", 0, 0);
 
-	pr_debug("read cnt: %d", ksb->alloced_read_pkts);
-
 	usb_kill_anchored_urbs(&ksb->submitted);
 
 	return 0;