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

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

Merge "mmc: cmdq_hci: ice: Handle ICE HCI errors in cmdq mode"

parents bf7c99c1 b6782991
Loading
Loading
Loading
Loading
+130 −4
Original line number Diff line number Diff line
@@ -145,6 +145,29 @@ static void cmdq_clear_set_irqs(struct cmdq_host *cq_host, u32 clear, u32 set)
	mb();
}

static int cmdq_clear_task_poll(struct cmdq_host *cq_host, unsigned int tag)
{
	int retries = 100;

	cmdq_clear_set_irqs(cq_host, CQIS_TCL, 0);
	cmdq_writel(cq_host, 1<<tag, CQTCLR);
	while (retries) {
		/*
		 * Task Clear register and doorbell,
		 * both should indicate that task is cleared
		 */
		if ((cmdq_readl(cq_host, CQTCLR) & 1<<tag) ||
			(cmdq_readl(cq_host, CQTDBR) & 1<<tag)) {
			udelay(5);
			retries--;
			continue;
		} else
			break;
	}

	cmdq_clear_set_irqs(cq_host, 0, CQIS_TCL);
	return retries ? 0 : -ETIMEDOUT;
}

#define DRV_NAME "cmdq-host"

@@ -345,6 +368,7 @@ static int cmdq_enable(struct mmc_host *mmc)
{
	int err = 0;
	u32 cqcfg;
	u32 cqcap = 0;
	bool dcmd_enable;
	struct cmdq_host *cq_host = mmc_cmdq_private(mmc);

@@ -373,6 +397,18 @@ static int cmdq_enable(struct mmc_host *mmc)
	cqcfg = ((cq_host->caps & CMDQ_TASK_DESC_SZ_128 ? CQ_TASK_DESC_SZ : 0) |
			(dcmd_enable ? CQ_DCMD : 0));

	cqcap = cmdq_readl(cq_host, CQCAP);
	if (cqcap & CQCAP_CS) {
		/*
		 * In case host controller supports cryptographic operations
		 * then, it uses 128bit task descriptor. Upper 64 bits of task
		 * descriptor would be used to pass crypto specific informaton.
		 */
		cq_host->caps |= CMDQ_CAP_CRYPTO_SUPPORT |
				 CMDQ_TASK_DESC_SZ_128;
		cqcfg |= CQ_ICE_ENABLE;
	}

	cmdq_writel(cq_host, cqcfg, CQCFG);
	/* enable CQ_HOST */
	cmdq_writel(cq_host, cmdq_readl(cq_host, CQCFG) | CQ_ENABLE,
@@ -688,6 +724,30 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc,
		upper_32_bits(*task_desc));
}

static inline
void cmdq_prep_crypto_desc(struct cmdq_host *cq_host, u64 *task_desc,
			u64 ice_ctx)
{
	u64 *ice_desc = NULL;

	if (cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) {
		/*
		 * Get the address of ice context for the given task descriptor.
		 * ice context is present in the upper 64bits of task descriptor
		 * ice_conext_base_address = task_desc + 8-bytes
		 */
		ice_desc = (__le64 *)((u8 *)task_desc +
						CQ_TASK_DESC_TASK_PARAMS_SIZE);
		memset(ice_desc, 0, CQ_TASK_DESC_ICE_PARAMS_SIZE);

		/*
		 *  Assign upper 64bits data of task descritor with ice context
		 */
		if (ice_ctx)
			*ice_desc = cpu_to_le64(ice_ctx);
	}
}

static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -711,6 +771,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
	u32 tag = mrq->cmdq_req->tag;
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
	struct sdhci_host *host = mmc_priv(mmc);
	u64 ice_ctx = 0;

	if (!cq_host->enabled) {
		pr_err("%s: CMDQ host not enabled yet !!!\n",
@@ -730,7 +791,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
	}

	if (cq_host->ops->crypto_cfg) {
		err = cq_host->ops->crypto_cfg(mmc, mrq, tag);
		err = cq_host->ops->crypto_cfg(mmc, mrq, tag, &ice_ctx);
		if (err) {
			pr_err("%s: failed to configure crypto: err %d tag %d\n",
					mmc_hostname(mmc), err, tag);
@@ -743,6 +804,9 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
	cmdq_prep_task_desc(mrq, &data, 1,
			    (mrq->cmdq_req->cmdq_req_flags & QBR));
	*task_desc = cpu_to_le64(data);

	cmdq_prep_crypto_desc(cq_host, task_desc, ice_ctx);

	cmdq_log_task_desc_history(cq_host, *task_desc, false);

	err = cmdq_prep_tran_desc(mrq, cq_host, tag);
@@ -787,7 +851,8 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag)
			    CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG);

	cmdq_runtime_pm_put(cq_host);
	if (cq_host->ops->crypto_cfg_reset)
	if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) &&
			cq_host->ops->crypto_cfg_reset)
		cq_host->ops->crypto_cfg_reset(mmc, tag);
	mrq->done(mrq);
}
@@ -801,6 +866,8 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
	struct mmc_request *mrq;
	int ret;
	u32 dbr_set = 0;
	u32 dev_pend_set = 0;
	int stat_err = 0;

	status = cmdq_readl(cq_host, CQIS);

@@ -809,7 +876,9 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
	MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n",
		__func__, status, err);

	if (err || (status & CQIS_RED)) {
	stat_err = status & (CQIS_RED | CQIS_GCE | CQIS_ICCE);

	if (err || stat_err) {
		err_info = cmdq_readl(cq_host, CQTERRI);
		pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n",
		       mmc_hostname(mmc), err, status, err_info);
@@ -912,7 +981,7 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
		 * CQE detected a response error from device
		 * In most cases, this would require a reset.
		 */
		if (status & CQIS_RED) {
		if (stat_err & CQIS_RED) {
			/*
			 * will check if the RED error is due to a bkops
			 * exception once the queue is empty
@@ -931,6 +1000,62 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
			mrq->cmdq_req->resp_arg = cmdq_readl(cq_host, CQCRA);
		}

		/*
		 * Generic Crypto error detected by CQE.
		 * Its a fatal, would require cmdq reset.
		 */
		if (stat_err & CQIS_GCE) {
			if (mrq->data)
				mrq->data->error = -EIO;
			pr_err("%s: Crypto generic error while processing task %lu!",
				mmc_hostname(mmc), tag);
			MMC_TRACE(mmc, "%s: GCE error detected with tag %lu\n",
					__func__, tag);
		}
		/*
		 * Invalid crypto config error detected by CQE, clear the task.
		 * Task can be cleared only when CQE is halt state.
		 */
		if (stat_err & CQIS_ICCE) {
			/*
			 * Invalid Crypto Config Error is detected at the
			 * beginning of the transfer before the actual execution
			 * started. So just clear the task in CQE. No need to
			 * clear in device. Only the task which caused ICCE has
			 * to be cleared. Other tasks can be continue processing
			 * The first task which is about to be prepared would
			 * cause ICCE Error.
			 */
			dbr_set = cmdq_readl(cq_host, CQTDBR);
			dev_pend_set = cmdq_readl(cq_host, CQDPT);
			if (dbr_set ^ dev_pend_set)
				tag = ffs(dbr_set ^ dev_pend_set) - 1;
			mrq = get_req_by_tag(cq_host, tag);
			pr_err("%s: Crypto config error while processing task %lu!",
				mmc_hostname(mmc), tag);
			MMC_TRACE(mmc, "%s: ICCE error with tag %lu\n",
						__func__, tag);
			if (mrq->data)
				mrq->data->error = -EIO;
			else if (mrq->cmd)
				mrq->cmd->error = -EIO;
			/*
			 * If CQE is halted and tag is valid then clear the task
			 * then un-halt CQE and set flag to skip error recovery.
			 * If any of the condtions is not met thene it will
			 * enter into default error recovery path.
			 */
			if (!ret && (dbr_set ^ dev_pend_set)) {
				ret = cmdq_clear_task_poll(cq_host, tag);
				if (ret) {
					pr_err("%s: %s: task[%lu] clear failed ret=%d\n",
						mmc_hostname(mmc),
						__func__, tag, ret);
				} else if (!cmdq_halt_poll(mmc, false)) {
					mrq->cmdq_req->skip_err_handling = true;
				}
			}
		}
		cmdq_finish_data(mmc, tag);
	} else {
		cmdq_writel(cq_host, status, CQIS);
@@ -1001,6 +1126,7 @@ static int cmdq_halt_poll(struct mmc_host *mmc, bool halt)
			cq_host->ops->clear_set_irqs(mmc, true);
		cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT,
			    CQCTL);
		mmc_host_clr_halt(mmc);
		return 0;
	}

+10 −2
Original line number Diff line number Diff line
@@ -18,11 +18,13 @@
#define CQVER		0x00
/* capabilities */
#define CQCAP		0x04
#define CQCAP_CS	(1 << 28)
/* configuration */
#define CQCFG		0x08
#define CQ_DCMD		0x00001000
#define CQ_TASK_DESC_SZ 0x00000100
#define CQ_ENABLE	0x00000001
#define CQ_ICE_ENABLE	0x00000002

/* control */
#define CQCTL		0x0C
@@ -35,6 +37,8 @@
#define CQIS_TCC	(1 << 1)
#define CQIS_RED	(1 << 2)
#define CQIS_TCL	(1 << 3)
#define CQIS_GCE	(1 << 4)
#define CQIS_ICCE	(1 << 5)

/* interrupt status enable */
#define CQISTE		0x14
@@ -110,7 +114,7 @@
/* command response argument */
#define CQCRA		0x5C

#define CQ_INT_ALL	0xF
#define CQ_INT_ALL	0x3F
#define CQIC_DEFAULT_ICCTH 31
#define CQIC_DEFAULT_ICTOVAL 1

@@ -144,6 +148,9 @@
#define CQ_VENDOR_CFG	0x100
#define CMDQ_SEND_STATUS_TRIGGER (1 << 31)

#define CQ_TASK_DESC_TASK_PARAMS_SIZE	8
#define CQ_TASK_DESC_ICE_PARAMS_SIZE	8

struct task_history {
	u64 task;
	bool is_dcmd;
@@ -161,6 +168,7 @@ struct cmdq_host {
	u32 dcmd_slot;
	u32 caps;
#define CMDQ_TASK_DESC_SZ_128 0x1
#define CMDQ_CAP_CRYPTO_SUPPORT 0x2

	u32 quirks;
#define CMDQ_QUIRK_SHORT_TXFR_DESC_SZ 0x1
@@ -209,7 +217,7 @@ struct cmdq_host_ops {
	int (*reset)(struct mmc_host *mmc);
	void (*post_cqe_halt)(struct mmc_host *mmc);
	int (*crypto_cfg)(struct mmc_host *mmc, struct mmc_request *mrq,
				u32 slot);
				u32 slot, u64 *ice_ctx);
	void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot);
};

+68 −2
Original line number Diff line number Diff line
@@ -276,6 +276,58 @@ void sdhci_msm_ice_update_cfg(struct sdhci_host *host, u64 lba,
	mb();
}

static inline
void sdhci_msm_ice_hci_update_cmdq_cfg(u64 dun, unsigned int bypass,
				short key_index, u64 *ice_ctx)
{
	/*
	 * The naming convention got changed between ICE2.0 and ICE3.0
	 * registers fields. Below is the equivalent names for
	 * ICE3.0 Vs ICE2.0:
	 *   Data Unit Number(DUN) == Logical Base address(LBA)
	 *   Crypto Configuration index (CCI) == Key Index
	 *   Crypto Enable (CE) == !BYPASS
	 */
	if (ice_ctx)
		*ice_ctx = DATA_UNIT_NUM(dun) |
			CRYPTO_CONFIG_INDEX(key_index) |
			CRYPTO_ENABLE(!bypass);
}

static
void sdhci_msm_ice_hci_update_noncq_cfg(struct sdhci_host *host,
		u64 dun, unsigned int bypass, short key_index)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;
	unsigned int crypto_params = 0;
	/*
	 * The naming convention got changed between ICE2.0 and ICE3.0
	 * registers fields. Below is the equivalent names for
	 * ICE3.0 Vs ICE2.0:
	 *   Data Unit Number(DUN) == Logical Base address(LBA)
	 *   Crypto Configuration index (CCI) == Key Index
	 *   Crypto Enable (CE) == !BYPASS
	 */
	/* Configure ICE bypass mode */
	crypto_params |=
		(!bypass & MASK_SDHCI_MSM_ICE_HCI_PARAM_CE)
			<< OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE;
	/* Configure Crypto Configure Index (CCI) */
	crypto_params |= (key_index &
			 MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI)
			 << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI;

	writel_relaxed((crypto_params & 0xFFFFFFFF),
		msm_host->cryptoio + ICE_NONCQ_CRYPTO_PARAMS);

	/* Update DUN */
	writel_relaxed((dun & 0xFFFFFFFF),
		msm_host->cryptoio + ICE_NONCQ_CRYPTO_DUN);
	/* Ensure ICE registers are configured before issuing SDHCI request */
	mb();
}

int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
			u32 slot)
{
@@ -308,7 +360,14 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
				slot, bypass, key_index);
	}

	if (msm_host->ice_hci_support) {
		/* For ICE HCI / ICE3.0 */
		sdhci_msm_ice_hci_update_noncq_cfg(host, lba, bypass,
						key_index);
	} else {
		/* For ICE versions earlier to ICE3.0 */
		sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
	}
	return 0;
}

@@ -344,7 +403,14 @@ int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
				slot, bypass, key_index);
	}

	if (msm_host->ice_hci_support) {
		/* For ICE HCI / ICE3.0 */
		sdhci_msm_ice_hci_update_cmdq_cfg(lba, bypass, key_index,
						ice_ctx);
	} else {
		/* For ICE versions earlier to ICE3.0 */
		sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
	}
	return 0;
}

+8 −2
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@
#define ICE_HCI_SUPPORT		(1 << 28)
#define ICE_CQ_CONFIG		0x08
#define CRYPTO_GENERAL_ENABLE	(1 << 1)
#define ICE_NONCQ_CRYPTO_PARAMS	0x70
#define ICE_NONCQ_CRYPTO_DUN	0x74

/* ICE3.0 register which got added hc reg space */
#define HC_VENDOR_SPECIFIC_FUNC4	0x260
@@ -52,8 +54,10 @@
/* SDHCI MSM ICE CTRL Info register offset */
enum {
	OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS     = 0,
	OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX  = 0x1,
	OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU        = 0x6,
	OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX  = 1,
	OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU        = 6,
	OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI	  = 0,
	OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE	  = 8,
};

/* SDHCI MSM ICE CTRL Info register masks */
@@ -61,6 +65,8 @@ enum {
	MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS     = 0x1,
	MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX  = 0x1F,
	MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU        = 0x7,
	MASK_SDHCI_MSM_ICE_HCI_PARAM_CE		= 0x1,
	MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI	= 0xff
};

/* SDHCI MSM ICE encryption/decryption bypass state */
+4 −3
Original line number Diff line number Diff line
@@ -3775,7 +3775,7 @@ static void sdhci_cmdq_post_cqe_halt(struct mmc_host *mmc)
	sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
}
static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
		struct mmc_request *mrq, u32 slot)
		struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
{
	struct sdhci_host *host = mmc_priv(mmc);
	int err = 0;
@@ -3794,7 +3794,8 @@ static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
	}

	if (host->ops->crypto_engine_cmdq_cfg) {
		err = host->ops->crypto_engine_cmdq_cfg(host, mrq, slot, NULL);
		err = host->ops->crypto_engine_cmdq_cfg(host, mrq,
				slot, ice_ctx);
		if (err) {
			pr_err("%s: failed to configure crypto\n",
					mmc_hostname(host->mmc));
@@ -3862,7 +3863,7 @@ static void sdhci_cmdq_post_cqe_halt(struct mmc_host *mmc)
}

static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
		struct mmc_request *mrq, u32 slot)
		struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
{
	return 0;
}
Loading