Skip to content

Commit

Permalink
bus: mhi: core: Add support for creating and destroying MHI devices
Browse files Browse the repository at this point in the history
This commit adds support for creating and destroying MHI devices. The
MHI devices binds to the MHI channels and are used to transfer data
between MHI host and client device.

This is based on the patch submitted by Sujeev Dias:
https://lkml.org/lkml/2018/7/9/989

Signed-off-by: Sujeev Dias <sdias@codeaurora.org>
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
[mani: splitted from pm patch and cleaned up for upstream]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Jeffrey Hugo <jhugo@codeaurora.org>
Tested-by: Jeffrey Hugo <jhugo@codeaurora.org>
Link: https://lore.kernel.org/r/20200220095854.4804-5-manivannan.sadhasivam@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Manivannan Sadhasivam authored and Greg Kroah-Hartman committed Mar 19, 2020
1 parent e755cad commit da1c4f8
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/bus/mhi/core/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
obj-$(CONFIG_MHI_BUS) := mhi.o

mhi-y := init.o
mhi-y := init.o main.o
123 changes: 123 additions & 0 deletions drivers/bus/mhi/core/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
*/

#include <linux/device.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/mhi.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include "internal.h"

int mhi_destroy_device(struct device *dev, void *data)
{
struct mhi_device *mhi_dev;
struct mhi_controller *mhi_cntrl;

if (dev->bus != &mhi_bus_type)
return 0;

mhi_dev = to_mhi_device(dev);
mhi_cntrl = mhi_dev->mhi_cntrl;

/* Only destroy virtual devices thats attached to bus */
if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER)
return 0;

dev_dbg(&mhi_cntrl->mhi_dev->dev, "destroy device for chan:%s\n",
mhi_dev->chan_name);

/* Notify the client and remove the device from MHI bus */
device_del(dev);
put_device(dev);

return 0;
}

static void mhi_notify(struct mhi_device *mhi_dev, enum mhi_callback cb_reason)
{
struct mhi_driver *mhi_drv;

if (!mhi_dev->dev.driver)
return;

mhi_drv = to_mhi_driver(mhi_dev->dev.driver);

if (mhi_drv->status_cb)
mhi_drv->status_cb(mhi_dev, cb_reason);
}

/* Bind MHI channels to MHI devices */
void mhi_create_devices(struct mhi_controller *mhi_cntrl)
{
struct mhi_chan *mhi_chan;
struct mhi_device *mhi_dev;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
int i, ret;

mhi_chan = mhi_cntrl->mhi_chan;
for (i = 0; i < mhi_cntrl->max_chan; i++, mhi_chan++) {
if (!mhi_chan->configured || mhi_chan->mhi_dev ||
!(mhi_chan->ee_mask & BIT(mhi_cntrl->ee)))
continue;
mhi_dev = mhi_alloc_device(mhi_cntrl);
if (!mhi_dev)
return;

mhi_dev->dev_type = MHI_DEVICE_XFER;
switch (mhi_chan->dir) {
case DMA_TO_DEVICE:
mhi_dev->ul_chan = mhi_chan;
mhi_dev->ul_chan_id = mhi_chan->chan;
break;
case DMA_FROM_DEVICE:
/* We use dl_chan as offload channels */
mhi_dev->dl_chan = mhi_chan;
mhi_dev->dl_chan_id = mhi_chan->chan;
break;
default:
dev_err(dev, "Direction not supported\n");
put_device(&mhi_dev->dev);
return;
}

get_device(&mhi_dev->dev);
mhi_chan->mhi_dev = mhi_dev;

/* Check next channel if it matches */
if ((i + 1) < mhi_cntrl->max_chan && mhi_chan[1].configured) {
if (!strcmp(mhi_chan[1].name, mhi_chan->name)) {
i++;
mhi_chan++;
if (mhi_chan->dir == DMA_TO_DEVICE) {
mhi_dev->ul_chan = mhi_chan;
mhi_dev->ul_chan_id = mhi_chan->chan;
} else {
mhi_dev->dl_chan = mhi_chan;
mhi_dev->dl_chan_id = mhi_chan->chan;
}
get_device(&mhi_dev->dev);
mhi_chan->mhi_dev = mhi_dev;
}
}

/* Channel name is same for both UL and DL */
mhi_dev->chan_name = mhi_chan->name;
dev_set_name(&mhi_dev->dev, "%04x_%s", mhi_chan->chan,
mhi_dev->chan_name);

/* Init wakeup source if available */
if (mhi_dev->dl_chan && mhi_dev->dl_chan->wake_capable)
device_init_wakeup(&mhi_dev->dev, true);

ret = device_add(&mhi_dev->dev);
if (ret)
put_device(&mhi_dev->dev);
}
}
2 changes: 2 additions & 0 deletions include/linux/mhi.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ enum mhi_db_brst_mode {
* @doorbell_mode_switch: Channel switches to doorbell mode on M0 transition
* @auto_queue: Framework will automatically queue buffers for DL traffic
* @auto_start: Automatically start (open) this channel
* @wake-capable: Channel capable of waking up the system
*/
struct mhi_channel_config {
char *name;
Expand All @@ -180,6 +181,7 @@ struct mhi_channel_config {
bool doorbell_mode_switch;
bool auto_queue;
bool auto_start;
bool wake_capable;
};

/**
Expand Down

0 comments on commit da1c4f8

Please sign in to comment.