tty: smux_ctl: add device attribute for open timeout

Port open call for smux is blocking. There is a 5 seconds default
timeout for the open call. The total number of retries for opening
the port makes the total wait time to be 11 minutes. This timeout
becomes an issue if QSC does not come up in time. Adding a device
attribute lets the user space control/reduce the timeout value.

CRs-Fixed: 372629
Change-Id: Ib20bf05da740c99dbb7e94b4df96d256ecadad34
Signed-off-by: Angshuman Sarkar <angshuman@codeaurora.org>
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
index 2b8f028..0078b04 100644
--- a/drivers/tty/smux_ctl.c
+++ b/drivers/tty/smux_ctl.c
@@ -52,6 +52,7 @@
 };
 
 #define SMUX_CTL_NUM_CHANNELS ARRAY_SIZE(smux_ctl_ch_id)
+#define DEFAULT_OPEN_TIMEOUT 5
 
 struct smux_ctl_dev {
 	int id;
@@ -64,6 +65,7 @@
 	int is_channel_reset;
 	int is_high_wm;
 	int write_pending;
+	unsigned open_timeout_val;
 
 	struct mutex rx_lock;
 	uint32_t read_avail;
@@ -149,6 +151,52 @@
 #define SMUXCTL_SET_LOOPBACK(lcid) do {} while (0)
 #endif
 
+static ssize_t open_timeout_store(struct device *d,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t n)
+{
+	int i;
+	unsigned long tmp;
+	for (i = 0; i < SMUX_CTL_NUM_CHANNELS; ++i) {
+		if (smux_ctl_devp[i]->devicep == d)
+			break;
+	}
+	if (i >= SMUX_CTL_NUM_CHANNELS) {
+		pr_err("%s: unable to match device to valid smux ctl port\n",
+				__func__);
+		return -EINVAL;
+	}
+	if (!kstrtoul(buf, 10, &tmp)) {
+		smux_ctl_devp[i]->open_timeout_val = tmp;
+		return n;
+	} else {
+		pr_err("%s: unable to convert: %s to an int\n", __func__,
+				buf);
+		return -EINVAL;
+	}
+}
+
+static ssize_t open_timeout_show(struct device *d,
+		struct device_attribute *attr,
+		char *buf)
+{
+	int i;
+	for (i = 0; i < SMUX_CTL_NUM_CHANNELS; ++i) {
+		if (smux_ctl_devp[i]->devicep == d)
+			break;
+	}
+	if (i >= SMUX_CTL_NUM_CHANNELS) {
+		pr_err("%s: unable to match device to valid smux ctl port\n",
+				__func__);
+		return -EINVAL;
+	}
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			smux_ctl_devp[i]->open_timeout_val);
+}
+
+static DEVICE_ATTR(open_timeout, 0664, open_timeout_show, open_timeout_store);
+
 static int get_ctl_dev_index(int id)
 {
 	int dev_index;
@@ -323,6 +371,7 @@
 {
 	int r = 0;
 	struct smux_ctl_dev *devp;
+	unsigned wait_time = DEFAULT_OPEN_TIMEOUT * HZ;
 
 	if (!smux_ctl_inited)
 		return -EIO;
@@ -349,11 +398,14 @@
 			return r;
 		}
 
+		if (devp->open_timeout_val)
+			wait_time = devp->open_timeout_val * HZ;
+
 		r = wait_event_interruptible_timeout(
 				devp->write_wait_queue,
 				(devp->state == SMUX_CONNECTED ||
-				 devp->abort_wait),
-				(5 * HZ));
+				devp->abort_wait),
+				wait_time);
 		if (r == 0)
 			r = -ETIMEDOUT;
 
@@ -822,6 +874,11 @@
 			kfree(smux_ctl_devp[i]);
 			goto error2;
 		}
+		if (device_create_file(smux_ctl_devp[i]->devicep,
+				&dev_attr_open_timeout))
+			pr_err("%s: unable to create device attr for" \
+				" smux ctl dev id:%d\n", __func__, i);
+
 	}
 
 	smux_ctl_inited = 1;