Loading drivers/char/diag/diag_debugfs.c +2 −2 Original line number Diff line number Diff line Loading @@ -785,9 +785,9 @@ static ssize_t diag_dbgfs_read_mhiinfo(struct file *file, char __user *ubuf, mhi_info->name, DIAG_BRIDGE_GET_NAME(mhi_info->dev_id), DIAG_MEMPOOL_GET_NAME(mhi_info->mempool), mhi_info->read_ch.opened, atomic_read(&mhi_info->read_ch.opened), mhi_info->read_ch.hdl, mhi_info->write_ch.opened, atomic_read(&mhi_info->write_ch.opened), mhi_info->write_ch.hdl, work_pending(&mhi_info->read_work), work_pending(&mhi_info->read_done_work), Loading drivers/char/diag/diag_ipc_logging.h +2 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #define DIAG_DEBUG_PERIPHERALS 0x0008 #define DIAG_DEBUG_MASKS 0x0010 #define DIAG_DEBUG_POWER 0x0020 #define DIAG_DEBUG_BRIDGE 0x0040 #define DIAG_DEBUG #ifdef DIAG_DEBUG Loading drivers/char/diag/diagfwd_mhi.c +161 −83 Original line number Diff line number Diff line /* Copyright (c) 2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -24,9 +24,11 @@ #include <linux/delay.h> #include <linux/vmalloc.h> #include <asm/current.h> #include <linux/atomic.h> #include "diagmem.h" #include "diagfwd_bridge.h" #include "diagfwd_mhi.h" #include "diag_ipc_logging.h" #define SET_CH_CTXT(index, type) (((index & 0xFF) << 8) | (type & 0xFF)) #define GET_INFO_INDEX(val) ((val & 0xFF00) >> 8) Loading @@ -34,6 +36,8 @@ #define CHANNELS_OPENED 0 #define OPEN_CHANNELS 1 #define CHANNELS_CLOSED 0 #define CLOSE_CHANNELS 1 #define DIAG_MHI_STRING_SZ 11 Loading @@ -49,13 +53,11 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { .read_ch = { .chan = MHI_CLIENT_DIAG_IN, .type = TYPE_MHI_READ_CH, .opened = 0, .hdl = NULL, }, .write_ch = { .chan = MHI_CLIENT_DIAG_OUT, .type = TYPE_MHI_WRITE_CH, .opened = 0, .hdl = NULL, } }, Loading @@ -70,13 +72,11 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { .read_ch = { .chan = MHI_CLIENT_DCI_IN, .type = TYPE_MHI_READ_CH, .opened = 0, .hdl = NULL, }, .write_ch = { .chan = MHI_CLIENT_DCI_OUT, .type = TYPE_MHI_WRITE_CH, .opened = 0, .hdl = NULL, } } Loading @@ -85,12 +85,11 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { static int mhi_ch_open(struct diag_mhi_ch_t *ch) { int err = 0; unsigned long flags; if (!ch) return -EINVAL; if (ch->opened) { if (atomic_read(&ch->opened)) { pr_debug("diag: In %s, channel is already opened, id: %d\n", __func__, ch->type); return 0; Loading @@ -101,15 +100,14 @@ static int mhi_ch_open(struct diag_mhi_ch_t *ch) __func__, ch->type, err); return err; } spin_lock_irqsave(&ch->lock, flags); ch->opened = 1; spin_unlock_irqrestore(&ch->lock, flags); atomic_set(&ch->opened, 1); INIT_LIST_HEAD(&ch->buf_tbl); return 0; } static int mhi_buf_tbl_add(struct diag_mhi_info *mhi_info, int type, void *buf, int len) void *buf, dma_addr_t dma_addr, int len) { unsigned long flags; struct diag_mhi_buf_tbl_t *item; Loading Loading @@ -142,6 +140,7 @@ static int mhi_buf_tbl_add(struct diag_mhi_info *mhi_info, int type, spin_lock_irqsave(&ch->lock, flags); item->buf = buf; item->len = len; item->dma_addr = dma_addr; list_add_tail(&item->link, &ch->buf_tbl); spin_unlock_irqrestore(&ch->lock, flags); Loading Loading @@ -199,18 +198,20 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) struct diag_mhi_buf_tbl_t *item = NULL; struct diag_mhi_ch_t *ch = NULL; if (!mhi_info) if (!mhi_info || !mhi_info->enabled) return; /* Clear all the pending reads */ ch = &mhi_info->read_ch; /* At this point, the channel should already by closed */ if (!ch->opened) { if (!(atomic_read(&ch->opened))) { spin_lock_irqsave(&ch->lock, flags); list_for_each_safe(start, temp, &ch->buf_tbl) { item = list_entry(start, struct diag_mhi_buf_tbl_t, link); list_del(&item->link); dma_unmap_single(NULL, item->dma_addr, DIAG_MDM_BUF_SIZE, DMA_FROM_DEVICE); diagmem_free(driver, item->buf, mhi_info->mempool); kfree(item); Loading @@ -221,12 +222,14 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) /* Clear all the pending writes */ ch = &mhi_info->write_ch; /* At this point, the channel should already by closed */ if (!ch->opened) { if (!(atomic_read(&ch->opened))) { spin_lock_irqsave(&ch->lock, flags); list_for_each_safe(start, temp, &ch->buf_tbl) { item = list_entry(start, struct diag_mhi_buf_tbl_t, link); list_del(&item->link); dma_unmap_single(NULL, item->dma_addr, item->len, DMA_TO_DEVICE); diag_remote_dev_write_done(mhi_info->dev_id, item->buf, item->len, mhi_info->id); kfree(item); Loading @@ -236,69 +239,97 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) } } static int mhi_close(int id) static int __mhi_close(struct diag_mhi_info *mhi_info, int close_flag) { struct diag_mhi_info *mhi_info = NULL; unsigned long flags; if (!mhi_info) return -EIO; if (id < 0 || id >= NUM_MHI_DEV) { pr_err("diag: In %s, invalid index %d\n", __func__, id); return -EINVAL; if (!mhi_info->enabled) return -ENODEV; if (close_flag == CLOSE_CHANNELS) { atomic_set(&(mhi_info->read_ch.opened), 0); atomic_set(&(mhi_info->write_ch.opened), 0); } mhi_info = &diag_mhi[id]; if (mhi_info->read_ch.opened) { spin_lock_irqsave(&mhi_info->read_ch.lock, flags); mhi_info->read_ch.opened = 0; spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); if (!(atomic_read(&(mhi_info->read_ch.opened)))) { flush_workqueue(mhi_info->mhi_wq); mhi_close_channel(mhi_info->read_ch.hdl); } if (mhi_info->write_ch.opened) { spin_lock_irqsave(&mhi_info->write_ch.lock, flags); mhi_info->write_ch.opened = 0; spin_unlock_irqrestore(&mhi_info->write_ch.lock, flags); if (!(atomic_read(&(mhi_info->write_ch.opened)))) { flush_workqueue(mhi_info->mhi_wq); mhi_close_channel(mhi_info->write_ch.hdl); } mhi_buf_tbl_clear(mhi_info); diag_remote_dev_close(mhi_info->dev_id); return 0; } static int mhi_close(int id) { if (id < 0 || id >= NUM_MHI_DEV) { pr_err("diag: In %s, invalid index %d\n", __func__, id); return -EINVAL; } if (!diag_mhi[id].enabled) return -ENODEV; /* * This function is called whenever the channel needs to be closed * explicitly by Diag. Close both the read and write channels (denoted * by CLOSE_CHANNELS flag) */ return __mhi_close(&diag_mhi[id], CLOSE_CHANNELS); } static void mhi_close_work_fn(struct work_struct *work) { struct diag_mhi_info *mhi_info = container_of(work, struct diag_mhi_info, close_work); /* * This is a part of work function which is queued after the channels * are explicitly closed. Do not close channels again (denoted by * CHANNELS_CLOSED flag) */ if (mhi_info) mhi_close(mhi_info->id); __mhi_close(mhi_info, CHANNELS_CLOSED); } static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) { int err = 0; int tbl_size = 0; unsigned long flags; if (!mhi_info) return -EIO; if (open_flag == OPEN_CHANNELS) { if (!mhi_info->read_ch.opened) { if (!atomic_read(&mhi_info->read_ch.opened)) { err = mhi_ch_open(&mhi_info->read_ch); if (err) goto fail; DIAG_LOG(DIAG_DEBUG_BRIDGE, "opened mhi read channel, port: %d\n", mhi_info->id); } if (!mhi_info->write_ch.opened) { if (!atomic_read(&mhi_info->write_ch.opened)) { err = mhi_ch_open(&mhi_info->write_ch); if (err) goto fail; DIAG_LOG(DIAG_DEBUG_BRIDGE, "opened mhi write channel, port: %d\n", mhi_info->id); } } else if (open_flag == CHANNELS_OPENED) { if (!mhi_info->read_ch.opened || !mhi_info->write_ch.opened) if (!atomic_read(&(mhi_info->read_ch.opened)) || !atomic_read(&(mhi_info->write_ch.opened))) { return -ENODEV; } } tbl_size = sizeof(void *) * diag_mempools[mhi_info->mempool].poolsize; spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 1; spin_unlock_irqrestore(&mhi_info->lock, flags); Loading @@ -307,6 +338,7 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) return 0; fail: pr_err("diag: Failed to open mhi channlels, err: %d\n", err); mhi_close(mhi_info->id); return err; } Loading @@ -325,7 +357,11 @@ static int mhi_open(int id) * explicitly by Diag. Open both the read and write channels (denoted by * OPEN_CHANNELS flag) */ return __mhi_open(&diag_mhi[id], OPEN_CHANNELS); __mhi_open(&diag_mhi[id], OPEN_CHANNELS); diag_remote_dev_open(diag_mhi[id].dev_id); queue_work(diag_mhi[id].mhi_wq, &(diag_mhi[id].read_work)); return 0; } static void mhi_open_work_fn(struct work_struct *work) Loading @@ -338,8 +374,10 @@ static void mhi_open_work_fn(struct work_struct *work) * are explicitly opened. Do not open channels again (denoted by * CHANNELS_OPENED flag) */ if (mhi_info) __mhi_open(mhi_info, CHANNELS_OPENED); if (mhi_info) { diag_remote_dev_open(mhi_info->dev_id); queue_work(mhi_info->mhi_wq, &(mhi_info->read_work)); } } static void mhi_read_done_work_fn(struct work_struct *work) Loading @@ -355,6 +393,8 @@ static void mhi_read_done_work_fn(struct work_struct *work) return; do { if (!(atomic_read(&(mhi_info->read_ch.opened)))) break; err = mhi_poll_inbound(mhi_info->read_ch.hdl, &result); if (err) { pr_debug("diag: In %s, err %d\n", __func__, err); Loading @@ -366,8 +406,21 @@ static void mhi_read_done_work_fn(struct work_struct *work) dma_unmap_single(NULL, result.payload_buf, result.bytes_xferd, DMA_FROM_DEVICE); buf = dma_to_virt(NULL, result.payload_buf); DIAG_LOG(DIAG_DEBUG_BRIDGE, "read from mhi port %d buf %p unmapped from %u\n", mhi_info->id, buf, result.payload_buf); /* * The read buffers can come after the MHI channels are closed. * If the channels are closed at the time of read, discard the * buffers here and do not forward them to the mux layer. */ if ((atomic_read(&(mhi_info->read_ch.opened)))) { diag_remote_dev_read_done(mhi_info->dev_id, buf, result.bytes_xferd); } else { mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, result.bytes_xferd); } } while (phy_buf); } Loading @@ -376,44 +429,54 @@ static void mhi_read_work_fn(struct work_struct *work) int err = 0; unsigned char *buf = NULL; dma_addr_t dma_addr; enum MHI_FLAGS flags = MHI_EOT; enum MHI_FLAGS mhi_flags = MHI_EOT; struct diag_mhi_ch_t *read_ch = NULL; unsigned long flags; struct diag_mhi_info *mhi_info = container_of(work, struct diag_mhi_info, read_work); if (!mhi_info || !mhi_info->read_ch.opened) if (!mhi_info) return; read_ch = &mhi_info->read_ch; if (!read_ch->opened) return; do { if (!(atomic_read(&(read_ch->opened)))) break; buf = diagmem_alloc(driver, DIAG_MDM_BUF_SIZE, mhi_info->mempool); buf = diagmem_alloc(driver, DIAG_MDM_BUF_SIZE, mhi_info->mempool); if (!buf) return; break; err = mhi_buf_tbl_add(mhi_info, TYPE_MHI_READ_CH, buf, dma_addr = dma_map_single(NULL, buf, DIAG_MDM_BUF_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(NULL, dma_addr)) panic("ASSERT"); err = mhi_buf_tbl_add(mhi_info, TYPE_MHI_READ_CH, buf, dma_addr, DIAG_MDM_BUF_SIZE); if (err) goto fail; dma_addr = dma_map_single(NULL, buf, DIAG_MDM_BUF_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(NULL, dma_addr)) goto fail; err = mhi_queue_xfer(read_ch->hdl, dma_addr, DIAG_MDM_BUF_SIZE, flags); DIAG_LOG(DIAG_DEBUG_BRIDGE, "queueing a read buf %p mapped to 0x%x, ch: %s\n", buf, dma_addr, mhi_info->name); spin_lock_irqsave(&read_ch->lock, flags); err = mhi_queue_xfer(read_ch->hdl, dma_addr, DIAG_MDM_BUF_SIZE, mhi_flags); spin_unlock_irqrestore(&read_ch->lock, flags); if (err) { pr_err_ratelimited("diag: Unable to read from MHI channel %s, err: %d\n", mhi_info->name, err); dma_unmap_single(NULL, dma_addr, DIAG_MDM_BUF_SIZE, DMA_TO_DEVICE); buf = dma_to_virt(NULL, dma_addr); goto fail; } } while (buf); queue_work(mhi_info->mhi_wq, &mhi_info->read_work); return; fail: dma_unmap_single(NULL, dma_addr, DIAG_MDM_BUF_SIZE, DMA_FROM_DEVICE); buf = dma_to_virt(NULL, dma_addr); mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, DIAG_MDM_BUF_SIZE); queue_work(mhi_info->mhi_wq, &mhi_info->read_work); } Loading @@ -432,7 +495,8 @@ static int mhi_queue_read(int id) static int mhi_write(int id, unsigned char *buf, int len, int ctxt) { int err = 0; enum MHI_FLAGS flags = MHI_EOT; enum MHI_FLAGS mhi_flags = MHI_EOT; unsigned long flags; dma_addr_t dma_addr = 0; struct diag_mhi_ch_t *ch = NULL; Loading @@ -455,31 +519,35 @@ static int mhi_write(int id, unsigned char *buf, int len, int ctxt) } ch = &diag_mhi[id].write_ch; if (!ch->opened) { if (!(atomic_read(&(ch->opened)))) { pr_err_ratelimited("diag: In %s, MHI write channel %s is not open\n", __func__, diag_mhi[id].name); return -EIO; } err = mhi_buf_tbl_add(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, len); if (err) return err; dma_addr = dma_map_single(NULL, buf, len, DMA_TO_DEVICE); if (dma_mapping_error(NULL, dma_addr)) { mhi_buf_tbl_remove(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, len); return -ENOMEM; } if (dma_mapping_error(NULL, dma_addr)) panic("ASSERT"); err = mhi_buf_tbl_add(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, dma_addr, len); if (err) goto fail; err = mhi_queue_xfer(ch->hdl, dma_addr, len, flags); DIAG_LOG(DIAG_DEBUG_BRIDGE, "buf %p mapped to %u\n", buf, dma_addr); spin_lock_irqsave(&ch->lock, flags); err = mhi_queue_xfer(ch->hdl, dma_addr, len, mhi_flags); spin_unlock_irqrestore(&ch->lock, flags); if (err) { pr_err_ratelimited("diag: In %s, cannot write to MHI channel %p, len %d, err: %d\n", __func__, diag_mhi[id].name, len, err); dma_unmap_single(NULL, (dma_addr_t)dma_addr, len, DMA_TO_DEVICE); mhi_buf_tbl_remove(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, len); goto fail; } return 0; fail: dma_unmap_single(NULL, dma_addr, len, DMA_TO_DEVICE); return err; } Loading Loading @@ -540,6 +608,9 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) switch (cb_info->cb_reason) { case MHI_CB_MHI_ENABLED: DIAG_LOG(DIAG_DEBUG_BRIDGE, "received mhi enabled notifiation port: %d ch: %d\n", index, ch->type); err = mhi_ch_open(ch); if (err) break; Loading @@ -550,17 +621,17 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) __func__, diag_mhi[index].num_read); break; } diagmem_init(driver, diag_mhi[index].mempool); } __mhi_open(&diag_mhi[index], CHANNELS_OPENED); queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].open_work)); break; case MHI_CB_MHI_DISABLED: ch->opened = 0; if (ch->type == TYPE_MHI_READ_CH) diagmem_exit(driver, diag_mhi[index].mempool); queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].close_work)); DIAG_LOG(DIAG_DEBUG_BRIDGE, "received mhi disabled notifiation port: %d ch: %d\n", index, ch->type); atomic_set(&(ch->opened), 0); __mhi_close(&diag_mhi[index], CHANNELS_CLOSED); break; case MHI_CB_XFER: /* Loading @@ -569,6 +640,9 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) * a write channel. */ if (type == TYPE_MHI_READ_CH) { if (!atomic_read(&(diag_mhi[index].read_ch.opened))) break; queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].read_done_work)); break; Loading Loading @@ -612,6 +686,7 @@ static int diag_mhi_register_ch(int id, struct diag_mhi_ch_t *ch) if (id < 0 || id >= NUM_MHI_DEV) return -EINVAL; spin_lock_init(&ch->lock); atomic_set(&(ch->opened), 0); ctxt = SET_CH_CTXT(id, ch->type); ch->client_info.mhi_client_cb = mhi_notifier; return mhi_register_channel(&ch->hdl, ch->chan, 0, &ch->client_info, Loading @@ -634,6 +709,7 @@ int diag_mhi_init() INIT_WORK(&(mhi_info->close_work), mhi_close_work_fn); strlcpy(wq_name, "diag_mhi_", DIAG_MHI_STRING_SZ); strlcat(wq_name, mhi_info->name, sizeof(mhi_info->name)); diagmem_init(driver, mhi_info->mempool); mhi_info->mhi_wq = create_singlethread_workqueue(wq_name); if (!mhi_info->mhi_wq) goto fail; Loading @@ -656,6 +732,7 @@ int diag_mhi_init() i, err); goto fail; } DIAG_LOG(DIAG_DEBUG_BRIDGE, "mhi port %d is initailzed\n", i); } return 0; Loading @@ -674,6 +751,7 @@ void diag_mhi_exit() if (mhi_info->mhi_wq) destroy_workqueue(mhi_info->mhi_wq); mhi_close(mhi_info->id); diagmem_exit(driver, mhi_info->mempool); } } drivers/char/diag/diagfwd_mhi.h +4 −3 Original line number Diff line number Diff line /* Copyright (c) 2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -45,16 +45,17 @@ #define DIAG_MHI_NAME_SZ 24 struct diag_mhi_buf_tbl_t { struct list_head link; unsigned char *buf; dma_addr_t dma_addr; int len; struct list_head link; }; struct diag_mhi_ch_t { uint8_t type; u32 channel; enum MHI_CLIENT_CHANNEL chan; uint8_t opened; atomic_t opened; spinlock_t lock; struct mhi_client_info_t client_info; struct mhi_client_handle *hdl; Loading Loading
drivers/char/diag/diag_debugfs.c +2 −2 Original line number Diff line number Diff line Loading @@ -785,9 +785,9 @@ static ssize_t diag_dbgfs_read_mhiinfo(struct file *file, char __user *ubuf, mhi_info->name, DIAG_BRIDGE_GET_NAME(mhi_info->dev_id), DIAG_MEMPOOL_GET_NAME(mhi_info->mempool), mhi_info->read_ch.opened, atomic_read(&mhi_info->read_ch.opened), mhi_info->read_ch.hdl, mhi_info->write_ch.opened, atomic_read(&mhi_info->write_ch.opened), mhi_info->write_ch.hdl, work_pending(&mhi_info->read_work), work_pending(&mhi_info->read_done_work), Loading
drivers/char/diag/diag_ipc_logging.h +2 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #define DIAG_DEBUG_PERIPHERALS 0x0008 #define DIAG_DEBUG_MASKS 0x0010 #define DIAG_DEBUG_POWER 0x0020 #define DIAG_DEBUG_BRIDGE 0x0040 #define DIAG_DEBUG #ifdef DIAG_DEBUG Loading
drivers/char/diag/diagfwd_mhi.c +161 −83 Original line number Diff line number Diff line /* Copyright (c) 2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -24,9 +24,11 @@ #include <linux/delay.h> #include <linux/vmalloc.h> #include <asm/current.h> #include <linux/atomic.h> #include "diagmem.h" #include "diagfwd_bridge.h" #include "diagfwd_mhi.h" #include "diag_ipc_logging.h" #define SET_CH_CTXT(index, type) (((index & 0xFF) << 8) | (type & 0xFF)) #define GET_INFO_INDEX(val) ((val & 0xFF00) >> 8) Loading @@ -34,6 +36,8 @@ #define CHANNELS_OPENED 0 #define OPEN_CHANNELS 1 #define CHANNELS_CLOSED 0 #define CLOSE_CHANNELS 1 #define DIAG_MHI_STRING_SZ 11 Loading @@ -49,13 +53,11 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { .read_ch = { .chan = MHI_CLIENT_DIAG_IN, .type = TYPE_MHI_READ_CH, .opened = 0, .hdl = NULL, }, .write_ch = { .chan = MHI_CLIENT_DIAG_OUT, .type = TYPE_MHI_WRITE_CH, .opened = 0, .hdl = NULL, } }, Loading @@ -70,13 +72,11 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { .read_ch = { .chan = MHI_CLIENT_DCI_IN, .type = TYPE_MHI_READ_CH, .opened = 0, .hdl = NULL, }, .write_ch = { .chan = MHI_CLIENT_DCI_OUT, .type = TYPE_MHI_WRITE_CH, .opened = 0, .hdl = NULL, } } Loading @@ -85,12 +85,11 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { static int mhi_ch_open(struct diag_mhi_ch_t *ch) { int err = 0; unsigned long flags; if (!ch) return -EINVAL; if (ch->opened) { if (atomic_read(&ch->opened)) { pr_debug("diag: In %s, channel is already opened, id: %d\n", __func__, ch->type); return 0; Loading @@ -101,15 +100,14 @@ static int mhi_ch_open(struct diag_mhi_ch_t *ch) __func__, ch->type, err); return err; } spin_lock_irqsave(&ch->lock, flags); ch->opened = 1; spin_unlock_irqrestore(&ch->lock, flags); atomic_set(&ch->opened, 1); INIT_LIST_HEAD(&ch->buf_tbl); return 0; } static int mhi_buf_tbl_add(struct diag_mhi_info *mhi_info, int type, void *buf, int len) void *buf, dma_addr_t dma_addr, int len) { unsigned long flags; struct diag_mhi_buf_tbl_t *item; Loading Loading @@ -142,6 +140,7 @@ static int mhi_buf_tbl_add(struct diag_mhi_info *mhi_info, int type, spin_lock_irqsave(&ch->lock, flags); item->buf = buf; item->len = len; item->dma_addr = dma_addr; list_add_tail(&item->link, &ch->buf_tbl); spin_unlock_irqrestore(&ch->lock, flags); Loading Loading @@ -199,18 +198,20 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) struct diag_mhi_buf_tbl_t *item = NULL; struct diag_mhi_ch_t *ch = NULL; if (!mhi_info) if (!mhi_info || !mhi_info->enabled) return; /* Clear all the pending reads */ ch = &mhi_info->read_ch; /* At this point, the channel should already by closed */ if (!ch->opened) { if (!(atomic_read(&ch->opened))) { spin_lock_irqsave(&ch->lock, flags); list_for_each_safe(start, temp, &ch->buf_tbl) { item = list_entry(start, struct diag_mhi_buf_tbl_t, link); list_del(&item->link); dma_unmap_single(NULL, item->dma_addr, DIAG_MDM_BUF_SIZE, DMA_FROM_DEVICE); diagmem_free(driver, item->buf, mhi_info->mempool); kfree(item); Loading @@ -221,12 +222,14 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) /* Clear all the pending writes */ ch = &mhi_info->write_ch; /* At this point, the channel should already by closed */ if (!ch->opened) { if (!(atomic_read(&ch->opened))) { spin_lock_irqsave(&ch->lock, flags); list_for_each_safe(start, temp, &ch->buf_tbl) { item = list_entry(start, struct diag_mhi_buf_tbl_t, link); list_del(&item->link); dma_unmap_single(NULL, item->dma_addr, item->len, DMA_TO_DEVICE); diag_remote_dev_write_done(mhi_info->dev_id, item->buf, item->len, mhi_info->id); kfree(item); Loading @@ -236,69 +239,97 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) } } static int mhi_close(int id) static int __mhi_close(struct diag_mhi_info *mhi_info, int close_flag) { struct diag_mhi_info *mhi_info = NULL; unsigned long flags; if (!mhi_info) return -EIO; if (id < 0 || id >= NUM_MHI_DEV) { pr_err("diag: In %s, invalid index %d\n", __func__, id); return -EINVAL; if (!mhi_info->enabled) return -ENODEV; if (close_flag == CLOSE_CHANNELS) { atomic_set(&(mhi_info->read_ch.opened), 0); atomic_set(&(mhi_info->write_ch.opened), 0); } mhi_info = &diag_mhi[id]; if (mhi_info->read_ch.opened) { spin_lock_irqsave(&mhi_info->read_ch.lock, flags); mhi_info->read_ch.opened = 0; spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); if (!(atomic_read(&(mhi_info->read_ch.opened)))) { flush_workqueue(mhi_info->mhi_wq); mhi_close_channel(mhi_info->read_ch.hdl); } if (mhi_info->write_ch.opened) { spin_lock_irqsave(&mhi_info->write_ch.lock, flags); mhi_info->write_ch.opened = 0; spin_unlock_irqrestore(&mhi_info->write_ch.lock, flags); if (!(atomic_read(&(mhi_info->write_ch.opened)))) { flush_workqueue(mhi_info->mhi_wq); mhi_close_channel(mhi_info->write_ch.hdl); } mhi_buf_tbl_clear(mhi_info); diag_remote_dev_close(mhi_info->dev_id); return 0; } static int mhi_close(int id) { if (id < 0 || id >= NUM_MHI_DEV) { pr_err("diag: In %s, invalid index %d\n", __func__, id); return -EINVAL; } if (!diag_mhi[id].enabled) return -ENODEV; /* * This function is called whenever the channel needs to be closed * explicitly by Diag. Close both the read and write channels (denoted * by CLOSE_CHANNELS flag) */ return __mhi_close(&diag_mhi[id], CLOSE_CHANNELS); } static void mhi_close_work_fn(struct work_struct *work) { struct diag_mhi_info *mhi_info = container_of(work, struct diag_mhi_info, close_work); /* * This is a part of work function which is queued after the channels * are explicitly closed. Do not close channels again (denoted by * CHANNELS_CLOSED flag) */ if (mhi_info) mhi_close(mhi_info->id); __mhi_close(mhi_info, CHANNELS_CLOSED); } static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) { int err = 0; int tbl_size = 0; unsigned long flags; if (!mhi_info) return -EIO; if (open_flag == OPEN_CHANNELS) { if (!mhi_info->read_ch.opened) { if (!atomic_read(&mhi_info->read_ch.opened)) { err = mhi_ch_open(&mhi_info->read_ch); if (err) goto fail; DIAG_LOG(DIAG_DEBUG_BRIDGE, "opened mhi read channel, port: %d\n", mhi_info->id); } if (!mhi_info->write_ch.opened) { if (!atomic_read(&mhi_info->write_ch.opened)) { err = mhi_ch_open(&mhi_info->write_ch); if (err) goto fail; DIAG_LOG(DIAG_DEBUG_BRIDGE, "opened mhi write channel, port: %d\n", mhi_info->id); } } else if (open_flag == CHANNELS_OPENED) { if (!mhi_info->read_ch.opened || !mhi_info->write_ch.opened) if (!atomic_read(&(mhi_info->read_ch.opened)) || !atomic_read(&(mhi_info->write_ch.opened))) { return -ENODEV; } } tbl_size = sizeof(void *) * diag_mempools[mhi_info->mempool].poolsize; spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 1; spin_unlock_irqrestore(&mhi_info->lock, flags); Loading @@ -307,6 +338,7 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) return 0; fail: pr_err("diag: Failed to open mhi channlels, err: %d\n", err); mhi_close(mhi_info->id); return err; } Loading @@ -325,7 +357,11 @@ static int mhi_open(int id) * explicitly by Diag. Open both the read and write channels (denoted by * OPEN_CHANNELS flag) */ return __mhi_open(&diag_mhi[id], OPEN_CHANNELS); __mhi_open(&diag_mhi[id], OPEN_CHANNELS); diag_remote_dev_open(diag_mhi[id].dev_id); queue_work(diag_mhi[id].mhi_wq, &(diag_mhi[id].read_work)); return 0; } static void mhi_open_work_fn(struct work_struct *work) Loading @@ -338,8 +374,10 @@ static void mhi_open_work_fn(struct work_struct *work) * are explicitly opened. Do not open channels again (denoted by * CHANNELS_OPENED flag) */ if (mhi_info) __mhi_open(mhi_info, CHANNELS_OPENED); if (mhi_info) { diag_remote_dev_open(mhi_info->dev_id); queue_work(mhi_info->mhi_wq, &(mhi_info->read_work)); } } static void mhi_read_done_work_fn(struct work_struct *work) Loading @@ -355,6 +393,8 @@ static void mhi_read_done_work_fn(struct work_struct *work) return; do { if (!(atomic_read(&(mhi_info->read_ch.opened)))) break; err = mhi_poll_inbound(mhi_info->read_ch.hdl, &result); if (err) { pr_debug("diag: In %s, err %d\n", __func__, err); Loading @@ -366,8 +406,21 @@ static void mhi_read_done_work_fn(struct work_struct *work) dma_unmap_single(NULL, result.payload_buf, result.bytes_xferd, DMA_FROM_DEVICE); buf = dma_to_virt(NULL, result.payload_buf); DIAG_LOG(DIAG_DEBUG_BRIDGE, "read from mhi port %d buf %p unmapped from %u\n", mhi_info->id, buf, result.payload_buf); /* * The read buffers can come after the MHI channels are closed. * If the channels are closed at the time of read, discard the * buffers here and do not forward them to the mux layer. */ if ((atomic_read(&(mhi_info->read_ch.opened)))) { diag_remote_dev_read_done(mhi_info->dev_id, buf, result.bytes_xferd); } else { mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, result.bytes_xferd); } } while (phy_buf); } Loading @@ -376,44 +429,54 @@ static void mhi_read_work_fn(struct work_struct *work) int err = 0; unsigned char *buf = NULL; dma_addr_t dma_addr; enum MHI_FLAGS flags = MHI_EOT; enum MHI_FLAGS mhi_flags = MHI_EOT; struct diag_mhi_ch_t *read_ch = NULL; unsigned long flags; struct diag_mhi_info *mhi_info = container_of(work, struct diag_mhi_info, read_work); if (!mhi_info || !mhi_info->read_ch.opened) if (!mhi_info) return; read_ch = &mhi_info->read_ch; if (!read_ch->opened) return; do { if (!(atomic_read(&(read_ch->opened)))) break; buf = diagmem_alloc(driver, DIAG_MDM_BUF_SIZE, mhi_info->mempool); buf = diagmem_alloc(driver, DIAG_MDM_BUF_SIZE, mhi_info->mempool); if (!buf) return; break; err = mhi_buf_tbl_add(mhi_info, TYPE_MHI_READ_CH, buf, dma_addr = dma_map_single(NULL, buf, DIAG_MDM_BUF_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(NULL, dma_addr)) panic("ASSERT"); err = mhi_buf_tbl_add(mhi_info, TYPE_MHI_READ_CH, buf, dma_addr, DIAG_MDM_BUF_SIZE); if (err) goto fail; dma_addr = dma_map_single(NULL, buf, DIAG_MDM_BUF_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(NULL, dma_addr)) goto fail; err = mhi_queue_xfer(read_ch->hdl, dma_addr, DIAG_MDM_BUF_SIZE, flags); DIAG_LOG(DIAG_DEBUG_BRIDGE, "queueing a read buf %p mapped to 0x%x, ch: %s\n", buf, dma_addr, mhi_info->name); spin_lock_irqsave(&read_ch->lock, flags); err = mhi_queue_xfer(read_ch->hdl, dma_addr, DIAG_MDM_BUF_SIZE, mhi_flags); spin_unlock_irqrestore(&read_ch->lock, flags); if (err) { pr_err_ratelimited("diag: Unable to read from MHI channel %s, err: %d\n", mhi_info->name, err); dma_unmap_single(NULL, dma_addr, DIAG_MDM_BUF_SIZE, DMA_TO_DEVICE); buf = dma_to_virt(NULL, dma_addr); goto fail; } } while (buf); queue_work(mhi_info->mhi_wq, &mhi_info->read_work); return; fail: dma_unmap_single(NULL, dma_addr, DIAG_MDM_BUF_SIZE, DMA_FROM_DEVICE); buf = dma_to_virt(NULL, dma_addr); mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, DIAG_MDM_BUF_SIZE); queue_work(mhi_info->mhi_wq, &mhi_info->read_work); } Loading @@ -432,7 +495,8 @@ static int mhi_queue_read(int id) static int mhi_write(int id, unsigned char *buf, int len, int ctxt) { int err = 0; enum MHI_FLAGS flags = MHI_EOT; enum MHI_FLAGS mhi_flags = MHI_EOT; unsigned long flags; dma_addr_t dma_addr = 0; struct diag_mhi_ch_t *ch = NULL; Loading @@ -455,31 +519,35 @@ static int mhi_write(int id, unsigned char *buf, int len, int ctxt) } ch = &diag_mhi[id].write_ch; if (!ch->opened) { if (!(atomic_read(&(ch->opened)))) { pr_err_ratelimited("diag: In %s, MHI write channel %s is not open\n", __func__, diag_mhi[id].name); return -EIO; } err = mhi_buf_tbl_add(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, len); if (err) return err; dma_addr = dma_map_single(NULL, buf, len, DMA_TO_DEVICE); if (dma_mapping_error(NULL, dma_addr)) { mhi_buf_tbl_remove(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, len); return -ENOMEM; } if (dma_mapping_error(NULL, dma_addr)) panic("ASSERT"); err = mhi_buf_tbl_add(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, dma_addr, len); if (err) goto fail; err = mhi_queue_xfer(ch->hdl, dma_addr, len, flags); DIAG_LOG(DIAG_DEBUG_BRIDGE, "buf %p mapped to %u\n", buf, dma_addr); spin_lock_irqsave(&ch->lock, flags); err = mhi_queue_xfer(ch->hdl, dma_addr, len, mhi_flags); spin_unlock_irqrestore(&ch->lock, flags); if (err) { pr_err_ratelimited("diag: In %s, cannot write to MHI channel %p, len %d, err: %d\n", __func__, diag_mhi[id].name, len, err); dma_unmap_single(NULL, (dma_addr_t)dma_addr, len, DMA_TO_DEVICE); mhi_buf_tbl_remove(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, len); goto fail; } return 0; fail: dma_unmap_single(NULL, dma_addr, len, DMA_TO_DEVICE); return err; } Loading Loading @@ -540,6 +608,9 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) switch (cb_info->cb_reason) { case MHI_CB_MHI_ENABLED: DIAG_LOG(DIAG_DEBUG_BRIDGE, "received mhi enabled notifiation port: %d ch: %d\n", index, ch->type); err = mhi_ch_open(ch); if (err) break; Loading @@ -550,17 +621,17 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) __func__, diag_mhi[index].num_read); break; } diagmem_init(driver, diag_mhi[index].mempool); } __mhi_open(&diag_mhi[index], CHANNELS_OPENED); queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].open_work)); break; case MHI_CB_MHI_DISABLED: ch->opened = 0; if (ch->type == TYPE_MHI_READ_CH) diagmem_exit(driver, diag_mhi[index].mempool); queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].close_work)); DIAG_LOG(DIAG_DEBUG_BRIDGE, "received mhi disabled notifiation port: %d ch: %d\n", index, ch->type); atomic_set(&(ch->opened), 0); __mhi_close(&diag_mhi[index], CHANNELS_CLOSED); break; case MHI_CB_XFER: /* Loading @@ -569,6 +640,9 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) * a write channel. */ if (type == TYPE_MHI_READ_CH) { if (!atomic_read(&(diag_mhi[index].read_ch.opened))) break; queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].read_done_work)); break; Loading Loading @@ -612,6 +686,7 @@ static int diag_mhi_register_ch(int id, struct diag_mhi_ch_t *ch) if (id < 0 || id >= NUM_MHI_DEV) return -EINVAL; spin_lock_init(&ch->lock); atomic_set(&(ch->opened), 0); ctxt = SET_CH_CTXT(id, ch->type); ch->client_info.mhi_client_cb = mhi_notifier; return mhi_register_channel(&ch->hdl, ch->chan, 0, &ch->client_info, Loading @@ -634,6 +709,7 @@ int diag_mhi_init() INIT_WORK(&(mhi_info->close_work), mhi_close_work_fn); strlcpy(wq_name, "diag_mhi_", DIAG_MHI_STRING_SZ); strlcat(wq_name, mhi_info->name, sizeof(mhi_info->name)); diagmem_init(driver, mhi_info->mempool); mhi_info->mhi_wq = create_singlethread_workqueue(wq_name); if (!mhi_info->mhi_wq) goto fail; Loading @@ -656,6 +732,7 @@ int diag_mhi_init() i, err); goto fail; } DIAG_LOG(DIAG_DEBUG_BRIDGE, "mhi port %d is initailzed\n", i); } return 0; Loading @@ -674,6 +751,7 @@ void diag_mhi_exit() if (mhi_info->mhi_wq) destroy_workqueue(mhi_info->mhi_wq); mhi_close(mhi_info->id); diagmem_exit(driver, mhi_info->mempool); } }
drivers/char/diag/diagfwd_mhi.h +4 −3 Original line number Diff line number Diff line /* Copyright (c) 2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -45,16 +45,17 @@ #define DIAG_MHI_NAME_SZ 24 struct diag_mhi_buf_tbl_t { struct list_head link; unsigned char *buf; dma_addr_t dma_addr; int len; struct list_head link; }; struct diag_mhi_ch_t { uint8_t type; u32 channel; enum MHI_CLIENT_CHANNEL chan; uint8_t opened; atomic_t opened; spinlock_t lock; struct mhi_client_info_t client_info; struct mhi_client_handle *hdl; Loading