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

Commit fd0ae096 authored by Skylar Chang's avatar Skylar Chang
Browse files

msm: ipa3: handle GSI STOP_IN_PROG in uC



In case IPA uC is trying to stop a GSI channel and fails
because the channels is stuck in STOP_IN_PROG state, AP needs
to send a DMA_TASK to IPA to unblock IPA uC.

Change-Id: Iecd8515ed9e3ba522977d38dcba80cffa57c56b4
Acked-by: default avatarAdy Abraham <adya@qti.qualcomm.com>
Signed-off-by: default avatarSkylar Chang <chiaweic@codeaurora.org>
parent f9e6b2e9
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -176,6 +176,11 @@
#define IPA_SMMU_UC_VA_SIZE 0x20000000
#define IPA_SMMU_UC_VA_END (IPA_SMMU_UC_VA_START +  IPA_SMMU_UC_VA_SIZE)

#define IPA_GSI_CHANNEL_STOP_MAX_RETRY 10
#define IPA_GSI_CHANNEL_STOP_PKT_SIZE 1
#define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000)
#define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000)


struct ipa3_client_names {
	enum ipa_client_type names[MAX_RESOURCE_TO_CLIENTS];
@@ -2248,5 +2253,6 @@ int ipa3_rt_read_tbl_from_hw(u32 tbl_idx,

int ipa3_calc_extra_wrd_bytes(const struct ipa_ipfltri_rule_eq *attrib);
int ipa3_restore_suspend_handler(void);
int ipa3_inject_dma_task_for_gsi(void);

#endif /* _IPA3_I_H_ */
+24 −2
Original line number Diff line number Diff line
@@ -112,7 +112,11 @@ enum ipa3_hw_errors {
	IPA_HW_INVALID_OPCODE          =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 4),
	IPA_HW_ZIP_ENGINE_ERROR        =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 5)
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 5),
	IPA_HW_CONS_DISABLE_CMD_GSI_STOP_FAILURE =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 6),
	IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 7)
};

/**
@@ -628,6 +632,7 @@ int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
	int index;
	union IpaHwCpuCmdCompletedResponseData_t uc_rsp;
	unsigned long flags;
	int retries = 0;

	IPA3_UC_LOCK(flags);

@@ -637,6 +642,7 @@ int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
		return -EBADF;
	}

send_cmd:
	if (ipa3_ctx->apply_rg10_wa) {
		if (!polling_mode)
			IPADBG("Overriding mode to polling mode\n");
@@ -648,7 +654,6 @@ int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdParams = cmd;
	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdOp = opcode;
	ipa3_ctx->uc_ctx.pending_cmd = opcode;

	ipa3_ctx->uc_ctx.uc_sram_mmio->responseOp = 0;
	ipa3_ctx->uc_ctx.uc_sram_mmio->responseParams = 0;

@@ -711,6 +716,23 @@ int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
	}

	if (ipa3_ctx->uc_ctx.uc_status != expected_status) {
		if (ipa3_ctx->uc_ctx.uc_status ==
			IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE) {
			retries++;
			if (retries == IPA_GSI_CHANNEL_STOP_MAX_RETRY) {
				IPAERR("Failed after %d tries\n", retries);
				IPA3_UC_UNLOCK(flags);
				BUG();
				return -EFAULT;
			}

			ipa3_inject_dma_task_for_gsi();
			/* sleep for short period to flush IPA */
			usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
				IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
			goto send_cmd;
		}

		IPAERR("Recevied status %u, Expected status %u\n",
			ipa3_ctx->uc_ctx.uc_status, expected_status);
		IPA3_UC_UNLOCK(flags);
+55 −52
Original line number Diff line number Diff line
@@ -46,11 +46,6 @@
		IPA_ENDP_INIT_AGGR_N_AGGR_PKT_LIMIT_BMSK >> \
		IPA_ENDP_INIT_AGGR_N_AGGR_PKT_LIMIT_SHFT)

#define IPA_GSI_CHANNEL_STOP_MAX_RETRY 10
#define IPA_GSI_CHANNEL_STOP_PKT_SIZE 1
#define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000)
#define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000)

/* In IPAv3 only endpoints 0-3 can be configured to deaggregation */
#define IPA_EP_SUPPORTS_DEAGGR(idx) ((idx) >= 0 && (idx) <= 3)

@@ -4959,6 +4954,51 @@ void ipa3_suspend_apps_pipes(bool suspend)
		ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
}

/**
 * ipa3_inject_dma_task_for_gsi()- Send TMA_TASK to IPA for GSI stop channel
 *
 * Send a DMA_TASK of 1B to IPA to unblock GSI channel in STOP_IN_PROG.
 * Return value: 0 on success, negative otherwise
 */
int ipa3_inject_dma_task_for_gsi(void)
{
	static struct ipa3_mem_buffer mem = {0};
	static struct ipa3_hw_imm_cmd_dma_task_32b_addr cmd = {0};
	struct ipa3_desc desc = {0};

	/* allocate the memory only for the very first time */
	if (!mem.base) {
		IPADBG("Allocate mem\n");
		mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
		mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
			mem.size,
			&mem.phys_base,
			GFP_KERNEL);
		if (!mem.base) {
			IPAERR("no mem\n");
			return -EFAULT;
		}

		cmd.flsh = 1;
		cmd.size1 = mem.size;
		cmd.addr1 = mem.phys_base;
		cmd.packet_size = mem.size;
	}

	desc.opcode = IPA_DMA_TASK_32B_ADDR(1);
	desc.pyld = &cmd;
	desc.len = sizeof(cmd);
	desc.type = IPA_IMM_CMD_DESC;

	IPADBG("sending 1B packet to IPA\n");
	if (ipa3_send_cmd(1, &desc)) {
		IPAERR("ipa3_send_cmd failed\n");
		return -EFAULT;
	}

	return 0;
}

/**
 * ipa3_stop_gsi_channel()- Stops a GSI channel in IPA
 * @chan_hdl: GSI channel handle
@@ -4970,8 +5010,6 @@ void ipa3_suspend_apps_pipes(bool suspend)
 */
int ipa3_stop_gsi_channel(u32 clnt_hdl)
{
	struct ipa3_hw_imm_cmd_dma_task_32b_addr cmd;
	struct ipa3_desc desc;
	struct ipa3_mem_buffer mem;
	int res;
	int i;
@@ -4989,64 +5027,29 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)

	memset(&mem, 0, sizeof(mem));

	if (IPA_CLIENT_IS_PROD(ep->client)) {
		res = gsi_stop_channel(ep->gsi_chan_hdl);
		goto bail;
	}
	if (IPA_CLIENT_IS_PROD(ep->client))
		return gsi_stop_channel(ep->gsi_chan_hdl);

	for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
		IPADBG("Calling gsi_stop_channel\n");
		res = gsi_stop_channel(ep->gsi_chan_hdl);
		IPADBG("gsi_stop_channel returned %d\n", res);
		if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
			goto bail;
		/* Send a 1B packet DMA_RASK to IPA and try again*/
		IPADBG("gsi_stop_channel timed out\n");
		if (!mem.base) {
			mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
			mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
				mem.size,
				&mem.phys_base,
				GFP_KERNEL);
			if (!mem.base) {
				IPAERR("no mem\n");
				res = -EFAULT;
				goto bail;
			}

			memset(&cmd, 0, sizeof(cmd));
			cmd.flsh = 1;
			cmd.size1 = mem.size;
			cmd.addr1 = mem.phys_base;
			cmd.packet_size = mem.size;
		}

		memset(&desc, 0, sizeof(desc));
		desc.opcode = IPA_DMA_TASK_32B_ADDR(1);
		desc.pyld = &cmd;
		desc.len = sizeof(cmd);
		desc.type = IPA_IMM_CMD_DESC;
			return res;

		IPADBG("sending 1B packet to IPA\n");
		if (ipa3_send_cmd(1, &desc)) {
			IPAERR("ipa3_send_cmd failed\n");
			dma_free_coherent(ipa3_ctx->pdev,
				mem.size,
				mem.base,
				mem.phys_base);
			res = -EFAULT;
			goto bail;
		/* Send a 1B packet DMA_RASK to IPA and try again*/
		res = ipa3_inject_dma_task_for_gsi();
		if (res) {
			IPAERR("ipa3_inject_dma_task_for_gsi failed\n");
			return res;
		}

		/* sleep for short period to flush IPA */
		usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
			IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
	}
bail:
	if (mem.base)
		dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base,
			mem.phys_base);
	return res;

	return -EFAULT;
}

/**