[PATCH v2 7/7] mhi_bus: dev: uci: add user space interface driver
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
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, +