msm: smd_pkt: Extend write operation to send data larger than SMD FIFO

The SMD_PKT driver write operation restricts the maximum data size to
the corresponding SMD channel size. The user-space application wants
to send more data than the SMD channel size. So update the write operation
to send data larger than SMD channel size.

Change-Id: Icf4b62ceaaca9305188d3a6d78a44d1c48aadca8
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 7c7a822..4744f1f 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -63,7 +63,6 @@
 	int i;
 
 	int blocking_write;
-	int needed_space;
 	int is_open;
 	unsigned ch_size;
 	uint open_modem_wait;
@@ -155,7 +154,7 @@
 	smd_pkt_devp->is_open = 0;
 
 	wake_up(&smd_pkt_devp->ch_read_wait_queue);
-	wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+	wake_up(&smd_pkt_devp->ch_write_wait_queue);
 	wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
 }
 
@@ -305,7 +304,7 @@
 		       size_t count,
 		       loff_t *ppos)
 {
-	int r = 0;
+	int r = 0, bytes_written;
 	struct smd_pkt_dev *smd_pkt_devp;
 	DEFINE_WAIT(write_wait);
 
@@ -317,84 +316,56 @@
 	if (!smd_pkt_devp || !smd_pkt_devp->ch)
 		return -EINVAL;
 
-	if (count > smd_pkt_devp->ch_size)
-		return -EINVAL;
-
 	if (smd_pkt_devp->do_reset_notification) {
 		/* notify client that a reset occurred */
 		return notify_reset(smd_pkt_devp);
 	}
 
-	if (smd_pkt_devp->blocking_write) {
-		for (;;) {
-			mutex_lock(&smd_pkt_devp->tx_lock);
-			if (smd_pkt_devp->has_reset) {
-				smd_disable_read_intr(smd_pkt_devp->ch);
-				mutex_unlock(&smd_pkt_devp->tx_lock);
-				return notify_reset(smd_pkt_devp);
-			}
-			if (signal_pending(current)) {
-				smd_disable_read_intr(smd_pkt_devp->ch);
-				mutex_unlock(&smd_pkt_devp->tx_lock);
-				return -ERESTARTSYS;
-			}
-
-			prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
-					&write_wait, TASK_INTERRUPTIBLE);
-			smd_enable_read_intr(smd_pkt_devp->ch);
-			if (smd_write_avail(smd_pkt_devp->ch) < count) {
-				if (!smd_pkt_devp->needed_space ||
-				    count < smd_pkt_devp->needed_space)
-					smd_pkt_devp->needed_space = count;
-				mutex_unlock(&smd_pkt_devp->tx_lock);
-				schedule();
-			} else
-				break;
-		}
-		finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
-		smd_disable_read_intr(smd_pkt_devp->ch);
-		if (smd_pkt_devp->has_reset) {
-			mutex_unlock(&smd_pkt_devp->tx_lock);
-			return notify_reset(smd_pkt_devp);
-		}
-		if (signal_pending(current)) {
-			mutex_unlock(&smd_pkt_devp->tx_lock);
-			return -ERESTARTSYS;
-		}
-	} else {
-		if (smd_pkt_devp->has_reset)
-			return notify_reset(smd_pkt_devp);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-
-		mutex_lock(&smd_pkt_devp->tx_lock);
+	mutex_lock(&smd_pkt_devp->tx_lock);
+	if (!smd_pkt_devp->blocking_write) {
 		if (smd_write_avail(smd_pkt_devp->ch) < count) {
 			D(KERN_ERR "%s: Not enough space to write\n",
-				    __func__);
+				   __func__);
 			mutex_unlock(&smd_pkt_devp->tx_lock);
 			return -ENOMEM;
 		}
 	}
 
-	D_DUMP_BUFFER("write: ", count, buf);
-
-	smd_pkt_devp->needed_space = 0;
-
-	r = smd_write_user_buffer(smd_pkt_devp->ch, buf, count);
-	if (r != count) {
+	r = smd_write_start(smd_pkt_devp->ch, count);
+	if (r < 0) {
 		mutex_unlock(&smd_pkt_devp->tx_lock);
-		if (smd_pkt_devp->has_reset)
-			return notify_reset(smd_pkt_devp);
-
-		printk(KERN_ERR "ERROR:%s:%i:%s: "
-		       "smd_write(ch,buf,count = %i) ret %i.\n",
-		       __FILE__,
-		       __LINE__,
-		       __func__,
-		       count,
-		       r);
+		pr_err("%s: Error %d @ smd_write_start\n", __func__, r);
 		return r;
 	}
+
+	bytes_written = 0;
+	do {
+		prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
+				&write_wait, TASK_UNINTERRUPTIBLE);
+		if (!smd_write_avail(smd_pkt_devp->ch) &&
+		    !smd_pkt_devp->has_reset) {
+			smd_enable_read_intr(smd_pkt_devp->ch);
+			schedule();
+		}
+		finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
+		smd_disable_read_intr(smd_pkt_devp->ch);
+
+		if (smd_pkt_devp->has_reset) {
+			mutex_unlock(&smd_pkt_devp->tx_lock);
+			return notify_reset(smd_pkt_devp);
+		} else {
+			r = smd_write_segment(smd_pkt_devp->ch,
+					      (void *)(buf + bytes_written),
+					      (count - bytes_written), 1);
+			if (r < 0) {
+				mutex_unlock(&smd_pkt_devp->tx_lock);
+				if (smd_pkt_devp->has_reset)
+					return notify_reset(smd_pkt_devp);
+			}
+			bytes_written += r;
+		}
+	} while (bytes_written != count);
+	smd_write_end(smd_pkt_devp->ch);
 	mutex_unlock(&smd_pkt_devp->tx_lock);
 
 	D(KERN_ERR "%s: just wrote %i bytes\n",
@@ -451,11 +422,11 @@
 		return;
 
 	sz = smd_write_avail(smd_pkt_devp->ch);
-	if (sz >= smd_pkt_devp->needed_space) {
+	if (sz) {
 		D(KERN_ERR "%s: %d bytes Write Space available\n",
 			    __func__, sz);
 		smd_disable_read_intr(smd_pkt_devp->ch);
-		wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
+		wake_up(&smd_pkt_devp->ch_write_wait_queue);
 	}
 }