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

Commit 1fc96da5 authored by Andrei Danaila's avatar Andrei Danaila Committed by Matt Wagantall
Browse files

mhi: core: Enable MHI reset operation



Enable MHI reset for dynamic recovery of MHI transport errors.

CRs-Fixed: 797757
Change-Id: I522503ab12d90d5391884772952960201f3585fb
Signed-off-by: default avatarAndrei Danaila <adanaila@codeaurora.org>
parent 2faf81b2
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/sched.h>
#include <linux/cdev.h>
#include <mach/msm_pcie.h>
#include <linux/sched.h>

extern struct mhi_pcie_devices mhi_devices;

@@ -115,7 +116,8 @@ enum MHI_STATE {
	MHI_STATE_M2 = 0x4,
	MHI_STATE_M3 = 0x5,
	MHI_STATE_BHI  = 0x7,
	MHI_STATE_LIMIT = 0x8,
	MHI_STATE_SYS_ERR  = 0x8,
	MHI_STATE_LIMIT = 0x9,
	MHI_STATE_reserved = 0x80000000
};

@@ -170,6 +172,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_SYS_ERR_EVENT = 0xFF,
};

struct __packed mhi_tx_pkt {
@@ -541,6 +544,8 @@ enum MHI_STATUS parse_cmd_event(struct mhi_device_ctxt *ctxt,
int parse_event_thread(void *ctxt);
enum MHI_STATUS mhi_test_for_device_ready(
					struct mhi_device_ctxt *mhi_dev_ctxt);
enum MHI_STATUS mhi_test_for_device_reset(
					struct mhi_device_ctxt *mhi_dev_ctxt);
enum MHI_STATUS validate_ring_el_addr(struct mhi_ring *ring, uintptr_t addr);
enum MHI_STATUS validate_ev_el_addr(struct mhi_ring *ring, uintptr_t addr);
int mhi_state_change_thread(void *ctxt);
@@ -590,5 +595,6 @@ u32 mhi_reg_read_field(void __iomem *io_addr, uintptr_t io_offset,
void mhi_exit_m2(struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_runtime_suspend(struct device *dev);
int mhi_runtime_resume(struct device *dev);
enum MHI_STATUS mhi_trigger_reset(struct mhi_device_ctxt *mhi_dev_ctxt);

#endif
+22 −2
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
@@ -71,6 +71,7 @@ static enum MHI_STATUS mhi_process_event_ring(
	struct mhi_event_ctxt *ev_ctxt = NULL;
	struct mhi_ring *local_ev_ctxt =
		&mhi_dev_ctxt->mhi_local_event_ctxt[ev_index];
	enum MHI_STATUS ret_val = MHI_STATUS_SUCCESS;

	ev_ctxt = &mhi_dev_ctxt->mhi_ctrl_seg->mhi_ec_list[ev_index];

@@ -103,7 +104,7 @@ static enum MHI_STATUS mhi_process_event_ring(
					ev_index);
			__pm_stay_awake(&mhi_dev_ctxt->w_lock);
			__pm_relax(&mhi_dev_ctxt->w_lock);
			parse_cmd_event(mhi_dev_ctxt,
			ret_val = parse_cmd_event(mhi_dev_ctxt,
					&event_to_process);
			break;
		case MHI_PKT_TYPE_TX_EVENT:
@@ -143,6 +144,13 @@ static enum MHI_STATUS mhi_process_event_ring(
			}
			break;
		}
		case MHI_PKT_TYPE_SYS_ERR_EVENT:
			mhi_log(MHI_MSG_INFO,
				"MHI System Error Detected. Triggering Reset\n");
			if (!mhi_trigger_reset(mhi_dev_ctxt))
				mhi_log(MHI_MSG_ERROR,
				"Failed to reset for SYSERR recovery\n");
		break;
		default:
			mhi_log(MHI_MSG_ERROR,
				"Unsupported packet type code 0x%x\n",
@@ -154,6 +162,11 @@ static enum MHI_STATUS mhi_process_event_ring(
		device_rp = (union mhi_event_pkt *)mhi_p2v_addr(
					mhi_dev_ctxt->mhi_ctrl_seg_info,
					(u64)ev_ctxt->mhi_event_read_ptr);
		if (mhi_dev_ctxt->mhi_state == MHI_STATE_SYS_ERR) {
			mhi_log(MHI_MSG_ERROR,
				"Detected system error, stopping.\n");
			return MHI_STATUS_ERROR;
		}
		--event_quota;
	}
	return MHI_STATUS_SUCCESS;
@@ -200,6 +213,13 @@ int parse_event_thread(void *ctxt)
			MHI_GET_EVENT_RING_INFO(EVENT_RING_POLLING,
					mhi_dev_ctxt->ev_ring_props[i],
					ev_poll_en)
			if (mhi_dev_ctxt->mhi_state == MHI_STATE_SYS_ERR) {
				mhi_log(MHI_MSG_INFO,
				   "SYS_ERR detected, not processing events\n");
				atomic_set(&mhi_dev_ctxt->flags.events_pending,
					   0);
				break;
			}
			if (ev_poll_en) {
				mhi_process_event_ring(mhi_dev_ctxt,
				 mhi_dev_ctxt->alloced_ev_rings[i],
+1 −1
Original line number Diff line number Diff line
@@ -239,7 +239,6 @@ enum MHI_STATUS mhi_open_channel(struct mhi_client_handle *client_handle)
	chan = client_handle->chan;
	mhi_log(MHI_MSG_INFO,
		"Entered: Client opening chan 0x%x\n", chan);
	init_completion(&client_handle->chan_open_complete);
	mhi_dev_ctxt = client_handle->mhi_dev_ctxt;
	switch (mhi_dev_ctxt->dev_exec_env) {
	case MHI_EXEC_ENV_PBL:
@@ -688,6 +687,7 @@ enum MHI_STATUS mhi_send_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
		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;
+27 −0
Original line number Diff line number Diff line
@@ -13,6 +13,33 @@
#include "mhi_hwio.h"
#include "mhi.h"

enum MHI_STATUS mhi_test_for_device_reset(struct mhi_device_ctxt *mhi_dev_ctxt)
{
	u32 pcie_word_val = 0;
	u32 expiry_counter;
	mhi_log(MHI_MSG_INFO, "Waiting for MMIO RESET bit to be cleared.\n");
	pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_addr, MHISTATUS);
	MHI_READ_FIELD(pcie_word_val,
			MHICTRL_RESET_MASK,
			MHICTRL_RESET_SHIFT);
	if (pcie_word_val == 0xFFFFFFFF)
		return MHI_STATUS_LINK_DOWN;
	while (MHI_STATE_RESET != pcie_word_val && expiry_counter < 100) {
		expiry_counter++;
		mhi_log(MHI_MSG_ERROR,
			"Device is not RESET, sleeping and retrying.\n");
		msleep(MHI_READY_STATUS_TIMEOUT_MS);
		pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_addr, MHICTRL);
		MHI_READ_FIELD(pcie_word_val,
				MHICTRL_RESET_MASK,
				MHICTRL_RESET_SHIFT);
	}

	if (MHI_STATE_READY != pcie_word_val)
		return MHI_STATUS_DEVICE_NOT_READY;
	return MHI_STATUS_SUCCESS;
}

enum MHI_STATUS mhi_test_for_device_ready(struct mhi_device_ctxt *mhi_dev_ctxt)
{
	u32 pcie_word_val = 0;
+18 −1
Original line number Diff line number Diff line
@@ -24,12 +24,14 @@
/* Write only sysfs attributes */
static DEVICE_ATTR(MHI_M3, S_IWUSR, NULL, sysfs_init_m3);
static DEVICE_ATTR(MHI_M0, S_IWUSR, NULL, sysfs_init_m0);
static DEVICE_ATTR(MHI_RESET, S_IWUSR, NULL, sysfs_init_mhi_reset);

/* Read only sysfs attributes */

static struct attribute *mhi_attributes[] = {
	&dev_attr_MHI_M3.attr,
	&dev_attr_MHI_M0.attr,
	&dev_attr_MHI_RESET.attr,
	NULL,
};

@@ -141,7 +143,22 @@ ssize_t sysfs_init_m3(struct device *dev, struct device_attribute *attr,

	return count;
}

ssize_t sysfs_init_mhi_reset(struct device *dev, struct device_attribute *attr,
			const char *buf, size_t count)
{
	struct mhi_device_ctxt *mhi_dev_ctxt =
		&mhi_devices.device_list[0].mhi_ctxt;
	enum MHI_STATUS ret_val = MHI_STATUS_SUCCESS;
	mhi_log(MHI_MSG_INFO, "Triggering MHI Reset.\n");
	ret_val = mhi_trigger_reset(mhi_dev_ctxt);
	if (ret_val != MHI_STATUS_SUCCESS)
		mhi_log(MHI_MSG_CRITICAL,
			"Failed to trigger MHI RESET ret %d\n",
			ret_val);
	else
		mhi_log(MHI_MSG_INFO, "Triggered! MHI RESET\n");
	return count;
}
ssize_t sysfs_init_m0(struct device *dev, struct device_attribute *attr,
			const char *buf, size_t count)
{
Loading