diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2017-03-03 17:39:22 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-03-03 17:39:22 -0800 |
commit | 6897134f7409d531a7cc53614773d74d54e6a3be (patch) | |
tree | a196c389acf43222c2c0b6f67a82a67a4476781b /drivers/platform | |
parent | f13bb40b09f583d4e55efc1e8ed21d053f59e619 (diff) | |
parent | 904c6c3c3102f7315fff31b590351996d06be4f4 (diff) |
Merge "msm: mhi_uci: Add support for platform devices"
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/msm/mhi_uci/mhi_uci.c | 916 |
1 files changed, 579 insertions, 337 deletions
diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c index 88a213b1b241..96c4671f994f 100644 --- a/drivers/platform/msm/mhi_uci/mhi_uci.c +++ b/drivers/platform/msm/mhi_uci/mhi_uci.c @@ -27,18 +27,17 @@ #include <linux/errno.h> #include <linux/device.h> #include <linux/errno.h> +#include <linux/of_device.h> #define MHI_DEV_NODE_NAME_LEN 13 -#define MHI_MAX_NR_OF_CLIENTS 23 -#define MHI_SOFTWARE_CLIENT_START 0 #define MHI_SOFTWARE_CLIENT_LIMIT 23 -#define MHI_MAX_SOFTWARE_CHANNELS 46 #define TRE_TYPICAL_SIZE 0x1000 #define TRE_MAX_SIZE 0xFFFF -#define MHI_UCI_IPC_LOG_PAGES (100) +#define MHI_UCI_IPC_LOG_PAGES (25) #define MAX_NR_TRBS_PER_CHAN 10 #define DEVICE_NAME "mhi" +#define MHI_UCI_DRIVER_NAME "mhi_uci" #define CTRL_MAGIC 0x4C525443 enum UCI_DBG_LEVEL { @@ -58,8 +57,6 @@ enum UCI_DBG_LEVEL mhi_uci_ipc_log_lvl = UCI_DBG_VERBOSE; enum UCI_DBG_LEVEL mhi_uci_ipc_log_lvl = UCI_DBG_ERROR; #endif -void *mhi_uci_ipc_log; - struct __packed rs232_ctrl_msg { u32 preamble; u32 msg_id; @@ -103,11 +100,12 @@ struct chan_attr { }; struct uci_client { - u32 client_index; u32 out_chan; u32 in_chan; u32 out_chan_state; u32 in_chan_state; + struct chan_attr in_attr; + struct chan_attr out_attr; struct mhi_client_handle *out_handle; struct mhi_client_handle *in_handle; size_t pending_data; @@ -126,22 +124,29 @@ struct uci_client { struct mhi_uci_ctxt_t *uci_ctxt; struct mutex in_chan_lock; struct mutex out_chan_lock; + void *uci_ipc_log; }; struct mhi_uci_ctxt_t { - struct chan_attr chan_attrib[MHI_MAX_SOFTWARE_CHANNELS]; + struct list_head node; + struct platform_dev *pdev; struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT]; struct mhi_client_info_t client_info; - dev_t start_ctrl_nr; - struct mhi_client_handle *ctrl_handle; + dev_t dev_t; struct mutex ctrl_mutex; - struct cdev cdev[MHI_MAX_SOFTWARE_CHANNELS]; - struct class *mhi_uci_class; - u32 ctrl_chan_id; + struct cdev cdev[MHI_SOFTWARE_CLIENT_LIMIT]; + struct uci_client *ctrl_client; atomic_t mhi_disabled; atomic_t mhi_enable_notif_wq_active; }; +struct mhi_uci_drv_ctxt { + struct list_head head; + struct mutex list_lock; + struct class *mhi_uci_class; + void *mhi_uci_ipc_log; +}; + #define CHAN_TO_CLIENT(_CHAN_NR) (_CHAN_NR / 2) #define CTRL_MSG_ID @@ -219,13 +224,13 @@ struct mhi_uci_ctxt_t { (_PKT)->size = new_val; \ }; -#define uci_log(_msg_lvl, _msg, ...) do { \ +#define uci_log(uci_ipc_log, _msg_lvl, _msg, ...) do { \ if (_msg_lvl >= mhi_uci_msg_lvl) { \ pr_err("[%s] "_msg, __func__, ##__VA_ARGS__); \ } \ - if (mhi_uci_ipc_log && (_msg_lvl >= mhi_uci_ipc_log_lvl)) { \ - ipc_log_string(mhi_uci_ipc_log, \ - "[%s] " _msg, __func__, ##__VA_ARGS__); \ + if (uci_ipc_log && (_msg_lvl >= mhi_uci_ipc_log_lvl)) { \ + ipc_log_string(uci_ipc_log, \ + "[%s] " _msg, __func__, ##__VA_ARGS__); \ } \ } while (0) @@ -246,20 +251,20 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait); static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static struct mhi_uci_ctxt_t uci_ctxt; +static struct mhi_uci_drv_ctxt mhi_uci_drv_ctxt; -static int mhi_init_inbound(struct uci_client *client_handle, - enum MHI_CLIENT_CHANNEL chan) +static int mhi_init_inbound(struct uci_client *client_handle) { int ret_val = 0; u32 i = 0; - struct chan_attr *chan_attributes = - &uci_ctxt.chan_attrib[chan]; + struct chan_attr *chan_attributes = &client_handle->in_attr; void *data_loc = NULL; size_t buf_size = chan_attributes->max_packet_size; if (client_handle == NULL) { - uci_log(UCI_DBG_ERROR, "Bad Input data, quitting\n"); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_ERROR, + "Bad Input data, quitting\n"); return -EINVAL; } chan_attributes->nr_trbs = @@ -270,12 +275,17 @@ static int mhi_init_inbound(struct uci_client *client_handle, if (!client_handle->in_buf_list) return -ENOMEM; - uci_log(UCI_DBG_INFO, "Channel %d supports %d desc\n", - i, chan_attributes->nr_trbs); + uci_log(client_handle->uci_ipc_log, + UCI_DBG_INFO, "Channel %d supports %d desc\n", + chan_attributes->chan_id, + chan_attributes->nr_trbs); for (i = 0; i < chan_attributes->nr_trbs; ++i) { data_loc = kmalloc(buf_size, GFP_KERNEL); - uci_log(UCI_DBG_INFO, "Allocated buffer %p size %zd\n", - data_loc, buf_size); + uci_log(client_handle->uci_ipc_log, + UCI_DBG_INFO, + "Allocated buffer %p size %zd\n", + data_loc, + buf_size); if (data_loc == NULL) return -ENOMEM; client_handle->in_buf_list[i] = data_loc; @@ -283,9 +293,11 @@ static int mhi_init_inbound(struct uci_client *client_handle, data_loc, buf_size, MHI_EOT); if (0 != ret_val) { kfree(data_loc); - uci_log(UCI_DBG_ERROR, + uci_log(client_handle->uci_ipc_log, + UCI_DBG_ERROR, "Failed insertion for chan %d, ret %d\n", - chan, ret_val); + chan_attributes->chan_id, + ret_val); break; } } @@ -325,7 +337,8 @@ static int mhi_uci_send_packet(struct mhi_client_handle **client_handle, if (is_uspace_buf) { data_loc = kmalloc(data_to_insert_now, GFP_KERNEL); if (NULL == data_loc) { - uci_log(UCI_DBG_ERROR, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Failed to allocate memory 0x%zx\n", data_to_insert_now); return -ENOMEM; @@ -343,13 +356,15 @@ static int mhi_uci_send_packet(struct mhi_client_handle **client_handle, flags = MHI_EOT; if (data_left_to_insert - data_to_insert_now > 0) flags |= MHI_CHAIN | MHI_EOB; - uci_log(UCI_DBG_VERBOSE, - "At trb i = %d/%d, chain = %d, eob = %d, addr 0x%p chan %d\n", - i, nr_avail_trbs, - flags & MHI_CHAIN, - flags & MHI_EOB, - data_loc, - uci_handle->out_chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "At trb i = %d/%d, chain = %d, eob = %d, addr 0x%p chan %d\n", + i, + nr_avail_trbs, + flags & MHI_CHAIN, + flags & MHI_EOB, + data_loc, + uci_handle->out_chan); ret_val = mhi_queue_xfer(*client_handle, data_loc, data_to_insert_now, flags); @@ -375,25 +390,34 @@ static int mhi_uci_send_status_cmd(struct uci_client *client) { struct rs232_ctrl_msg *rs232_pkt = NULL; struct uci_client *uci_ctrl_handle; - u32 ctrl_chan_id = uci_ctxt.ctrl_chan_id; - + struct mhi_uci_ctxt_t *uci_ctxt = client->uci_ctxt; int ret_val = 0; size_t pkt_size = sizeof(struct rs232_ctrl_msg); u32 amount_sent; - uci_ctrl_handle = &uci_ctxt.client_handles[ctrl_chan_id/2]; + if (!uci_ctxt->ctrl_client) { + uci_log(client->uci_ipc_log, + UCI_DBG_INFO, + "Control channel is not defined\n"); + return -EIO; + } + + uci_ctrl_handle = uci_ctxt->ctrl_client; mutex_lock(&uci_ctrl_handle->out_chan_lock); if (!atomic_read(&uci_ctrl_handle->mhi_disabled) && !uci_ctrl_handle->out_chan_state) { - uci_log(UCI_DBG_INFO, - "Opening outbound control channel %d\n", - uci_ctrl_handle->out_chan); + uci_log(uci_ctrl_handle->uci_ipc_log, + UCI_DBG_INFO, + "Opening outbound control channel %d for chan:%d\n", + uci_ctrl_handle->out_chan, + client->out_chan); ret_val = mhi_open_channel(uci_ctrl_handle->out_handle); if (0 != ret_val) { - uci_log(UCI_DBG_CRITICAL, + uci_log(uci_ctrl_handle->uci_ipc_log, + UCI_DBG_CRITICAL, "Could not open chan %d, for sideband ctrl\n", - client->out_chan); + uci_ctrl_handle->out_chan); ret_val = -EIO; goto error_open; } @@ -405,7 +429,8 @@ static int mhi_uci_send_status_cmd(struct uci_client *client) ret_val = -ENOMEM; goto error_open; } - uci_log(UCI_DBG_VERBOSE, + uci_log(uci_ctrl_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Received request to send msg for chan %d\n", client->out_chan); rs232_pkt->preamble = CTRL_MAGIC; @@ -423,9 +448,11 @@ static int mhi_uci_send_status_cmd(struct uci_client *client) pkt_size, 0); if (pkt_size != amount_sent) { - uci_log(UCI_DBG_INFO, - "Failed to send signal on chan %d, ret : %d\n", - client->out_chan, ret_val); + uci_log(uci_ctrl_handle->uci_ipc_log, + UCI_DBG_INFO, + "Failed to send signal for chan %d, ret : %d\n", + client->out_chan, + ret_val); goto error; } error_open: @@ -451,15 +478,20 @@ static int mhi_uci_tiocm_set(struct uci_client *client_ctxt, u32 set, u32 clear) client_ctxt->local_tiocm |= status_set; client_ctxt->local_tiocm &= ~status_clear; - uci_log(UCI_DBG_VERBOSE, + uci_log(client_ctxt->uci_ipc_log, + UCI_DBG_VERBOSE, "Old TIOCM0x%x for chan %d, Current TIOCM 0x%x\n", - old_status, client_ctxt->out_chan, client_ctxt->local_tiocm); + old_status, + client_ctxt->out_chan, + client_ctxt->local_tiocm); mutex_unlock(&client_ctxt->uci_ctxt->ctrl_mutex); if (client_ctxt->local_tiocm != old_status) { - uci_log(UCI_DBG_VERBOSE, + uci_log(client_ctxt->uci_ipc_log, + UCI_DBG_VERBOSE, "Setting TIOCM to 0x%x for chan %d\n", - client_ctxt->local_tiocm, client_ctxt->out_chan); + client_ctxt->local_tiocm, + client_ctxt->out_chan); return mhi_uci_send_status_cmd(client_ctxt); } return 0; @@ -474,26 +506,35 @@ static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd, uci_handle = file->private_data; if (uci_handle == NULL) { - uci_log(UCI_DBG_VERBOSE, - "Invalid handle for client.\n"); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_VERBOSE, + "Invalid handle for client\n"); return -ENODEV; } - uci_log(UCI_DBG_VERBOSE, - "Attempting to dtr cmd 0x%x arg 0x%lx for chan %d\n", - cmd, arg, uci_handle->out_chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Attempting to dtr cmd 0x%x arg 0x%lx for chan %d\n", + cmd, + arg, + uci_handle->out_chan); switch (cmd) { case TIOCMGET: - uci_log(UCI_DBG_VERBOSE, - "Returning 0x%x mask\n", uci_handle->local_tiocm); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Returning 0x%x mask\n", + uci_handle->local_tiocm); ret_val = uci_handle->local_tiocm; break; case TIOCMSET: if (0 != copy_from_user(&set_val, (void *)arg, sizeof(set_val))) return -ENOMEM; - uci_log(UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Attempting to set cmd 0x%x arg 0x%x for chan %d\n", - cmd, set_val, uci_handle->out_chan); + cmd, + set_val, + uci_handle->out_chan); ret_val = mhi_uci_tiocm_set(uci_handle, set_val, ~set_val); break; default: @@ -506,28 +547,36 @@ static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd, static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - struct uci_client *uci_handle = NULL; - uci_handle = file->private_data; + struct uci_client *uci_handle = file->private_data; + struct mhi_uci_ctxt_t *uci_ctxt; if (uci_handle == NULL) return -ENODEV; + + uci_ctxt = uci_handle->uci_ctxt; poll_wait(file, &uci_handle->read_wq, wait); poll_wait(file, &uci_handle->write_wq, wait); if (atomic_read(&uci_handle->avail_pkts) > 0) { - uci_log(UCI_DBG_VERBOSE, - "Client can read chan %d\n", uci_handle->in_chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Client can read chan %d\n", + uci_handle->in_chan); mask |= POLLIN | POLLRDNORM; } - if (!atomic_read(&uci_ctxt.mhi_disabled) && + if (!atomic_read(&uci_ctxt->mhi_disabled) && (mhi_get_free_desc(uci_handle->out_handle) > 0)) { - uci_log(UCI_DBG_VERBOSE, - "Client can write chan %d\n", uci_handle->out_chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Client can write chan %d\n", + uci_handle->out_chan); mask |= POLLOUT | POLLWRNORM; } - uci_log(UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Client attempted to poll chan %d, returning mask 0x%x\n", - uci_handle->in_chan, mask); + uci_handle->in_chan, + mask); return mask; } @@ -535,10 +584,12 @@ static int open_client_mhi_channels(struct uci_client *uci_client) { int ret_val = 0; int r = 0; - uci_log(UCI_DBG_INFO, - "Starting channels %d %d.\n", - uci_client->out_chan, - uci_client->in_chan); + + uci_log(uci_client->uci_ipc_log, + UCI_DBG_INFO, + "Starting channels %d %d\n", + uci_client->out_chan, + uci_client->in_chan); mutex_lock(&uci_client->out_chan_lock); mutex_lock(&uci_client->in_chan_lock); ret_val = mhi_open_channel(uci_client->out_handle); @@ -553,21 +604,26 @@ static int open_client_mhi_channels(struct uci_client *uci_client) ret_val = mhi_open_channel(uci_client->in_handle); if (ret_val != 0) { - uci_log(UCI_DBG_ERROR, - "Failed to open chan %d, ret 0x%x\n", - uci_client->out_chan, ret_val); + uci_log(uci_client->uci_ipc_log, + UCI_DBG_ERROR, + "Failed to open chan %d, ret 0x%x\n", + uci_client->out_chan, + ret_val); goto handle_in_err; } - uci_log(UCI_DBG_INFO, - "Initializing inbound chan %d.\n", - uci_client->in_chan); + uci_log(uci_client->uci_ipc_log, + UCI_DBG_INFO, + "Initializing inbound chan %d\n", + uci_client->in_chan); uci_client->in_chan_state = 1; - ret_val = mhi_init_inbound(uci_client, uci_client->in_chan); + ret_val = mhi_init_inbound(uci_client); if (0 != ret_val) { - uci_log(UCI_DBG_ERROR, - "Failed to init inbound 0x%x, ret 0x%x\n", - uci_client->in_chan, ret_val); + uci_log(uci_client->uci_ipc_log, + UCI_DBG_ERROR, + "Failed to init inbound 0x%x, ret 0x%x\n", + uci_client->in_chan, + ret_val); } mutex_unlock(&uci_client->in_chan_lock); @@ -583,37 +639,54 @@ handle_not_rdy_err: return r; } -static int mhi_uci_client_open(struct inode *mhi_inode, +static int mhi_uci_client_open(struct inode *inode, struct file *file_handle) { struct uci_client *uci_handle = NULL; + struct mhi_uci_ctxt_t *uci_ctxt = NULL, *itr; int r = 0; - int client_id = iminor(mhi_inode); - uci_handle = &uci_ctxt.client_handles[client_id]; - - if (NULL == uci_handle) + int client_id = iminor(inode); + int major = imajor(inode); + + /* Find the uci ctxt from major */ + mutex_lock(&mhi_uci_drv_ctxt.list_lock); + list_for_each_entry(itr, &mhi_uci_drv_ctxt.head, node) { + if (MAJOR(itr->dev_t) == major) { + uci_ctxt = itr; + break; + } + } + mutex_unlock(&mhi_uci_drv_ctxt.list_lock); + if (!uci_ctxt || client_id >= MHI_SOFTWARE_CLIENT_LIMIT) return -EINVAL; + uci_handle = &uci_ctxt->client_handles[client_id]; if (atomic_read(&uci_handle->mhi_disabled)) { - uci_log(UCI_DBG_INFO, - "MHI is still recovering from SSR, client %d\n", + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_INFO, + "MHI channel still disable for, client %d\n", client_id); msleep(500); return -EAGAIN; } - uci_log(UCI_DBG_INFO, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_INFO, "Client opened device node 0x%x, ref count 0x%x\n", - iminor(mhi_inode), atomic_read(&uci_handle->ref_count)); + client_id, + atomic_read(&uci_handle->ref_count)); if (1 == atomic_add_return(1, &uci_handle->ref_count)) { - uci_handle->uci_ctxt = &uci_ctxt; - uci_log(UCI_DBG_INFO, - "Opening channels client %d\n", client_id); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_INFO, + "Opening channels client %d\n", + client_id); r = open_client_mhi_channels(uci_handle); if (r) - uci_log(UCI_DBG_INFO, - "Failed to open channels ret %d\n", r); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_INFO, + "Failed to open channels ret %d\n", + r); } file_handle->private_data = uci_handle; return r; @@ -623,7 +696,6 @@ static int mhi_uci_client_release(struct inode *mhi_inode, struct file *file_handle) { struct uci_client *uci_handle = file_handle->private_data; - struct mhi_uci_ctxt_t *uci_ctxt; u32 nr_in_bufs = 0; int in_chan = 0; int i = 0; @@ -632,21 +704,22 @@ static int mhi_uci_client_release(struct inode *mhi_inode, if (uci_handle == NULL) return -EINVAL; - uci_ctxt = uci_handle->uci_ctxt; - in_chan = iminor(mhi_inode) + 1; - nr_in_bufs = uci_ctxt->chan_attrib[in_chan].nr_trbs; - buf_size = uci_ctxt->chan_attrib[in_chan].max_packet_size; + in_chan = uci_handle->in_attr.chan_id; + nr_in_bufs = uci_handle->in_attr.nr_trbs; + buf_size = uci_handle->in_attr.max_packet_size; if (atomic_sub_return(1, &uci_handle->ref_count) == 0) { - uci_log(UCI_DBG_ERROR, - "Last client left, closing channel 0x%x\n", - iminor(mhi_inode)); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_ERROR, + "Last client left, closing channel 0x%x\n", + in_chan); if (atomic_read(&uci_handle->out_pkt_pend_ack)) - uci_log(UCI_DBG_CRITICAL, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_CRITICAL, "Still waiting on %d acks!, chan %d\n", atomic_read(&uci_handle->out_pkt_pend_ack), - iminor(mhi_inode)); + uci_handle->out_attr.chan_id); mhi_close_channel(uci_handle->out_handle); mhi_close_channel(uci_handle->in_handle); @@ -659,7 +732,8 @@ static int mhi_uci_client_release(struct inode *mhi_inode, kfree(uci_handle->in_buf_list); atomic_set(&uci_handle->avail_pkts, 0); } else { - uci_log(UCI_DBG_ERROR, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_ERROR, "Client close chan %d, ref count 0x%x\n", iminor(mhi_inode), atomic_read(&uci_handle->ref_count)); @@ -689,17 +763,23 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, mutex = &uci_handle->in_chan_lock; chan = uci_handle->in_chan; mutex_lock(mutex); - buf_size = uci_ctxt.chan_attrib[chan].max_packet_size; + buf_size = uci_handle->in_attr.max_packet_size; + result.buf_addr = NULL; - uci_log(UCI_DBG_VERBOSE, "Client attempted read on chan %d\n", chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Client attempted read on chan %d\n", + chan); do { if (!uci_handle->pkt_loc && - !atomic_read(&uci_ctxt.mhi_disabled)) { + !atomic_read(&uci_handle->uci_ctxt->mhi_disabled)) { ret_val = mhi_poll_inbound(client_handle, &result); if (ret_val) { - uci_log(UCI_DBG_ERROR, - "Failed to poll inbound ret %d avail pkt %d\n", - ret_val, atomic_read(&uci_handle->avail_pkts)); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_ERROR, + "Failed to poll inbound ret %d avail pkt %d\n", + ret_val, + atomic_read(&uci_handle->avail_pkts)); } if (result.buf_addr) uci_handle->pkt_loc = result.buf_addr; @@ -707,23 +787,27 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, uci_handle->pkt_loc = 0; uci_handle->pkt_size = result.bytes_xferd; *bytes_pending = uci_handle->pkt_size; - uci_log(UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Got pkt size 0x%zx at addr 0x%lx, chan %d\n", uci_handle->pkt_size, - (uintptr_t)result.buf_addr, chan); + (uintptr_t)result.buf_addr, + chan); } if ((*bytes_pending == 0 || uci_handle->pkt_loc == 0) && (atomic_read(&uci_handle->avail_pkts) <= 0)) { /* If nothing was copied yet, wait for data */ - uci_log(UCI_DBG_VERBOSE, - "No data avail_pkts %d, chan %d\n", - atomic_read(&uci_handle->avail_pkts), - chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "No data avail_pkts %d, chan %d\n", + atomic_read(&uci_handle->avail_pkts), + chan); ret_val = wait_event_interruptible( uci_handle->read_wq, (atomic_read(&uci_handle->avail_pkts) > 0)); if (ret_val == -ERESTARTSYS) { - uci_log(UCI_DBG_ERROR, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_ERROR, "Exit signal caught\n"); goto error; } @@ -732,7 +816,8 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, 0 == uci_handle->pkt_size && 0 == uci_handle->pkt_loc && uci_handle->mhi_status == -ENETRESET) { - uci_log(UCI_DBG_ERROR, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_ERROR, "Detected pending reset, reporting chan %d\n", chan); atomic_dec(&uci_handle->avail_pkts); @@ -743,23 +828,24 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, } else if (atomic_read(&uci_handle->avail_pkts) && uci_handle->pkt_size != 0 && uci_handle->pkt_loc != 0) { - uci_log(UCI_DBG_VERBOSE, - "Got packet: avail pkts %d phy_adr 0x%p, chan %d\n", - atomic_read(&uci_handle->avail_pkts), - result.buf_addr, - chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Got packet: avail pkts %d phy_adr 0x%p, chan %d\n", + atomic_read(&uci_handle->avail_pkts), + result.buf_addr, + chan); break; /* * MHI did not return a valid packet, but we have one * which we did not finish returning to user */ } else { - uci_log(UCI_DBG_CRITICAL, - "chan %d err: avail pkts %d phy_adr 0x%p mhi_stat%d\n", - chan, - atomic_read(&uci_handle->avail_pkts), - result.buf_addr, - uci_handle->mhi_status); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_CRITICAL, + "chan %d err: avail pkts %d mhi_stat%d\n", + chan, + atomic_read(&uci_handle->avail_pkts), + uci_handle->mhi_status); return -EIO; } } while (!uci_handle->pkt_loc); @@ -775,9 +861,12 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, bytes_copied = *bytes_pending; *bytes_pending = 0; - uci_log(UCI_DBG_VERBOSE, - "Copied 0x%zx of 0x%x, chan %d\n", - bytes_copied, (u32)*bytes_pending, chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Copied 0x%zx of 0x%x, chan %d\n", + bytes_copied, + (u32)*bytes_pending, + chan); } else { addr_offset = uci_handle->pkt_size - *bytes_pending; if (copy_to_user(buf, @@ -789,39 +878,50 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, } bytes_copied = uspace_buf_size; *bytes_pending -= uspace_buf_size; - uci_log(UCI_DBG_VERBOSE, - "Copied 0x%zx of 0x%x,chan %d\n", - bytes_copied, - (u32)*bytes_pending, - chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Copied 0x%zx of 0x%x,chan %d\n", + bytes_copied, + (u32)*bytes_pending, + chan); } /* We finished with this buffer, map it back */ if (*bytes_pending == 0) { - uci_log(UCI_DBG_VERBOSE, "Pkt loc %p ,chan %d\n", - uci_handle->pkt_loc, chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Pkt loc %p ,chan %d\n", + uci_handle->pkt_loc, + chan); memset(uci_handle->pkt_loc, 0, buf_size); atomic_dec(&uci_handle->avail_pkts); - uci_log(UCI_DBG_VERBOSE, - "Decremented avail pkts avail 0x%x\n", - atomic_read(&uci_handle->avail_pkts)); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Decremented avail pkts avail 0x%x\n", + atomic_read(&uci_handle->avail_pkts)); ret_val = mhi_queue_xfer(client_handle, uci_handle->pkt_loc, buf_size, MHI_EOT); if (0 != ret_val) { - uci_log(UCI_DBG_ERROR, - "Failed to recycle element\n"); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_ERROR, + "Failed to recycle element\n"); ret_val = -EIO; goto error; } uci_handle->pkt_loc = 0; } - uci_log(UCI_DBG_VERBOSE, - "Returning 0x%zx bytes, 0x%x bytes left\n", - bytes_copied, (u32)*bytes_pending); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "Returning 0x%zx bytes, 0x%x bytes left\n", + bytes_copied, + (u32)*bytes_pending); mutex_unlock(mutex); return bytes_copied; error: mutex_unlock(mutex); - uci_log(UCI_DBG_ERROR, "Returning %d\n", ret_val); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_ERROR, + "Returning %d\n", + ret_val); return ret_val; } @@ -846,9 +946,10 @@ static ssize_t mhi_uci_client_write(struct file *file, ret_val = mhi_uci_send_packet(&uci_handle->out_handle, (void *)buf, count, 1); if (!ret_val) { - uci_log(UCI_DBG_VERBOSE, - "No descriptors available, did we poll, chan %d?\n", - chan); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, + "No descriptors available, did we poll, chan %d?\n", + chan); mutex_unlock(&uci_handle->out_chan_lock); ret_val = wait_event_interruptible( @@ -857,8 +958,9 @@ static ssize_t mhi_uci_client_write(struct file *file, mutex_lock(&uci_handle->out_chan_lock); if (-ERESTARTSYS == ret_val) { goto sys_interrupt; - uci_log(UCI_DBG_WARNING, - "Waitqueue cancelled by system\n"); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_WARNING, + "Waitqueue cancelled by system\n"); } } } @@ -867,60 +969,79 @@ sys_interrupt: return ret_val; } -static int uci_init_client_attributes(struct mhi_uci_ctxt_t - *uci_ctxt) +static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt, + struct device_node *of_node) { - u32 i = 0; - struct chan_attr *chan_attrib = NULL; - size_t max_packet_size = TRE_TYPICAL_SIZE; - - for (i = 0; i < MHI_MAX_SOFTWARE_CHANNELS; ++i) { - max_packet_size = TRE_TYPICAL_SIZE; - chan_attrib = &uci_ctxt->chan_attrib[i]; - switch (i) { - case MHI_CLIENT_SAHARA_IN: - max_packet_size = TRE_MAX_SIZE; - case MHI_CLIENT_SAHARA_OUT: - case MHI_CLIENT_LOOPBACK_OUT: - case MHI_CLIENT_LOOPBACK_IN: - case MHI_CLIENT_EFS_OUT: - case MHI_CLIENT_EFS_IN: - case MHI_CLIENT_QMI_OUT: - case MHI_CLIENT_QMI_IN: - case MHI_CLIENT_IP_CTRL_0_OUT: - case MHI_CLIENT_IP_CTRL_0_IN: - case MHI_CLIENT_IP_CTRL_1_OUT: - case MHI_CLIENT_IP_CTRL_1_IN: - case MHI_CLIENT_BL_OUT: - case MHI_CLIENT_BL_IN: - case MHI_CLIENT_DUN_OUT: - case MHI_CLIENT_DUN_IN: - case MHI_CLIENT_TF_OUT: - case MHI_CLIENT_TF_IN: + int num_rows, ret_val = 0; + int i, dir; + u32 ctrl_chan = -1; + u32 *chan_info, *itr; + const char *prop_name = "qcom,mhi-uci-channels"; + + ret_val = of_property_read_u32(of_node, "qcom,mhi-uci-ctrlchan", + &ctrl_chan); + if (ret_val) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_INFO, + "Could not find property 'qcom,mhi-uci-ctrlchan'\n"); + } + + num_rows = of_property_count_elems_of_size(of_node, prop_name, + sizeof(u32) * 4); + /* At least one pair of channels should exist */ + if (num_rows < 1) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_CRITICAL, + "Missing or invalid property 'qcom,mhi-uci-channels'\n"); + return -ENODEV; + } + + if (num_rows > MHI_SOFTWARE_CLIENT_LIMIT) + num_rows = MHI_SOFTWARE_CLIENT_LIMIT; + + chan_info = kmalloc_array(num_rows, 4 * sizeof(*chan_info), GFP_KERNEL); + if (!chan_info) + return -ENOMEM; + + ret_val = of_property_read_u32_array(of_node, prop_name, chan_info, + num_rows * 4); + if (ret_val) + goto error_dts; + + for (i = 0, itr = chan_info; i < num_rows; i++) { + struct uci_client *client = &uci_ctxt->client_handles[i]; + struct chan_attr *chan_attrib; + + for (dir = 0; dir < 2; dir++) { + chan_attrib = (dir) ? + &client->in_attr : &client->out_attr; chan_attrib->uci_ownership = 1; - break; - default: - chan_attrib->uci_ownership = 0; - break; - } - if (chan_attrib->uci_ownership) { - chan_attrib->chan_id = i; - chan_attrib->max_packet_size = max_packet_size; + chan_attrib->chan_id = *itr++; + chan_attrib->max_packet_size = *itr++; + if (dir == 0) + chan_attrib->dir = MHI_DIR_OUT; + else + chan_attrib->dir = MHI_DIR_IN; + + if (chan_attrib->chan_id == ctrl_chan) + uci_ctxt->ctrl_client = client; } - if (i % 2 == 0) - chan_attrib->dir = MHI_DIR_OUT; - else - chan_attrib->dir = MHI_DIR_IN; } - return 0; + +error_dts: + kfree(chan_info); + return ret_val; } static int process_mhi_disabled_notif_sync(struct uci_client *uci_handle) { - uci_log(UCI_DBG_INFO, "Entered.\n"); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_INFO, + "Entered.\n"); if (uci_handle->mhi_status != -ENETRESET) { - uci_log(UCI_DBG_CRITICAL, - "Setting reset for chan %d.\n", + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_CRITICAL, + "Setting reset for chan %d\n", uci_handle->out_chan); uci_handle->pkt_size = 0; uci_handle->pkt_loc = NULL; @@ -932,39 +1053,53 @@ static int process_mhi_disabled_notif_sync(struct uci_client *uci_handle) uci_handle->in_chan_state = 0; wake_up(&uci_handle->read_wq); } else { - uci_log(UCI_DBG_CRITICAL, - "Chan %d state already reset.\n", + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_CRITICAL, + "Chan %d state already reset\n", uci_handle->out_chan); } - uci_log(UCI_DBG_INFO, "Exited.\n"); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "Exited\n"); return 0; } -static void process_rs232_state(struct mhi_result *result) +static void process_rs232_state(struct uci_client *ctrl_client, + struct mhi_result *result) { struct rs232_ctrl_msg *rs232_pkt; - struct uci_client *client; + struct uci_client *client = NULL; + struct mhi_uci_ctxt_t *uci_ctxt = ctrl_client->uci_ctxt; u32 msg_id; - int ret_val; + int ret_val, i; u32 chan; - mutex_lock(&uci_ctxt.ctrl_mutex); + mutex_lock(&uci_ctxt->ctrl_mutex); if (result->transaction_status != 0) { - uci_log(UCI_DBG_ERROR, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_ERROR, "Non successful transfer code 0x%x\n", - result->transaction_status); + result->transaction_status); goto error_bad_xfer; } if (result->bytes_xferd != sizeof(struct rs232_ctrl_msg)) { - uci_log(UCI_DBG_ERROR, - "Buffer is of wrong size is: 0x%zx: expected 0x%zx\n", - result->bytes_xferd, sizeof(struct rs232_ctrl_msg)); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_ERROR, + "Buffer is of wrong size is: 0x%zx: expected 0x%zx\n", + result->bytes_xferd, + sizeof(struct rs232_ctrl_msg)); goto error_size; } rs232_pkt = result->buf_addr; MHI_GET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, chan); - client = &uci_ctxt.client_handles[chan / 2]; + for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) + if (chan == uci_ctxt->client_handles[i].out_chan || + chan == uci_ctxt->client_handles[i].in_chan) { + client = &uci_ctxt->client_handles[i]; + break; + } + /* No valid channel found */ + if (!client) + goto error_bad_xfer; MHI_GET_CTRL_MSG_ID(CTRL_MSG_ID, rs232_pkt, msg_id); client->local_tiocm = 0; @@ -982,35 +1117,38 @@ static void process_rs232_state(struct mhi_result *result) error_bad_xfer: error_size: memset(rs232_pkt, 0, sizeof(struct rs232_ctrl_msg)); - ret_val = mhi_queue_xfer(client->in_handle, - result->buf_addr, - result->bytes_xferd, - result->flags); + ret_val = mhi_queue_xfer(ctrl_client->in_handle, + result->buf_addr, + result->bytes_xferd, + result->flags); if (0 != ret_val) { - uci_log(UCI_DBG_ERROR, - "Failed to recycle ctrl msg buffer\n"); + uci_log(ctrl_client->uci_ipc_log, + UCI_DBG_ERROR, + "Failed to recycle ctrl msg buffer\n"); } - mutex_unlock(&uci_ctxt.ctrl_mutex); + mutex_unlock(&uci_ctxt->ctrl_mutex); } static void parse_inbound_ack(struct uci_client *uci_handle, struct mhi_result *result) { atomic_inc(&uci_handle->avail_pkts); - uci_log(UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Received cb on chan %d, avail pkts: 0x%x\n", uci_handle->in_chan, atomic_read(&uci_handle->avail_pkts)); wake_up(&uci_handle->read_wq); - if (uci_handle->in_chan == MHI_CLIENT_IP_CTRL_1_IN) - process_rs232_state(result); + if (uci_handle == uci_handle->uci_ctxt->ctrl_client) + process_rs232_state(uci_handle, result); } static void parse_outbound_ack(struct uci_client *uci_handle, struct mhi_result *result) { kfree(result->buf_addr); - uci_log(UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Received ack on chan %d, pending acks: 0x%x\n", uci_handle->out_chan, atomic_read(&uci_handle->out_pkt_pend_ack)); @@ -1021,88 +1159,96 @@ static void parse_outbound_ack(struct uci_client *uci_handle, static void uci_xfer_cb(struct mhi_cb_info *cb_info) { - int chan_nr; struct uci_client *uci_handle = NULL; - u32 client_index; struct mhi_result *result; if (!cb_info || !cb_info->result) { - uci_log(UCI_DBG_CRITICAL, "Bad CB info from MHI.\n"); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_CRITICAL, + "Bad CB info from MHI\n"); return; } - chan_nr = (uintptr_t)cb_info->result->user_data; - client_index = CHAN_TO_CLIENT(chan_nr); - uci_handle = &uci_ctxt.client_handles[client_index]; - + uci_handle = cb_info->result->user_data; switch (cb_info->cb_reason) { case MHI_CB_MHI_ENABLED: atomic_set(&uci_handle->mhi_disabled, 0); break; case MHI_CB_MHI_DISABLED: atomic_set(&uci_handle->mhi_disabled, 1); - uci_log(UCI_DBG_INFO, "MHI disabled CB received.\n"); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_INFO, + "MHI disabled CB received\n"); process_mhi_disabled_notif_sync(uci_handle); break; case MHI_CB_XFER: if (!cb_info->result) { - uci_log(UCI_DBG_CRITICAL, - "Failed to obtain mhi result from CB.\n"); + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_CRITICAL, + "Failed to obtain mhi result from CB\n"); return; } result = cb_info->result; - chan_nr = (uintptr_t)result->user_data; - client_index = chan_nr / 2; - uci_handle = - &uci_ctxt.client_handles[client_index]; - if (chan_nr % 2) + if (cb_info->chan % 2) parse_inbound_ack(uci_handle, result); else parse_outbound_ack(uci_handle, result); break; default: - uci_log(UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, + UCI_DBG_VERBOSE, "Cannot handle cb reason 0x%x\n", cb_info->cb_reason); } } -static int mhi_register_client(struct uci_client *mhi_client, int index) +static int mhi_register_client(struct uci_client *mhi_client) { int ret_val = 0; - uci_log(UCI_DBG_INFO, "Setting up workqueues.\n"); + uci_log(mhi_client->uci_ipc_log, + UCI_DBG_INFO, + "Setting up workqueues\n"); init_waitqueue_head(&mhi_client->read_wq); init_waitqueue_head(&mhi_client->write_wq); - mhi_client->out_chan = index * 2; - mhi_client->in_chan = index * 2 + 1; - mhi_client->client_index = index; + mhi_client->out_chan = mhi_client->out_attr.chan_id; + mhi_client->in_chan = mhi_client->in_attr.chan_id; mutex_init(&mhi_client->in_chan_lock); mutex_init(&mhi_client->out_chan_lock); atomic_set(&mhi_client->mhi_disabled, 1); - uci_log(UCI_DBG_INFO, "Registering chan %d.\n", mhi_client->out_chan); + uci_log(mhi_client->uci_ipc_log, + UCI_DBG_INFO, + "Registering chan %d\n", + mhi_client->out_chan); ret_val = mhi_register_channel(&mhi_client->out_handle, mhi_client->out_chan, 0, - &uci_ctxt.client_info, - (void *)(uintptr_t)(mhi_client->out_chan)); + &mhi_client->uci_ctxt->client_info, + mhi_client); if (0 != ret_val) - uci_log(UCI_DBG_ERROR, + uci_log(mhi_client->uci_ipc_log, + UCI_DBG_ERROR, "Failed to init outbound chan 0x%x, ret 0x%x\n", - mhi_client->out_chan, ret_val); + mhi_client->out_chan, + ret_val); - uci_log(UCI_DBG_INFO, "Registering chan %d.\n", mhi_client->in_chan); + uci_log(mhi_client->uci_ipc_log, + UCI_DBG_INFO, + "Registering chan %d\n", + mhi_client->in_chan); ret_val = mhi_register_channel(&mhi_client->in_handle, mhi_client->in_chan, 0, - &uci_ctxt.client_info, - (void *)(uintptr_t)(mhi_client->in_chan)); + &mhi_client->uci_ctxt->client_info, + mhi_client); if (0 != ret_val) - uci_log(UCI_DBG_ERROR, + uci_log(mhi_client->uci_ipc_log, + UCI_DBG_ERROR, "Failed to init inbound chan 0x%x, ret 0x%x\n", - mhi_client->in_chan, ret_val); + mhi_client->in_chan, + ret_val); return 0; } @@ -1115,119 +1261,215 @@ static const struct file_operations mhi_uci_client_fops = { .unlocked_ioctl = mhi_uci_ctl_ioctl, }; -static int mhi_uci_init(void) +static int mhi_uci_probe(struct platform_device *pdev) { - u32 i = 0; - int ret_val = 0; - struct uci_client *mhi_client = NULL; - s32 r = 0; - mhi_uci_ipc_log = ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES, - "mhi-uci", 0); - if (mhi_uci_ipc_log == NULL) { - uci_log(UCI_DBG_WARNING, - "Failed to create IPC logging context\n"); - } - uci_log(UCI_DBG_INFO, "Setting up work queues.\n"); - uci_ctxt.client_info.mhi_client_cb = uci_xfer_cb; + struct mhi_uci_ctxt_t *uci_ctxt; + int ret_val; + int i; + char node_name[16]; + + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_INFO, + "Entered with pdev:%p\n", + pdev); + + if (pdev->dev.of_node == NULL) + return -ENODEV; + + pdev->id = of_alias_get_id(pdev->dev.of_node, "mhi_uci"); + if (pdev->id < 0) + return -ENODEV; + + uci_ctxt = devm_kzalloc(&pdev->dev, + sizeof(*uci_ctxt), + GFP_KERNEL); + if (!uci_ctxt) + return -ENOMEM; - mutex_init(&uci_ctxt.ctrl_mutex); + uci_ctxt->client_info.mhi_client_cb = uci_xfer_cb; + mutex_init(&uci_ctxt->ctrl_mutex); - uci_log(UCI_DBG_INFO, "Setting up channel attributes.\n"); - ret_val = uci_init_client_attributes(&uci_ctxt); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_INFO, + "Setting up channel attributes\n"); + ret_val = uci_init_client_attributes(uci_ctxt, + pdev->dev.of_node); if (ret_val) { - uci_log(UCI_DBG_ERROR, - "Failed to init client attributes\n"); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_ERROR, + "Failed to init client attributes\n"); return -EIO; } - uci_ctxt.ctrl_chan_id = MHI_CLIENT_IP_CTRL_1_OUT; - uci_log(UCI_DBG_INFO, "Registering for MHI events.\n"); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_INFO, + "Registering for MHI events\n"); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) { - if (uci_ctxt.chan_attrib[i * 2].uci_ownership) { - mhi_client = &uci_ctxt.client_handles[i]; - r = mhi_register_client(mhi_client, i); - if (r) { - uci_log(UCI_DBG_CRITICAL, + struct uci_client *uci_client = &uci_ctxt->client_handles[i]; + + uci_client->uci_ctxt = uci_ctxt; + if (uci_client->in_attr.uci_ownership) { + ret_val = mhi_register_client(uci_client); + if (ret_val) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_CRITICAL, "Failed to reg client %d ret %d\n", - r, i); + ret_val, + i); + + return -EIO; } + snprintf(node_name, sizeof(node_name), "mhi-uci%d", + uci_client->out_attr.chan_id); + uci_client->uci_ipc_log = ipc_log_context_create + (MHI_UCI_IPC_LOG_PAGES, + node_name, + 0); } } - uci_log(UCI_DBG_INFO, "Allocating char devices.\n"); - r = alloc_chrdev_region(&uci_ctxt.start_ctrl_nr, - 0, MHI_MAX_SOFTWARE_CHANNELS, - DEVICE_NAME); - - if (IS_ERR_VALUE(r)) { - uci_log(UCI_DBG_ERROR, - "Failed to alloc char devs, ret 0x%x\n", r); + + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_INFO, + "Allocating char devices\n"); + ret_val = alloc_chrdev_region(&uci_ctxt->dev_t, + 0, + MHI_SOFTWARE_CLIENT_LIMIT, + DEVICE_NAME); + if (IS_ERR_VALUE(ret_val)) { + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_ERROR, + "Failed to alloc char devs, ret 0x%x\n", ret_val); goto failed_char_alloc; } - uci_log(UCI_DBG_INFO, "Creating class\n"); - uci_ctxt.mhi_uci_class = class_create(THIS_MODULE, - DEVICE_NAME); - if (IS_ERR(uci_ctxt.mhi_uci_class)) { - uci_log(UCI_DBG_ERROR, - "Failed to instantiate class, ret 0x%x\n", r); - r = -ENOMEM; - goto failed_class_add; - } - uci_log(UCI_DBG_INFO, "Setting up device nodes.\n"); + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, + UCI_DBG_INFO, + "Setting up device nodes. for dev_t: 0x%x major:0x%x\n", + uci_ctxt->dev_t, + MAJOR(uci_ctxt->dev_t)); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) { - if (uci_ctxt.chan_attrib[i*2].uci_ownership) { - cdev_init(&uci_ctxt.cdev[i], &mhi_uci_client_fops); - uci_ctxt.cdev[i].owner = THIS_MODULE; - r = cdev_add(&uci_ctxt.cdev[i], - uci_ctxt.start_ctrl_nr + i , 1); - if (IS_ERR_VALUE(r)) { - uci_log(UCI_DBG_ERROR, + struct uci_client *uci_client = &uci_ctxt->client_handles[i]; + + if (uci_client->in_attr.uci_ownership) { + cdev_init(&uci_ctxt->cdev[i], &mhi_uci_client_fops); + uci_ctxt->cdev[i].owner = THIS_MODULE; + ret_val = cdev_add(&uci_ctxt->cdev[i], + uci_ctxt->dev_t + i, 1); + if (IS_ERR_VALUE(ret_val)) { + uci_log(uci_client->uci_ipc_log, + UCI_DBG_ERROR, "Failed to add cdev %d, ret 0x%x\n", - i, r); + i, ret_val); goto failed_char_add; } - uci_ctxt.client_handles[i].dev = - device_create(uci_ctxt.mhi_uci_class, NULL, - uci_ctxt.start_ctrl_nr + i, - NULL, DEVICE_NAME "_pipe_%d", - i * 2); - - if (IS_ERR(uci_ctxt.client_handles[i].dev)) { - uci_log(UCI_DBG_ERROR, - "Failed to add cdev %d\n", i); - cdev_del(&uci_ctxt.cdev[i]); + uci_client->dev = + device_create(mhi_uci_drv_ctxt.mhi_uci_class, + NULL, + uci_ctxt->dev_t + i, + NULL, + DEVICE_NAME "_pipe_%d", + uci_client->out_chan); + if (IS_ERR(uci_client->dev)) { + uci_log(uci_client->uci_ipc_log, + UCI_DBG_ERROR, + "Failed to add cdev %d\n", i); + cdev_del(&uci_ctxt->cdev[i]); + ret_val = -EIO; goto failed_device_create; } } } + platform_set_drvdata(pdev, uci_ctxt); + mutex_lock(&mhi_uci_drv_ctxt.list_lock); + list_add_tail(&uci_ctxt->node, &mhi_uci_drv_ctxt.head); + mutex_unlock(&mhi_uci_drv_ctxt.list_lock); return 0; failed_char_add: failed_device_create: while (--i >= 0) { - cdev_del(&uci_ctxt.cdev[i]); - device_destroy(uci_ctxt.mhi_uci_class, - MKDEV(MAJOR(uci_ctxt.start_ctrl_nr), i * 2)); + cdev_del(&uci_ctxt->cdev[i]); + device_destroy(mhi_uci_drv_ctxt.mhi_uci_class, + MKDEV(MAJOR(uci_ctxt->dev_t), i)); }; - class_destroy(uci_ctxt.mhi_uci_class); -failed_class_add: - unregister_chrdev_region(MAJOR(uci_ctxt.start_ctrl_nr), - MHI_MAX_SOFTWARE_CHANNELS); + + unregister_chrdev_region(MAJOR(uci_ctxt->dev_t), + MHI_SOFTWARE_CLIENT_LIMIT); failed_char_alloc: - return r; -} -static void __exit mhi_uci_exit(void) + return ret_val; +}; + +static int mhi_uci_remove(struct platform_device *pdev) { + struct mhi_uci_ctxt_t *uci_ctxt = platform_get_drvdata(pdev); int i; + for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) { - cdev_del(&uci_ctxt.cdev[i]); - device_destroy(uci_ctxt.mhi_uci_class, - MKDEV(MAJOR(uci_ctxt.start_ctrl_nr), i * 2)); + struct uci_client *uci_client = &uci_ctxt->client_handles[i]; + + uci_client->uci_ctxt = uci_ctxt; + if (uci_client->in_attr.uci_ownership) { + mhi_deregister_channel(uci_client->out_handle); + mhi_deregister_channel(uci_client->in_handle); + cdev_del(&uci_ctxt->cdev[i]); + device_destroy(mhi_uci_drv_ctxt.mhi_uci_class, + MKDEV(MAJOR(uci_ctxt->dev_t), i)); + } } - class_destroy(uci_ctxt.mhi_uci_class); - unregister_chrdev_region(MAJOR(uci_ctxt.start_ctrl_nr), - MHI_MAX_SOFTWARE_CHANNELS); + + unregister_chrdev_region(MAJOR(uci_ctxt->dev_t), + MHI_SOFTWARE_CLIENT_LIMIT); + + mutex_lock(&mhi_uci_drv_ctxt.list_lock); + list_del(&uci_ctxt->node); + mutex_unlock(&mhi_uci_drv_ctxt.list_lock); + return 0; +}; + +static const struct of_device_id mhi_uci_match_table[] = { + {.compatible = "qcom,mhi-uci"}, + {}, +}; + +static struct platform_driver mhi_uci_driver = { + .probe = mhi_uci_probe, + .remove = mhi_uci_remove, + .driver = { + .name = MHI_UCI_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = mhi_uci_match_table, + }, +}; + +static int mhi_uci_init(void) +{ + mhi_uci_drv_ctxt.mhi_uci_ipc_log = + ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES, + "mhi-uci", + 0); + if (mhi_uci_drv_ctxt.mhi_uci_ipc_log == NULL) { + uci_log(NULL, + UCI_DBG_WARNING, + "Failed to create IPC logging context"); + } + + mhi_uci_drv_ctxt.mhi_uci_class = + class_create(THIS_MODULE, DEVICE_NAME); + + if (IS_ERR(mhi_uci_drv_ctxt.mhi_uci_class)) + return -ENODEV; + + mutex_init(&mhi_uci_drv_ctxt.list_lock); + INIT_LIST_HEAD(&mhi_uci_drv_ctxt.head); + + return platform_driver_register(&mhi_uci_driver); +} + +static void __exit mhi_uci_exit(void) +{ + class_destroy(mhi_uci_drv_ctxt.mhi_uci_class); + platform_driver_unregister(&mhi_uci_driver); } module_exit(mhi_uci_exit); |