Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ae05263 authored by Sujeev Dias's avatar Sujeev Dias
Browse files

mhi: core: add support to enable MHI burst mode per channel basis



Not all MHI hardware channels support burst mode, add
support to enable burst mode per channel basis.

CRs-Fixed: 1027069
Change-Id: Icd3061f1a1a4b4b3dab8f9fe3b989a8afefd18b2
Signed-off-by: default avatarSujeev Dias <sdias@codeaurora.org>
parent fcfe80f8
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/dma-mapping.h>

extern struct mhi_pcie_devices mhi_devices;
struct mhi_device_ctxt;

enum MHI_DEBUG_LEVEL {
	MHI_MSG_RAW = 0x1,
@@ -125,6 +126,14 @@ enum MHI_STATE {
	MHI_STATE_reserved = 0x80000000
};

enum MHI_BRSTMODE {
	/* BRST Mode Enable for HW Channels, SW Channel Disabled */
	MHI_BRSTMODE_DEFAULT = 0x0,
	MHI_BRSTMODE_RESERVED = 0x1,
	MHI_BRSTMODE_DISABLE = 0x2,
	MHI_BRSTMODE_ENABLE = 0x3
};

struct __packed mhi_event_ctxt {
	u32 mhi_intmodt;
	u32 mhi_event_er_type;
@@ -136,8 +145,11 @@ struct __packed mhi_event_ctxt {
};

struct __packed mhi_chan_ctxt {
	enum MHI_CHAN_STATE mhi_chan_state;
	enum MHI_CHAN_DIR mhi_chan_type;
	u32 chstate : 8;
	u32 brstmode : 2;
	u32 pollcfg : 6;
	u32 reserved : 16;
	u32 chtype;
	u32 mhi_event_ring_index;
	u64 mhi_trb_ring_base_addr;
	u64 mhi_trb_ring_len;
@@ -265,6 +277,11 @@ struct db_mode {
	/* if set do not reset DB_Mode during M0 resume */
	u32 preserve_db_state : 1;
	u32 db_mode : 1;
	enum MHI_BRSTMODE brstmode;
	void (*process_db)(struct mhi_device_ctxt *mhi_dev_ctxt,
			   void __iomem *io_addr,
			   uintptr_t chan,
			   u32 val);
};

struct mhi_ring {
@@ -414,7 +431,6 @@ struct mhi_flags {
	u32 ssr;
	u32 ev_thread_stopped;
	u32 st_thread_stopped;
	u32 uldl_enabled;
};

struct mhi_wait_queues {
@@ -578,7 +594,8 @@ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list,
				   u32 event_ring,
				   struct mhi_ring *ring,
				   enum MHI_CHAN_STATE chan_state,
				   bool preserve_db_state);
				   bool preserve_db_state,
				   enum MHI_BRSTMODE brstmode);
int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_get_event_ring_for_channel(struct mhi_device_ctxt *mhi_dev_ctxt,
					      u32 chan);
@@ -636,6 +653,14 @@ int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_set_bus_request(struct mhi_device_ctxt *mhi_dev_ctxt,
					int index);
int start_chan_sync(struct mhi_client_handle *client_handle);
void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt,
			     void __iomem *io_addr,
			     uintptr_t chan,
			     u32 val);
void mhi_process_db_brstmode_disable(struct mhi_device_ctxt *mhi_dev_ctxt,
				     void __iomem *io_addr,
				     uintptr_t chan,
				     u32 val);
void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt, void __iomem *io_addr,
		  uintptr_t io_offset, u32 val);
void mhi_reg_write_field(struct mhi_device_ctxt *mhi_dev_ctxt,
+29 −7
Original line number Diff line number Diff line
@@ -129,13 +129,18 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index)
	db_value = mhi_v2p_addr(mhi_dev_ctxt, MHI_RING_TYPE_EVENT_RING,
						event_ring_index,
						(uintptr_t) event_ctxt->wp);
	mhi_process_db(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.event_db_addr,
					event_ring_index, db_value);
	event_ctxt->db_mode.process_db(mhi_dev_ctxt,
				    mhi_dev_ctxt->mmio_info.event_db_addr,
				    event_ring_index,
				    db_value);
}

static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list,
				struct mhi_ring *ring, u32 el_per_ring,
				u32 intmodt_val, u32 msi_vec)
			       struct mhi_ring *ring,
			       u32 el_per_ring,
			       u32 intmodt_val,
			       u32 msi_vec,
			       enum MHI_BRSTMODE brstmode)
{
	ev_list->mhi_event_er_type  = MHI_EVENT_RING_TYPE_VALID;
	ev_list->mhi_msi_vector     = msi_vec;
@@ -144,6 +149,20 @@ static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list,
	ring->len = ((size_t)(el_per_ring)*sizeof(union mhi_event_pkt));
	ring->el_size = sizeof(union mhi_event_pkt);
	ring->overwrite_en = 0;

	ring->db_mode.db_mode = 1;
	ring->db_mode.brstmode = brstmode;
	switch (ring->db_mode.brstmode) {
	case MHI_BRSTMODE_ENABLE:
		ring->db_mode.process_db = mhi_process_db_brstmode;
		break;
	case MHI_BRSTMODE_DISABLE:
		ring->db_mode.process_db = mhi_process_db_brstmode_disable;
		break;
	default:
		ring->db_mode.process_db = mhi_process_db;
	}

	/* Flush writes to MMIO */
	wmb();
	return 0;
@@ -161,7 +180,10 @@ void init_event_ctxt_array(struct mhi_device_ctxt *mhi_dev_ctxt)
		mhi_event_ring_init(event_ctxt, mhi_local_event_ctxt,
				    mhi_dev_ctxt->ev_ring_props[i].nr_desc,
				    mhi_dev_ctxt->ev_ring_props[i].intmod,
			mhi_dev_ctxt->ev_ring_props[i].msi_vec);
				    mhi_dev_ctxt->ev_ring_props[i].msi_vec,
				    GET_EV_PROPS(EV_BRSTMODE,
						 mhi_dev_ctxt->
						 ev_ring_props[i].flags));
	}
}

+21 −4
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ void init_dev_chan_ctxt(struct mhi_chan_ctxt *chan_ctxt,
	chan_ctxt->mhi_trb_write_ptr = p_base_addr;
	chan_ctxt->mhi_trb_ring_len = len;
	/* Prepulate the channel ctxt */
	chan_ctxt->mhi_chan_state = MHI_CHAN_STATE_ENABLED;
	chan_ctxt->chstate = MHI_CHAN_STATE_ENABLED;
	chan_ctxt->mhi_event_ring_index = ev_index;
}

@@ -173,6 +173,8 @@ static int mhi_cmd_ring_init(struct mhi_cmd_ctxt *cmd_ctxt,
	ring[PRIMARY_CMD_RING].len = ring_size;
	ring[PRIMARY_CMD_RING].el_size = sizeof(union mhi_cmd_pkt);
	ring[PRIMARY_CMD_RING].overwrite_en = 0;
	ring[PRIMARY_CMD_RING].db_mode.process_db =
		mhi_process_db_brstmode_disable;
	return 0;
}

@@ -601,10 +603,12 @@ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list,
		       u64 el_per_ring, enum MHI_CHAN_DIR chan_type,
		       u32 event_ring, struct mhi_ring *ring,
		       enum MHI_CHAN_STATE chan_state,
		       bool preserve_db_state)
		       bool preserve_db_state,
		       enum MHI_BRSTMODE brstmode)
{
	cc_list->mhi_chan_state = chan_state;
	cc_list->mhi_chan_type = chan_type;
	cc_list->brstmode = brstmode;
	cc_list->chstate = chan_state;
	cc_list->chtype = chan_type;
	cc_list->mhi_event_ring_index = event_ring;
	cc_list->mhi_trb_ring_base_addr = trb_list_phy;
	cc_list->mhi_trb_ring_len =
@@ -621,6 +625,19 @@ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list,
	ring->dir = chan_type;
	ring->db_mode.db_mode = 1;
	ring->db_mode.preserve_db_state = (preserve_db_state) ? 1 : 0;
	ring->db_mode.brstmode = brstmode;

	switch (ring->db_mode.brstmode) {
	case MHI_BRSTMODE_ENABLE:
		ring->db_mode.process_db = mhi_process_db_brstmode;
		break;
	case MHI_BRSTMODE_DISABLE:
		ring->db_mode.process_db = mhi_process_db_brstmode_disable;
		break;
	default:
		ring->db_mode.process_db = mhi_process_db;
	}

	/* Flush writes to MMIO */
	wmb();
	return 0;
+8 −0
Original line number Diff line number Diff line
@@ -247,9 +247,17 @@
#define MHI_PRESERVE_DB_STATE__MASK (1)
#define MHI_PRESERVE_DB_STATE__SHIFT (8)

#define BRSTMODE
#define MHI_BRSTMODE__MASK (3)
#define MHI_BRSTMODE__SHIFT (9)

#define GET_CHAN_PROPS(_FIELD, _VAL) \
	(((_VAL) >> MHI_##_FIELD ## __SHIFT) & MHI_##_FIELD ## __MASK)

#define EV_BRSTMODE
#define MHI_EV_BRSTMODE__MASK (3)
#define MHI_EV_BRSTMODE__SHIFT (5)

#define EV_TYPE
#define MHI_EV_TYPE__MASK (3)
#define MHI_EV_TYPE__SHIFT (3)
+85 −27
Original line number Diff line number Diff line
@@ -212,7 +212,9 @@ int mhi_release_chan_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
			ring->len, ring->base,
			 cc_list->mhi_trb_ring_base_addr);
	mhi_init_chan_ctxt(cc_list, 0, 0, 0, 0, 0, ring,
			   MHI_CHAN_STATE_DISABLED, false);
			   MHI_CHAN_STATE_DISABLED,
			   false,
			   MHI_BRSTMODE_DEFAULT);
	return 0;
}

@@ -261,6 +263,8 @@ static int populate_tre_ring(struct mhi_client_handle *client_handle)
			   &mhi_dev_ctxt->mhi_local_chan_ctxt[chan],
			   MHI_CHAN_STATE_ENABLED,
			   GET_CHAN_PROPS(PRESERVE_DB_STATE,
					  client_handle->chan_info.flags),
			   GET_CHAN_PROPS(BRSTMODE,
					  client_handle->chan_info.flags));
	mhi_log(MHI_MSG_INFO, "Exited\n");
	return 0;
@@ -442,9 +446,10 @@ void mhi_update_chan_db(struct mhi_device_ctxt *mhi_dev_ctxt,
	db_value = mhi_v2p_addr(mhi_dev_ctxt, MHI_RING_TYPE_XFER_RING, chan,
						(uintptr_t) chan_ctxt->wp);
	mhi_dev_ctxt->mhi_chan_db_order[chan]++;
		mhi_process_db(mhi_dev_ctxt,
	chan_ctxt->db_mode.process_db(mhi_dev_ctxt,
				      mhi_dev_ctxt->mmio_info.chan_db_addr,
				chan, db_value);
				      chan,
				      db_value);
}

int mhi_check_m2_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
@@ -490,7 +495,7 @@ static inline int mhi_queue_tre(struct mhi_device_ctxt
	if (likely(((ret_val == 0) &&
	    (((mhi_dev_ctxt->mhi_state == MHI_STATE_M0) ||
	      (mhi_dev_ctxt->mhi_state == MHI_STATE_M1))) &&
	    (chan_ctxt->mhi_chan_state != MHI_CHAN_STATE_ERROR)) &&
	    (chan_ctxt->chstate != MHI_CHAN_STATE_ERROR)) &&
	    (!mhi_dev_ctxt->flags.pending_M3))) {
		if (likely(type == MHI_RING_TYPE_XFER_RING)) {
			spin_lock_irqsave(&mhi_dev_ctxt->db_write_lock[chan],
@@ -506,15 +511,18 @@ static inline int mhi_queue_tre(struct mhi_device_ctxt
			spin_unlock_irqrestore(
			   &mhi_dev_ctxt->db_write_lock[chan], flags);
		} else if (type == MHI_RING_TYPE_CMD_RING) {
			struct mhi_ring *cmd_ring = &mhi_dev_ctxt->
				mhi_local_cmd_ctxt[PRIMARY_CMD_RING];
			db_value = mhi_v2p_addr(mhi_dev_ctxt,
						MHI_RING_TYPE_CMD_RING,
						PRIMARY_CMD_RING,
						(uintptr_t)
			mhi_dev_ctxt->mhi_local_cmd_ctxt[PRIMARY_CMD_RING].wp);
			cmd_ring->wp);
			mhi_dev_ctxt->cmd_ring_order++;
			mhi_process_db(mhi_dev_ctxt,
			cmd_ring->db_mode.process_db(mhi_dev_ctxt,
				mhi_dev_ctxt->mmio_info.cmd_db_addr,
				0, db_value);
				0,
				db_value);
		} else {
			mhi_log(MHI_MSG_VERBOSE,
			"Wrong type of packet = %d\n", type);
@@ -524,7 +532,7 @@ static inline int mhi_queue_tre(struct mhi_device_ctxt
		mhi_log(MHI_MSG_VERBOSE,
			"Wakeup, pending data state %s chan state %d\n",
			TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state),
			chan_ctxt->mhi_chan_state);
			chan_ctxt->chstate);
			ret_val = 0;
	}
	return ret_val;
@@ -787,7 +795,7 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,

	atomic_inc(&mhi_dev_ctxt->flags.data_pending);
	from_state =
	    mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan].mhi_chan_state;
	    mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan].chstate;

	switch (cmd) {
		break;
@@ -1170,7 +1178,6 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt,
		u64 db_value = 0;
		unsigned long flags;

		mhi_dev_ctxt->flags.uldl_enabled = 1;
		chan = MHI_EV_READ_CHID(EV_CHID, event);
		chan_ctxt =
			&mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
@@ -1183,7 +1190,7 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt,
			db_value = mhi_v2p_addr(mhi_dev_ctxt,
						MHI_RING_TYPE_XFER_RING, chan,
						(uintptr_t) chan_ctxt->wp);
			mhi_process_db(mhi_dev_ctxt,
			chan_ctxt->db_mode.process_db(mhi_dev_ctxt,
				     mhi_dev_ctxt->mmio_info.chan_db_addr, chan,
				     db_value);
		}
@@ -1274,13 +1281,14 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
		case MHI_RING_TYPE_CMD_RING:
		{
			struct mutex *cmd_mutex = NULL;

			struct mhi_ring *mhi_ring = &mhi_dev_ctxt->
				mhi_local_cmd_ctxt[PRIMARY_CMD_RING];
			cmd_mutex =
				&mhi_dev_ctxt->
				mhi_cmd_mutex_list[PRIMARY_CMD_RING];
			mutex_lock(cmd_mutex);
			mhi_dev_ctxt->cmd_ring_order = 1;
			mhi_process_db(mhi_dev_ctxt,
			mhi_ring->db_mode.process_db(mhi_dev_ctxt,
				mhi_dev_ctxt->mmio_info.cmd_db_addr,
				ring_index, db_value);
			mutex_unlock(cmd_mutex);
@@ -1290,7 +1298,8 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
		{
			spinlock_t *lock = NULL;
			unsigned long flags = 0;

			struct mhi_ring *mhi_ring = &mhi_dev_ctxt->
				mhi_local_event_ctxt[ring_index];
			lock = &mhi_dev_ctxt->mhi_ev_spinlock_list[ring_index];
			spin_lock_irqsave(lock, flags);
			mhi_dev_ctxt->mhi_ev_db_order[ring_index] = 1;
@@ -1299,7 +1308,7 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
				db_value = mhi_v2p_addr(mhi_dev_ctxt, ring_type,
							ring_index,
							(uintptr_t) ring->wp);
				mhi_process_db(mhi_dev_ctxt,
				mhi_ring->db_mode.process_db(mhi_dev_ctxt,
					mhi_dev_ctxt->mmio_info.event_db_addr,
					ring_index, db_value);
			}
@@ -1309,12 +1318,13 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
		case MHI_RING_TYPE_XFER_RING:
		{
			unsigned long flags = 0;

			struct mhi_ring *mhi_ring = &mhi_dev_ctxt->
				mhi_local_chan_ctxt[ring_index];
			spin_lock_irqsave(
				&mhi_dev_ctxt->db_write_lock[ring_index],
				flags);
			mhi_dev_ctxt->mhi_chan_db_order[ring_index] = 1;
			mhi_process_db(mhi_dev_ctxt,
			mhi_ring->db_mode.process_db(mhi_dev_ctxt,
					mhi_dev_ctxt->mmio_info.chan_db_addr,
					ring_index, db_value);
			spin_unlock_irqrestore(
@@ -1380,7 +1390,7 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
	local_chan_ctxt->ack_rp = local_chan_ctxt->base;

	/* Reset the mhi channel context */
	chan_ctxt->mhi_chan_state = MHI_CHAN_STATE_DISABLED;
	chan_ctxt->chstate = MHI_CHAN_STATE_DISABLED;
	chan_ctxt->mhi_trb_read_ptr = chan_ctxt->mhi_trb_ring_base_addr;
	chan_ctxt->mhi_trb_write_ptr = chan_ctxt->mhi_trb_ring_base_addr;

@@ -1658,11 +1668,56 @@ int mhi_deregister_channel(struct mhi_client_handle
}
EXPORT_SYMBOL(mhi_deregister_channel);

void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt,
			     void __iomem *io_addr,
			     uintptr_t chan,
			     u32 val)
{
	struct mhi_ring *ring_ctxt =
		&mhi_dev_ctxt->mhi_local_chan_ctxt[chan];

	if (io_addr == mhi_dev_ctxt->mmio_info.chan_db_addr)
		ring_ctxt = &mhi_dev_ctxt->
			mhi_local_chan_ctxt[chan];
	else
		ring_ctxt = &mhi_dev_ctxt->
			mhi_local_event_ctxt[chan];

	mhi_log(MHI_MSG_VERBOSE,
			"db.set addr: %p io_offset 0x%lx val:0x%x\n",
			io_addr, chan, val);

	mhi_update_ctxt(mhi_dev_ctxt, io_addr, chan, val);

	if (ring_ctxt->db_mode.db_mode) {
		mhi_write_db(mhi_dev_ctxt, io_addr, chan, val);
		ring_ctxt->db_mode.db_mode = 0;
	} else {
		mhi_log(MHI_MSG_INFO,
			"Not ringing xfer db, chan %ld, brstmode %d db_mode %d\n",
			chan,
			ring_ctxt->db_mode.brstmode,
			ring_ctxt->db_mode.db_mode);
	}
}

void mhi_process_db_brstmode_disable(struct mhi_device_ctxt *mhi_dev_ctxt,
			     void __iomem *io_addr,
			     uintptr_t chan,
			     u32 val)
{
	mhi_log(MHI_MSG_VERBOSE,
			"db.set addr: %p io_offset 0x%lx val:0x%x\n",
			io_addr, chan, val);

	mhi_update_ctxt(mhi_dev_ctxt, io_addr, chan, val);
	mhi_write_db(mhi_dev_ctxt, io_addr, chan, val);
}

void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt,
		  void __iomem *io_addr,
		  uintptr_t chan, u32 val)
{
	struct mhi_ring *chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];

	mhi_log(MHI_MSG_VERBOSE,
			"db.set addr: %p io_offset 0x%lx val:0x%x\n",
@@ -1672,22 +1727,25 @@ void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt,

	/* Channel Doorbell and Polling Mode Disabled or Software Channel*/
	if (io_addr == mhi_dev_ctxt->mmio_info.chan_db_addr) {
		struct mhi_ring *chan_ctxt =
			&mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
		if (!(IS_HARDWARE_CHANNEL(chan) &&
		    mhi_dev_ctxt->flags.uldl_enabled &&
		    !chan_ctxt->db_mode.db_mode)) {
			mhi_write_db(mhi_dev_ctxt, io_addr, chan, val);
			chan_ctxt->db_mode.db_mode = 0;
		} else {
			mhi_log(MHI_MSG_INFO,
				"Not ringing xfer db, chan %ld, ul_dl %d db_mode %d\n",
				chan, mhi_dev_ctxt->flags.uldl_enabled,
				"Not ringing xfer db, chan %ld, brstmode %d db_mode %d\n",
				chan, chan_ctxt->db_mode.brstmode,
				chan_ctxt->db_mode.db_mode);
		}
	/* Event Doorbell and Polling mode Disabled */
	} else if (io_addr == mhi_dev_ctxt->mmio_info.event_db_addr) {
		/* Only ring for software channel */
		if (IS_SW_EV_RING(mhi_dev_ctxt, chan) ||
		    !mhi_dev_ctxt->flags.uldl_enabled) {
		struct mhi_ring *ev_ctxt =
			&mhi_dev_ctxt->mhi_local_event_ctxt[chan];
		/* Only ring for software channel or db mode*/
		if (!(IS_HW_EV_RING(mhi_dev_ctxt, chan) &&
		    !ev_ctxt->db_mode.db_mode)) {
			mhi_write_db(mhi_dev_ctxt, io_addr, chan, val);
		}
	} else {
Loading