Skip to content

Commit 189ff97

Browse files
Mani-Sadhasivamgregkh
authored andcommitted
bus: mhi: core: Add support for data transfer
Add support for transferring data between external modem and host processor using MHI protocol. This is based on the patch submitted by Sujeev Dias: https://lkml.org/lkml/2018/7/9/988 Signed-off-by: Sujeev Dias <[email protected]> Signed-off-by: Siddartha Mohanadoss <[email protected]> [mani: splitted the data transfer patch and cleaned up for upstream] Signed-off-by: Manivannan Sadhasivam <[email protected]> Reviewed-by: Jeffrey Hugo <[email protected]> Tested-by: Jeffrey Hugo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 1d3173a commit 189ff97

File tree

5 files changed

+979
-8
lines changed

5 files changed

+979
-8
lines changed

drivers/bus/mhi/core/init.c

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,73 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
491491
return 0;
492492
}
493493

494+
void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
495+
struct mhi_chan *mhi_chan)
496+
{
497+
struct mhi_ring *buf_ring;
498+
struct mhi_ring *tre_ring;
499+
struct mhi_chan_ctxt *chan_ctxt;
500+
501+
buf_ring = &mhi_chan->buf_ring;
502+
tre_ring = &mhi_chan->tre_ring;
503+
chan_ctxt = &mhi_cntrl->mhi_ctxt->chan_ctxt[mhi_chan->chan];
504+
505+
mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size,
506+
tre_ring->pre_aligned, tre_ring->dma_handle);
507+
vfree(buf_ring->base);
508+
509+
buf_ring->base = tre_ring->base = NULL;
510+
chan_ctxt->rbase = 0;
511+
}
512+
513+
int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
514+
struct mhi_chan *mhi_chan)
515+
{
516+
struct mhi_ring *buf_ring;
517+
struct mhi_ring *tre_ring;
518+
struct mhi_chan_ctxt *chan_ctxt;
519+
u32 tmp;
520+
int ret;
521+
522+
buf_ring = &mhi_chan->buf_ring;
523+
tre_ring = &mhi_chan->tre_ring;
524+
tre_ring->el_size = sizeof(struct mhi_tre);
525+
tre_ring->len = tre_ring->el_size * tre_ring->elements;
526+
chan_ctxt = &mhi_cntrl->mhi_ctxt->chan_ctxt[mhi_chan->chan];
527+
ret = mhi_alloc_aligned_ring(mhi_cntrl, tre_ring, tre_ring->len);
528+
if (ret)
529+
return -ENOMEM;
530+
531+
buf_ring->el_size = sizeof(struct mhi_buf_info);
532+
buf_ring->len = buf_ring->el_size * buf_ring->elements;
533+
buf_ring->base = vzalloc(buf_ring->len);
534+
535+
if (!buf_ring->base) {
536+
mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size,
537+
tre_ring->pre_aligned, tre_ring->dma_handle);
538+
return -ENOMEM;
539+
}
540+
541+
tmp = chan_ctxt->chcfg;
542+
tmp &= ~CHAN_CTX_CHSTATE_MASK;
543+
tmp |= (MHI_CH_STATE_ENABLED << CHAN_CTX_CHSTATE_SHIFT);
544+
chan_ctxt->chcfg = tmp;
545+
546+
chan_ctxt->rbase = tre_ring->iommu_base;
547+
chan_ctxt->rp = chan_ctxt->wp = chan_ctxt->rbase;
548+
chan_ctxt->rlen = tre_ring->len;
549+
tre_ring->ctxt_wp = &chan_ctxt->wp;
550+
551+
tre_ring->rp = tre_ring->wp = tre_ring->base;
552+
buf_ring->rp = buf_ring->wp = buf_ring->base;
553+
mhi_chan->db_cfg.db_mode = 1;
554+
555+
/* Update to all cores */
556+
smp_wmb();
557+
558+
return 0;
559+
}
560+
494561
static int parse_ev_cfg(struct mhi_controller *mhi_cntrl,
495562
struct mhi_controller_config *config)
496563
{
@@ -799,6 +866,14 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
799866
rwlock_init(&mhi_chan->lock);
800867
}
801868

869+
if (mhi_cntrl->bounce_buf) {
870+
mhi_cntrl->map_single = mhi_map_single_use_bb;
871+
mhi_cntrl->unmap_single = mhi_unmap_single_use_bb;
872+
} else {
873+
mhi_cntrl->map_single = mhi_map_single_no_bb;
874+
mhi_cntrl->unmap_single = mhi_unmap_single_no_bb;
875+
}
876+
802877
/* Register controller with MHI bus */
803878
mhi_dev = mhi_alloc_device(mhi_cntrl);
804879
if (IS_ERR(mhi_dev)) {
@@ -969,20 +1044,33 @@ static int mhi_driver_probe(struct device *dev)
9691044
struct mhi_event *mhi_event;
9701045
struct mhi_chan *ul_chan = mhi_dev->ul_chan;
9711046
struct mhi_chan *dl_chan = mhi_dev->dl_chan;
1047+
int ret;
1048+
1049+
/* Bring device out of LPM */
1050+
ret = mhi_device_get_sync(mhi_dev);
1051+
if (ret)
1052+
return ret;
1053+
1054+
ret = -EINVAL;
9721055

9731056
if (ul_chan) {
9741057
/*
9751058
* If channel supports LPM notifications then status_cb should
9761059
* be provided
9771060
*/
9781061
if (ul_chan->lpm_notify && !mhi_drv->status_cb)
979-
return -EINVAL;
1062+
goto exit_probe;
9801063

9811064
/* For non-offload channels then xfer_cb should be provided */
9821065
if (!ul_chan->offload_ch && !mhi_drv->ul_xfer_cb)
983-
return -EINVAL;
1066+
goto exit_probe;
9841067

9851068
ul_chan->xfer_cb = mhi_drv->ul_xfer_cb;
1069+
if (ul_chan->auto_start) {
1070+
ret = mhi_prepare_channel(mhi_cntrl, ul_chan);
1071+
if (ret)
1072+
goto exit_probe;
1073+
}
9861074
}
9871075

9881076
if (dl_chan) {
@@ -991,11 +1079,11 @@ static int mhi_driver_probe(struct device *dev)
9911079
* be provided
9921080
*/
9931081
if (dl_chan->lpm_notify && !mhi_drv->status_cb)
994-
return -EINVAL;
1082+
goto exit_probe;
9951083

9961084
/* For non-offload channels then xfer_cb should be provided */
9971085
if (!dl_chan->offload_ch && !mhi_drv->dl_xfer_cb)
998-
return -EINVAL;
1086+
goto exit_probe;
9991087

10001088
mhi_event = &mhi_cntrl->mhi_event[dl_chan->er_index];
10011089

@@ -1005,19 +1093,36 @@ static int mhi_driver_probe(struct device *dev)
10051093
* notify pending data
10061094
*/
10071095
if (mhi_event->cl_manage && !mhi_drv->status_cb)
1008-
return -EINVAL;
1096+
goto exit_probe;
10091097

10101098
dl_chan->xfer_cb = mhi_drv->dl_xfer_cb;
10111099
}
10121100

10131101
/* Call the user provided probe function */
1014-
return mhi_drv->probe(mhi_dev, mhi_dev->id);
1102+
ret = mhi_drv->probe(mhi_dev, mhi_dev->id);
1103+
if (ret)
1104+
goto exit_probe;
1105+
1106+
if (dl_chan && dl_chan->auto_start)
1107+
mhi_prepare_channel(mhi_cntrl, dl_chan);
1108+
1109+
mhi_device_put(mhi_dev);
1110+
1111+
return ret;
1112+
1113+
exit_probe:
1114+
mhi_unprepare_from_transfer(mhi_dev);
1115+
1116+
mhi_device_put(mhi_dev);
1117+
1118+
return ret;
10151119
}
10161120

10171121
static int mhi_driver_remove(struct device *dev)
10181122
{
10191123
struct mhi_device *mhi_dev = to_mhi_device(dev);
10201124
struct mhi_driver *mhi_drv = to_mhi_driver(dev->driver);
1125+
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
10211126
struct mhi_chan *mhi_chan;
10221127
enum mhi_ch_state ch_state[] = {
10231128
MHI_CH_STATE_DISABLED,
@@ -1049,6 +1154,10 @@ static int mhi_driver_remove(struct device *dev)
10491154
mhi_chan->ch_state = MHI_CH_STATE_SUSPENDED;
10501155
write_unlock_irq(&mhi_chan->lock);
10511156

1157+
/* Reset the non-offload channel */
1158+
if (!mhi_chan->offload_ch)
1159+
mhi_reset_chan(mhi_cntrl, mhi_chan);
1160+
10521161
mutex_unlock(&mhi_chan->mutex);
10531162
}
10541163

@@ -1063,11 +1172,20 @@ static int mhi_driver_remove(struct device *dev)
10631172

10641173
mutex_lock(&mhi_chan->mutex);
10651174

1175+
if (ch_state[dir] == MHI_CH_STATE_ENABLED &&
1176+
!mhi_chan->offload_ch)
1177+
mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan);
1178+
10661179
mhi_chan->ch_state = MHI_CH_STATE_DISABLED;
10671180

10681181
mutex_unlock(&mhi_chan->mutex);
10691182
}
10701183

1184+
read_lock_bh(&mhi_cntrl->pm_lock);
1185+
while (mhi_dev->dev_wake)
1186+
mhi_device_put(mhi_dev);
1187+
read_unlock_bh(&mhi_cntrl->pm_lock);
1188+
10711189
return 0;
10721190
}
10731191

drivers/bus/mhi/core/internal.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,8 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl);
587587
void mhi_pm_m1_transition(struct mhi_controller *mhi_cntrl);
588588
int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl);
589589
int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl);
590+
int mhi_send_cmd(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
591+
enum mhi_cmd_type cmd);
590592

591593
/* Register access methods */
592594
void mhi_db_brstmode(struct mhi_controller *mhi_cntrl, struct db_cfg *db_cfg,
@@ -618,6 +620,14 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl);
618620
void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl);
619621
void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
620622
struct image_info *img_info);
623+
int mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
624+
struct mhi_chan *mhi_chan);
625+
int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
626+
struct mhi_chan *mhi_chan);
627+
void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
628+
struct mhi_chan *mhi_chan);
629+
void mhi_reset_chan(struct mhi_controller *mhi_cntrl,
630+
struct mhi_chan *mhi_chan);
621631

622632
/* Memory allocation methods */
623633
static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl,
@@ -652,4 +662,16 @@ irqreturn_t mhi_irq_handler(int irq_number, void *dev);
652662
irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *dev);
653663
irqreturn_t mhi_intvec_handler(int irq_number, void *dev);
654664

665+
int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
666+
void *buf, void *cb, size_t buf_len, enum mhi_flags flags);
667+
668+
int mhi_map_single_no_bb(struct mhi_controller *mhi_cntrl,
669+
struct mhi_buf_info *buf_info);
670+
int mhi_map_single_use_bb(struct mhi_controller *mhi_cntrl,
671+
struct mhi_buf_info *buf_info);
672+
void mhi_unmap_single_no_bb(struct mhi_controller *mhi_cntrl,
673+
struct mhi_buf_info *buf_info);
674+
void mhi_unmap_single_use_bb(struct mhi_controller *mhi_cntrl,
675+
struct mhi_buf_info *buf_info);
676+
655677
#endif /* _MHI_INT_H */

0 commit comments

Comments
 (0)