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

Commit 7a3aebc9 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mhi: core: Mark unprocessed events as STALE"

parents a46c000c bdfe181b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ enum MHI_PKT_TYPE {
	MHI_PKT_TYPE_CMD_COMPLETION_EVENT = 0x21,
	MHI_PKT_TYPE_TX_EVENT = 0x22,
	MHI_PKT_TYPE_EE_EVENT = 0x40,
	MHI_PKT_TYPE_STALE_EVENT, /* Internal event */
	MHI_PKT_TYPE_SYS_ERR_EVENT = 0xFF,
};

@@ -310,6 +311,7 @@ struct mhi_ring {
	uintptr_t el_size;
	u32 overwrite_en;
	enum MHI_CHAN_DIR dir;
	enum MHI_CHAN_STATE ch_state;
	struct db_mode db_mode;
	u32 msi_disable_cntr;
	u32 msi_enable_cntr;
+3 −0
Original line number Diff line number Diff line
@@ -122,9 +122,11 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index)
{
	struct mhi_ring *event_ctxt = NULL;
	u64 db_value = 0;
	unsigned long flags;

	event_ctxt =
		&mhi_dev_ctxt->mhi_local_event_ctxt[event_ring_index];
	spin_lock_irqsave(&event_ctxt->ring_lock, flags);
	db_value = mhi_v2p_addr(mhi_dev_ctxt, MHI_RING_TYPE_EVENT_RING,
						event_ring_index,
						(uintptr_t) event_ctxt->wp);
@@ -132,6 +134,7 @@ void ring_ev_db(struct mhi_device_ctxt *mhi_dev_ctxt, u32 event_ring_index)
				    mhi_dev_ctxt->mmio_info.event_db_addr,
				    event_ring_index,
				    db_value);
	spin_unlock_irqrestore(&event_ctxt->ring_lock, flags);
}

static int mhi_event_ring_init(struct mhi_event_ctxt *ev_list,
+1 −0
Original line number Diff line number Diff line
@@ -594,6 +594,7 @@ int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list,
	ring->el_size = sizeof(struct mhi_tx_pkt);
	ring->overwrite_en = 0;
	ring->dir = chan_type;
	ring->ch_state = MHI_CHAN_STATE_DISABLED;
	ring->db_mode.db_mode = 1;
	ring->db_mode.preserve_db_state = (preserve_db_state) ? 1 : 0;
	ring->db_mode.brstmode = brstmode;
+31 −6
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ static int mhi_process_event_ring(
	union mhi_event_pkt event_to_process;
	int ret_val = 0;
	struct mhi_event_ctxt *ev_ctxt = NULL;
	unsigned long flags;
	struct mhi_ring *local_ev_ctxt =
		&mhi_dev_ctxt->mhi_local_event_ctxt[ev_index];

@@ -38,6 +39,7 @@ static int mhi_process_event_ring(
	read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
	ev_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[ev_index];

	spin_lock_irqsave(&local_ev_ctxt->ring_lock, flags);
	device_rp = (union mhi_event_pkt *)mhi_p2v_addr(
					mhi_dev_ctxt,
					MHI_RING_TYPE_EVENT_RING,
@@ -45,19 +47,19 @@ static int mhi_process_event_ring(
					ev_ctxt->mhi_event_read_ptr);

	local_rp = (union mhi_event_pkt *)local_ev_ctxt->rp;

	spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags);
	BUG_ON(validate_ev_el_addr(local_ev_ctxt, (uintptr_t)device_rp));

	while ((local_rp != device_rp) && (event_quota > 0) &&
			(device_rp != NULL) && (local_rp != NULL)) {

		spin_lock_irqsave(&local_ev_ctxt->ring_lock, flags);
		event_to_process = *local_rp;
		read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
		recycle_trb_and_ring(mhi_dev_ctxt,
				     local_ev_ctxt,
				     MHI_RING_TYPE_EVENT_RING,
				     ev_index);
		read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
		spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags);

		switch (MHI_TRB_READ_INFO(EV_TRB_TYPE, &event_to_process)) {
		case MHI_PKT_TYPE_CMD_COMPLETION_EVENT:
@@ -93,12 +95,28 @@ static int mhi_process_event_ring(
			break;
		}
		case MHI_PKT_TYPE_TX_EVENT:
		{
			u32 chan;
			struct mhi_ring *ring;

			__pm_stay_awake(&mhi_dev_ctxt->w_lock);
			chan = MHI_EV_READ_CHID(EV_CHID, &event_to_process);
			if (unlikely(!VALID_CHAN_NR(chan))) {
				mhi_log(MHI_MSG_ERROR,
					"Invalid chan:%d\n",
					chan);
				break;
			}
			ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
			spin_lock_bh(&ring->ring_lock);
			if (ring->ch_state == MHI_CHAN_STATE_ENABLED)
				parse_xfer_event(mhi_dev_ctxt,
						 &event_to_process,
						 ev_index);
			spin_unlock_bh(&ring->ring_lock);
			__pm_relax(&mhi_dev_ctxt->w_lock);
			break;
		}
		case MHI_PKT_TYPE_STATE_CHANGE_EVENT:
		{
			enum STATE_TRANSITION new_state;
@@ -153,6 +171,11 @@ static int mhi_process_event_ring(
			}
			break;
		}
		case MHI_PKT_TYPE_STALE_EVENT:
			mhi_log(MHI_MSG_INFO,
				"Stale Event received for chan:%u\n",
				MHI_EV_READ_CHID(EV_CHID, local_rp));
			break;
		case MHI_PKT_TYPE_SYS_ERR_EVENT:
			mhi_log(MHI_MSG_INFO,
			   "MHI System Error Detected. Triggering Reset\n");
@@ -165,12 +188,14 @@ static int mhi_process_event_ring(
					&event_to_process));
			break;
		}
		spin_lock_irqsave(&local_ev_ctxt->ring_lock, flags);
		local_rp = (union mhi_event_pkt *)local_ev_ctxt->rp;
		device_rp = (union mhi_event_pkt *)mhi_p2v_addr(
						mhi_dev_ctxt,
						MHI_RING_TYPE_EVENT_RING,
						ev_index,
						ev_ctxt->mhi_event_read_ptr);
		spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags);
		ret_val = 0;
		--event_quota;
	}
+59 −44
Original line number Diff line number Diff line
@@ -277,6 +277,7 @@ int mhi_open_channel(struct mhi_client_handle *client_handle)
{
	int ret_val = 0;
	struct mhi_device_ctxt *mhi_dev_ctxt;
	struct mhi_ring *chan_ring;
	int chan;
	struct mhi_chan_cfg *cfg;
	struct mhi_cmd_complete_event_pkt cmd_event_pkt;
@@ -295,6 +296,7 @@ int mhi_open_channel(struct mhi_client_handle *client_handle)

	chan = client_handle->chan_info.chan_nr;
	cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan];
	chan_ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
	mutex_lock(&cfg->chan_lock);
	mhi_log(MHI_MSG_INFO,
		"Entered: Client opening chan 0x%x\n", chan);
@@ -352,6 +354,9 @@ int mhi_open_channel(struct mhi_client_handle *client_handle)
	read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
	pm_runtime_get(&mhi_dev_ctxt->dev_info->pcie_device->dev);

	spin_lock_irq(&chan_ring->ring_lock);
	chan_ring->ch_state = MHI_CHAN_STATE_ENABLED;
	spin_unlock_irq(&chan_ring->ring_lock);
	ret_val = mhi_send_cmd(client_handle->mhi_dev_ctxt,
			       MHI_COMMAND_START_CHAN,
			       chan);
@@ -462,6 +467,7 @@ void mhi_close_channel(struct mhi_client_handle *client_handle)
	struct mhi_device_ctxt *mhi_dev_ctxt;
	struct mhi_cmd_complete_event_pkt cmd_event_pkt;
	union mhi_cmd_pkt cmd_pkt;
	struct mhi_ring *chan_ring;
	enum MHI_EVENT_CCS ev_code;

	if (!client_handle ||
@@ -474,7 +480,13 @@ void mhi_close_channel(struct mhi_client_handle *client_handle)
	cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan];

	mhi_log(MHI_MSG_INFO, "Client attempting to close chan 0x%x\n", chan);
	chan_ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
	mutex_lock(&cfg->chan_lock);

	/* No more processing events for this channel */
	spin_lock_irq(&chan_ring->ring_lock);
	chan_ring->ch_state = MHI_CHAN_STATE_DISABLED;
	spin_unlock_irq(&chan_ring->ring_lock);
	init_completion(&cfg->cmd_complete);
	read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
	WARN_ON(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE);
@@ -829,8 +841,6 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
			enum MHI_COMMAND cmd, u32 chan)
{
	union mhi_cmd_pkt *cmd_pkt = NULL;
	enum MHI_CHAN_STATE from_state = MHI_CHAN_STATE_DISABLED;
	enum MHI_CHAN_STATE to_state = MHI_CHAN_STATE_DISABLED;
	enum MHI_PKT_TYPE ring_el_type = MHI_PKT_TYPE_NOOP_CMD;
	int ret_val = 0;
	unsigned long flags, flags2;
@@ -849,33 +859,17 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
		TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state),
		mhi_dev_ctxt->dev_exec_env, chan, cmd);

	from_state =
	    mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan].chstate;

	switch (cmd) {
		break;
	case MHI_COMMAND_RESET_CHAN:
		to_state = MHI_CHAN_STATE_DISABLED;
		ring_el_type = MHI_PKT_TYPE_RESET_CHAN_CMD;
		break;
	case MHI_COMMAND_START_CHAN:
		switch (from_state) {
		case MHI_CHAN_STATE_DISABLED:
		case MHI_CHAN_STATE_ENABLED:
		case MHI_CHAN_STATE_STOP:
			to_state = MHI_CHAN_STATE_RUNNING;
			break;
		default:
			mhi_log(MHI_MSG_ERROR,
				"Invalid stt cmd 0x%x, from_state 0x%x\n",
				cmd, from_state);
			ret_val = -EPERM;
			goto error_invalid;
		}
		ring_el_type = MHI_PKT_TYPE_START_CHAN_CMD;
		break;
	default:
		mhi_log(MHI_MSG_ERROR, "Bad command received\n");
		return -EINVAL;
	}

	spin_lock_irqsave(&mhi_ring->ring_lock, flags);
@@ -897,7 +891,7 @@ int mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
		"Sent command 0x%x for chan %d\n",
		cmd,
		chan);
error_invalid:

	mhi_log(MHI_MSG_INFO, "Exited ret %d.\n", ret_val);
	return ret_val;
}
@@ -1120,13 +1114,11 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt,
	u32 nr_trb_to_parse;
	u32 i = 0;
	u32 ev_code;
	struct mhi_ring *local_chan_ctxt;

	trace_mhi_ev(event);
	chan = MHI_EV_READ_CHID(EV_CHID, event);
	if (unlikely(!VALID_CHAN_NR(chan))) {
		mhi_log(MHI_MSG_ERROR, "Bad ring id.\n");
		return -EINVAL;
	}
	local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
	ev_code = MHI_EV_READ_CODE(EV_TRB_CODE, event);
	client_handle = mhi_dev_ctxt->client_handle_list[chan];
	client_handle->pkt_count++;
@@ -1147,10 +1139,7 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt,
		dma_addr_t trb_data_loc;
		u32 ieot_flag;
		int ret_val;
		struct mhi_ring *local_chan_ctxt;

		local_chan_ctxt =
			&mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
		phy_ev_trb_loc = MHI_EV_READ_PTR(EV_PTR, event);

		chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan];
@@ -1217,29 +1206,22 @@ int parse_xfer_event(struct mhi_device_ctxt *ctxt,
	case MHI_EVENT_CC_OOB:
	case MHI_EVENT_CC_DB_MODE:
	{
		struct mhi_ring *chan_ctxt = NULL;
		u64 db_value = 0;
		unsigned long flags;

		chan = MHI_EV_READ_CHID(EV_CHID, event);
		chan_ctxt =
			&mhi_dev_ctxt->mhi_local_chan_ctxt[chan];

		mhi_log(MHI_MSG_INFO, "DB_MODE/OOB Detected chan %d.\n", chan);
		spin_lock_irqsave(&chan_ctxt->ring_lock, flags);
		chan_ctxt->db_mode.db_mode = 1;
		if (chan_ctxt->wp != chan_ctxt->rp) {

		local_chan_ctxt->db_mode.db_mode = 1;
		if (local_chan_ctxt->wp != local_chan_ctxt->rp) {
			db_value = mhi_v2p_addr(mhi_dev_ctxt,
					MHI_RING_TYPE_XFER_RING, chan,
						(uintptr_t) chan_ctxt->wp);
			chan_ctxt->db_mode.process_db(mhi_dev_ctxt,
					(uintptr_t) local_chan_ctxt->wp);
			local_chan_ctxt->db_mode.process_db(mhi_dev_ctxt,
				     mhi_dev_ctxt->mmio_info.chan_db_addr, chan,
				     db_value);
		}
		client_handle = mhi_dev_ctxt->client_handle_list[chan];
		if (client_handle)
			result->transaction_status = -ENOTCONN;
		spin_unlock_irqrestore(&chan_ctxt->ring_lock, flags);
		break;
	}
	case MHI_EVENT_CC_BAD_TRE:
@@ -1272,7 +1254,6 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
	u64 db_value = 0;
	void *removed_element = NULL;
	void *added_element = NULL;
	spinlock_t *lock;
	unsigned long flags;
	struct mhi_ring *mhi_ring = &mhi_dev_ctxt->
		mhi_local_event_ctxt[ring_index];
@@ -1292,8 +1273,7 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
	if (!MHI_DB_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state))
		return -EACCES;

	lock = &mhi_ring->ring_lock;
	spin_lock_irqsave(lock, flags);
	read_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
	db_value = mhi_v2p_addr(mhi_dev_ctxt,
				ring_type,
				ring_index,
@@ -1301,7 +1281,7 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
	mhi_ring->db_mode.process_db(mhi_dev_ctxt,
				     mhi_dev_ctxt->mmio_info.event_db_addr,
				     ring_index, db_value);
	spin_unlock_irqrestore(lock, flags);
	read_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags);

	return 0;

@@ -1313,10 +1293,15 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
	u32 chan  = 0;
	int ret_val = 0;
	struct mhi_ring *local_chan_ctxt;
	struct mhi_ring *ev_ring;
	struct mhi_chan_ctxt *chan_ctxt;
	struct mhi_event_ctxt *ev_ctxt = NULL;
	struct mhi_client_handle *client_handle = NULL;
	int pending_el = 0, i;
	struct mhi_ring *bb_ctxt;
	unsigned long flags;
	union mhi_event_pkt *local_rp = NULL;
	union mhi_event_pkt *device_rp = NULL;

	MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan);

@@ -1330,8 +1315,38 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
	client_handle = mhi_dev_ctxt->client_handle_list[chan];
	local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
	chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan];
	ev_ring = &mhi_dev_ctxt->
		mhi_local_event_ctxt[chan_ctxt->mhi_event_ring_index];
	ev_ctxt = &mhi_dev_ctxt->
		dev_space.ring_ctxt.ec_list[chan_ctxt->mhi_event_ring_index];
	mhi_log(MHI_MSG_INFO, "Processed cmd reset event\n");

	/* Clear all stale events related to Channel */
	spin_lock_irqsave(&ev_ring->ring_lock, flags);
	device_rp = (union mhi_event_pkt *)mhi_p2v_addr(
					mhi_dev_ctxt,
					MHI_RING_TYPE_EVENT_RING,
					chan_ctxt->mhi_event_ring_index,
					ev_ctxt->mhi_event_read_ptr);
	local_rp = (union mhi_event_pkt *)ev_ring->rp;
	while (device_rp != local_rp) {
		if (MHI_TRB_READ_INFO(EV_TRB_TYPE, local_rp) ==
		    MHI_PKT_TYPE_TX_EVENT) {
			u32 ev_chan = MHI_EV_READ_CHID(EV_CHID, local_rp);

			/* Mark as stale event */
			if (ev_chan == chan)
				MHI_TRB_SET_INFO(EV_TRB_TYPE,
						 local_rp,
						 MHI_PKT_TYPE_STALE_EVENT);
		}

		local_rp++;
		if (local_rp == (ev_ring->base + ev_ring->len))
			local_rp = ev_ring->base;
	}
	spin_unlock_irqrestore(&ev_ring->ring_lock, flags);

	/*
	 * If outbound elements are pending, they must be cleared since
	 * they will never be acked after a channel reset.