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

Commit a9d907d1 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mhi: core: add support for handling MHI SYS ERROR state in low power mode"

parents 37c03435 007b6cca
Loading
Loading
Loading
Loading
+26 −10
Original line number Diff line number Diff line
@@ -43,8 +43,10 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
	u32 rx_status;
	enum mhi_ee ee;
	struct image_info *rddm_image = mhi_cntrl->rddm_image;
	const u32 delayus = 100;
	const u32 delayus = 5000;
	u32 retry = (mhi_cntrl->timeout_ms * 1000) / delayus;
	const u32 rddm_timeout_us = 200000;
	int rddm_retry = rddm_timeout_us / delayus; /* time to enter rddm */
	void __iomem *base = mhi_cntrl->bhie;

	MHI_LOG("Entered with pm_state:%s dev_state:%s ee:%s\n",
@@ -58,14 +60,8 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
	 * returning from this function, we expect device to reset.
	 *
	 * Normaly, we would read/write pm_state only after grabbing
	 * pm_lock, since we're in a panic, skipping it.
	 */

	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
		return -EIO;

	/*
	 * There is no gurantee this state change would take effect since
	 * pm_lock, since we're in a panic, skipping it. Also there is no
	 * gurantee this state change would take effect since
	 * we're setting it w/o grabbing pmlock, it's best effort
	 */
	mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT;
@@ -98,7 +94,27 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
	MHI_LOG("Trigger device into RDDM mode\n");
	mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR);

	MHI_LOG("Waiting for image download completion\n");
	MHI_LOG("Waiting for device to enter RDDM\n");
	while (rddm_retry--) {
		ee = mhi_get_exec_env(mhi_cntrl);
		if (ee == MHI_EE_RDDM)
			break;

		udelay(delayus);
	}

	if (rddm_retry <= 0) {
		/* This is a hardware reset, will force device to enter rddm */
		MHI_LOG(
			"Did not enter RDDM triggering host req. reset to force rddm\n");
		mhi_write_reg(mhi_cntrl, mhi_cntrl->regs,
			      MHI_SOC_RESET_REQ_OFFSET, MHI_SOC_RESET_REQ);
		udelay(delayus);
	}

	ee = mhi_get_exec_env(mhi_cntrl);
	MHI_LOG("Waiting for image download completion, current EE:%s\n",
		TO_MHI_EXEC_STR(ee));
	while (retry--) {
		ret = mhi_read_reg_field(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS,
					 BHIE_RXVECSTATUS_STATUS_BMSK,
+26 −2
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */

#include <linux/debugfs.h>
#include <linux/device.h>
@@ -1239,6 +1239,7 @@ EXPORT_SYMBOL(mhi_alloc_controller);
int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
{
	int ret;
	u32 bhie_off;

	mutex_lock(&mhi_cntrl->pm_mutex);

@@ -1258,16 +1259,39 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
	 * allocate rddm table if specified, this table is for debug purpose
	 * so we'll ignore erros
	 */
	if (mhi_cntrl->rddm_size)
	if (mhi_cntrl->rddm_size) {
		mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image,
				     mhi_cntrl->rddm_size);

		/*
		 * This controller supports rddm, we need to manually clear
		 * BHIE RX registers since por values are undefined.
		 */
		ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF,
				   &bhie_off);
		if (ret) {
			MHI_ERR("Error getting bhie offset\n");
			goto bhie_error;
		}

		memset_io(mhi_cntrl->regs + bhie_off + BHIE_RXVECADDR_LOW_OFFS,
			  0, BHIE_RXVECSTATUS_OFFS - BHIE_RXVECADDR_LOW_OFFS +
			  4);
	}

	mhi_cntrl->pre_init = true;

	mutex_unlock(&mhi_cntrl->pm_mutex);

	return 0;

bhie_error:
	if (mhi_cntrl->rddm_image) {
		mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->rddm_image);
		mhi_cntrl->rddm_image = NULL;
	}
	mhi_deinit_free_irq(mhi_cntrl);

error_setup_irq:
	mhi_deinit_dev_ctxt(mhi_cntrl);

+4 −0
Original line number Diff line number Diff line
@@ -125,6 +125,10 @@ extern struct bus_type mhi_bus_type;
#define MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_MASK (0xFFFFFFFF)
#define MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_SHIFT (0)

/* Host request register */
#define MHI_SOC_RESET_REQ_OFFSET (0xB0)
#define MHI_SOC_RESET_REQ BIT(0)

/* MHI misc capability registers */
#define MISC_OFFSET (0x24)
#define MISC_CAP_MASK (0xFFFFFFFF)
+10 −3
Original line number Diff line number Diff line
@@ -1381,12 +1381,20 @@ void mhi_ctrl_ev_task(unsigned long data)
{
	struct mhi_event *mhi_event = (struct mhi_event *)data;
	struct mhi_controller *mhi_cntrl = mhi_event->mhi_cntrl;
	enum mhi_dev_state state = MHI_STATE_MAX;
	enum mhi_dev_state state;
	enum MHI_PM_STATE pm_state = 0;
	int ret;

	MHI_VERB("Enter for ev_index:%d\n", mhi_event->er_index);

	/*
	 * we can check pm_state w/o a lock here because there is no way
	 * pm_state can change from reg access valid to no access while this
	 * therad being executed.
	 */
	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
		return;

	/* process ctrl events events */
	ret = mhi_event->process_event(mhi_cntrl, mhi_event, U32_MAX);

@@ -1396,7 +1404,6 @@ void mhi_ctrl_ev_task(unsigned long data)
	 */
	if (!ret) {
		write_lock_irq(&mhi_cntrl->pm_lock);
		if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
		state = mhi_get_mhi_state(mhi_cntrl);
		if (state == MHI_STATE_SYS_ERR) {
			MHI_ERR("MHI system error detected\n");
+6 −21
Original line number Diff line number Diff line
@@ -1045,6 +1045,12 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
		MHI_ERR("Did not enter M0 state, cur_state:%s pm_state:%s\n",
			TO_MHI_STATE_STR(mhi_cntrl->dev_state),
			to_mhi_pm_state_str(mhi_cntrl->pm_state));

		/*
		 * It's possible device already in error state and we didn't
		 * process it due to low power mode, force a check
		 */
		mhi_intvec_threaded_handlr(0, mhi_cntrl);
		return -EIO;
	}

@@ -1124,22 +1130,8 @@ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl)
		to_mhi_pm_state_str(mhi_cntrl->pm_state),
		TO_MHI_EXEC_STR(mhi_cntrl->ee));

	/* before rddm mode, we need to enter M0 state */
	ret = __mhi_device_get_sync(mhi_cntrl);
	if (ret)
		return ret;

	mutex_lock(&mhi_cntrl->pm_mutex);
	write_lock_irq(&mhi_cntrl->pm_lock);
	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
		goto no_reg_access;

	MHI_LOG("Triggering SYS_ERR to force rddm state\n");

	mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR);
	mhi_cntrl->wake_put(mhi_cntrl, false);
	write_unlock_irq(&mhi_cntrl->pm_lock);
	mutex_unlock(&mhi_cntrl->pm_mutex);

	/* wait for rddm event */
	MHI_LOG("Waiting for device to enter RDDM state\n");
@@ -1153,12 +1145,5 @@ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl)
		TO_MHI_EXEC_STR(mhi_cntrl->ee), ret);

	return ret;

no_reg_access:
	mhi_cntrl->wake_put(mhi_cntrl, false);
	write_unlock_irq(&mhi_cntrl->pm_lock);
	mutex_unlock(&mhi_cntrl->pm_mutex);

	return -EIO;
}
EXPORT_SYMBOL(mhi_force_rddm_mode);