[PATCH v2 7/7] mhi_bus: dev: uci: add user space interface driver

2018-07-09 Thread Sujeev Dias
This module allows user space clients to transfer data
between external modem and host using standard file
operations.

Signed-off-by: Sujeev Dias 
Reviewed-by: Tony Truong 
Signed-off-by: Siddartha Mohanadoss 
---
 arch/arm64/configs/defconfig  |   1 +
 drivers/bus/Kconfig   |   1 +
 drivers/bus/mhi/Makefile  |   3 +-
 drivers/bus/mhi/devices/Kconfig   |  13 +
 drivers/bus/mhi/devices/Makefile  |   1 +
 drivers/bus/mhi/devices/mhi_uci.c | 590 ++
 6 files changed, 608 insertions(+), 1 deletion(-)
 create mode 100644 drivers/bus/mhi/devices/Kconfig
 create mode 100644 drivers/bus/mhi/devices/Makefile
 create mode 100644 drivers/bus/mhi/devices/mhi_uci.c

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index fd36426..7f68d706 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -169,6 +169,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_MHI_BUS=y
 CONFIG_MHI_QCOM=y
+CONFIG_MHI_UCI=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 8c6827a..cb10366 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -181,5 +181,6 @@ config MHI_BUS
 
 source "drivers/bus/fsl-mc/Kconfig"
 source drivers/bus/mhi/controllers/Kconfig
+source drivers/bus/mhi/devices/Kconfig
 
 endmenu
diff --git a/drivers/bus/mhi/Makefile b/drivers/bus/mhi/Makefile
index 3458ba3..2382e04 100644
--- a/drivers/bus/mhi/Makefile
+++ b/drivers/bus/mhi/Makefile
@@ -4,4 +4,5 @@
 
 # core layer
 obj-y += core/
-obj-y += controllers/
\ No newline at end of file
+obj-y += controllers/
+obj-y += devices/
diff --git a/drivers/bus/mhi/devices/Kconfig b/drivers/bus/mhi/devices/Kconfig
new file mode 100644
index 000..45cd742
--- /dev/null
+++ b/drivers/bus/mhi/devices/Kconfig
@@ -0,0 +1,13 @@
+menu "MHI device support"
+
+config MHI_UCI
+   tristate "MHI UCI"
+   depends on MHI_BUS
+   help
+ MHI based uci driver is for transferring data between host and
+ modem using standard file operations from user space. Open, read,
+ write, ioctl, and close operations are supported by this driver.
+ Please check mhi_uci_match_table for all supported channels that
+ are exposed to userspace.
+
+endmenu
diff --git a/drivers/bus/mhi/devices/Makefile b/drivers/bus/mhi/devices/Makefile
new file mode 100644
index 000..ddc0613
--- /dev/null
+++ b/drivers/bus/mhi/devices/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MHI_UCI) +=mhi_uci.o
diff --git a/drivers/bus/mhi/devices/mhi_uci.c 
b/drivers/bus/mhi/devices/mhi_uci.c
new file mode 100644
index 000..ad60a15
--- /dev/null
+++ b/drivers/bus/mhi/devices/mhi_uci.c
@@ -0,0 +1,590 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DEVICE_NAME "mhi"
+#define MHI_UCI_DRIVER_NAME "mhi_uci"
+
+struct uci_chan {
+   wait_queue_head_t wq;
+   spinlock_t lock;
+   struct list_head pending; /* user space waiting to read */
+   struct uci_buf *cur_buf; /* current buffer user space reading */
+   size_t rx_size;
+};
+
+struct uci_buf {
+   void *data;
+   size_t len;
+   struct list_head node;
+};
+
+struct uci_dev {
+   struct list_head node;
+   dev_t devt;
+   struct device *dev;
+   struct mhi_device *mhi_dev;
+   const char *chan;
+   struct mutex mutex; /* sync open and close */
+   struct uci_chan ul_chan;
+   struct uci_chan dl_chan;
+   size_t mtu;
+   int ref_count;
+   bool enabled;
+};
+
+struct mhi_uci_drv {
+   struct list_head head;
+   struct mutex lock;
+   struct class *class;
+   int major;
+   dev_t dev_t;
+};
+
+#define MAX_UCI_DEVICES (64)
+
+static DECLARE_BITMAP(uci_minors, MAX_UCI_DEVICES);
+static struct mhi_uci_drv mhi_uci_drv;
+
+static int mhi_queue_inbound(struct uci_dev *uci_dev)
+{
+   struct mhi_device *mhi_dev = uci_dev->mhi_dev;
+   int nr_trbs = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE);
+   size_t mtu = uci_dev->mtu;
+   void *buf;
+   struct uci_buf *uci_buf;
+   int ret = -EIO, i;
+
+   for (i = 0; i < nr_trbs; i++) {
+   buf = kmalloc(mtu + sizeof(*uci_buf), GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   uci_buf = buf + mtu;
+   uci_buf->data = buf;
+
+   ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, mtu,
+MHI_EOT);
+   if (ret) {
+   kfree(buf);
+   return ret;
+   }
+   }
+
+   return ret;
+}
+
+static long mhi_uci_ioctl(struct file *file,
+ unsigned int cmd,
+  

[PATCH v2 7/7] mhi_bus: dev: uci: add user space interface driver

2018-07-09 Thread Sujeev Dias
This module allows user space clients to transfer data
between external modem and host using standard file
operations.

Signed-off-by: Sujeev Dias 
Reviewed-by: Tony Truong 
Signed-off-by: Siddartha Mohanadoss 
---
 arch/arm64/configs/defconfig  |   1 +
 drivers/bus/Kconfig   |   1 +
 drivers/bus/mhi/Makefile  |   3 +-
 drivers/bus/mhi/devices/Kconfig   |  13 +
 drivers/bus/mhi/devices/Makefile  |   1 +
 drivers/bus/mhi/devices/mhi_uci.c | 590 ++
 6 files changed, 608 insertions(+), 1 deletion(-)
 create mode 100644 drivers/bus/mhi/devices/Kconfig
 create mode 100644 drivers/bus/mhi/devices/Makefile
 create mode 100644 drivers/bus/mhi/devices/mhi_uci.c

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index fd36426..7f68d706 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -169,6 +169,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_MHI_BUS=y
 CONFIG_MHI_QCOM=y
+CONFIG_MHI_UCI=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 8c6827a..cb10366 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -181,5 +181,6 @@ config MHI_BUS
 
 source "drivers/bus/fsl-mc/Kconfig"
 source drivers/bus/mhi/controllers/Kconfig
+source drivers/bus/mhi/devices/Kconfig
 
 endmenu
diff --git a/drivers/bus/mhi/Makefile b/drivers/bus/mhi/Makefile
index 3458ba3..2382e04 100644
--- a/drivers/bus/mhi/Makefile
+++ b/drivers/bus/mhi/Makefile
@@ -4,4 +4,5 @@
 
 # core layer
 obj-y += core/
-obj-y += controllers/
\ No newline at end of file
+obj-y += controllers/
+obj-y += devices/
diff --git a/drivers/bus/mhi/devices/Kconfig b/drivers/bus/mhi/devices/Kconfig
new file mode 100644
index 000..45cd742
--- /dev/null
+++ b/drivers/bus/mhi/devices/Kconfig
@@ -0,0 +1,13 @@
+menu "MHI device support"
+
+config MHI_UCI
+   tristate "MHI UCI"
+   depends on MHI_BUS
+   help
+ MHI based uci driver is for transferring data between host and
+ modem using standard file operations from user space. Open, read,
+ write, ioctl, and close operations are supported by this driver.
+ Please check mhi_uci_match_table for all supported channels that
+ are exposed to userspace.
+
+endmenu
diff --git a/drivers/bus/mhi/devices/Makefile b/drivers/bus/mhi/devices/Makefile
new file mode 100644
index 000..ddc0613
--- /dev/null
+++ b/drivers/bus/mhi/devices/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MHI_UCI) +=mhi_uci.o
diff --git a/drivers/bus/mhi/devices/mhi_uci.c 
b/drivers/bus/mhi/devices/mhi_uci.c
new file mode 100644
index 000..ad60a15
--- /dev/null
+++ b/drivers/bus/mhi/devices/mhi_uci.c
@@ -0,0 +1,590 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DEVICE_NAME "mhi"
+#define MHI_UCI_DRIVER_NAME "mhi_uci"
+
+struct uci_chan {
+   wait_queue_head_t wq;
+   spinlock_t lock;
+   struct list_head pending; /* user space waiting to read */
+   struct uci_buf *cur_buf; /* current buffer user space reading */
+   size_t rx_size;
+};
+
+struct uci_buf {
+   void *data;
+   size_t len;
+   struct list_head node;
+};
+
+struct uci_dev {
+   struct list_head node;
+   dev_t devt;
+   struct device *dev;
+   struct mhi_device *mhi_dev;
+   const char *chan;
+   struct mutex mutex; /* sync open and close */
+   struct uci_chan ul_chan;
+   struct uci_chan dl_chan;
+   size_t mtu;
+   int ref_count;
+   bool enabled;
+};
+
+struct mhi_uci_drv {
+   struct list_head head;
+   struct mutex lock;
+   struct class *class;
+   int major;
+   dev_t dev_t;
+};
+
+#define MAX_UCI_DEVICES (64)
+
+static DECLARE_BITMAP(uci_minors, MAX_UCI_DEVICES);
+static struct mhi_uci_drv mhi_uci_drv;
+
+static int mhi_queue_inbound(struct uci_dev *uci_dev)
+{
+   struct mhi_device *mhi_dev = uci_dev->mhi_dev;
+   int nr_trbs = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE);
+   size_t mtu = uci_dev->mtu;
+   void *buf;
+   struct uci_buf *uci_buf;
+   int ret = -EIO, i;
+
+   for (i = 0; i < nr_trbs; i++) {
+   buf = kmalloc(mtu + sizeof(*uci_buf), GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   uci_buf = buf + mtu;
+   uci_buf->data = buf;
+
+   ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, mtu,
+MHI_EOT);
+   if (ret) {
+   kfree(buf);
+   return ret;
+   }
+   }
+
+   return ret;
+}
+
+static long mhi_uci_ioctl(struct file *file,
+ unsigned int cmd,
+