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

Commit 0a538bb8 authored by Gilad Broner's avatar Gilad Broner Committed by Gerrit - the friendly Code Review server
Browse files

scsi: ufs: qcom-ice: block further requests until ICE config is complete



Requests that need to go through the ICE must be setup with a key
before and have a key index ready. In cases where the key is not
ready as it is not in the key cache, the ICE 'config_start' callback
returns -EAGAIN and we need to block further requests and call
'config_start' again from a non-atomic context until key setup
is ready and then resume requests handling.

Change-Id: I51ff1e99240386ce533b5ab3f5f024043532b0ad
Signed-off-by: default avatarGilad Broner <gbroner@codeaurora.org>
parent 149b76de
Loading
Loading
Loading
Loading
+45 −2
Original line number Diff line number Diff line
@@ -164,7 +164,35 @@ int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host)

out:
	return err;
}

static void ufs_qcom_ice_cfg_work(struct work_struct *work)
{
	struct ice_data_setting ice_set;
	struct ufs_qcom_host *qcom_host =
		container_of(work, struct ufs_qcom_host, ice_cfg_work);

	if (!qcom_host->ice.vops->config_start || !qcom_host->req_pending)
		return;

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

	/*
	 * config_start is called again as previous attempt returned -EAGAIN,
	 * this call shall now take care of the necessary key setup.
	 * 'ice_set' will not actually be used, instead the next call to
	 * config_start() for this request, in the normal call flow, will
	 * succeed as the key has now been setup.
	 */
	qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
		qcom_host->req_pending, &ice_set, false);

	/*
	 * Resume with requests processing. We assume config_start has been
	 * successful, but even if it wasn't we still must resume in order to
	 * allow for the request to be retried.
	 */
	ufshcd_scsi_unblock_requests(qcom_host->hba);
}

/**
@@ -193,6 +221,7 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host)
	}

	qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN;
	INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work);

out:
	return err;
@@ -300,8 +329,22 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
		err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
							req, &ice_set, true);
		if (err) {
			dev_err(dev, "%s: error in ice_vops->config %d\n",
				__func__, err);
			/*
			 * config_start() returns -EAGAIN when a key slot is
			 * available but still not configured. As configuration
			 * requires a non-atomic context, this means we should
			 * call the function again from the worker thread to do
			 * the configuration. For this request the error will
			 * propagate so it will be re-queued and until the
			 * configuration is is completed we block further
			 * request processing.
			 */
			if (err == -EAGAIN) {
				qcom_host->req_pending = req;
				if (schedule_work(&qcom_host->ice_cfg_work))
					ufshcd_scsi_block_requests(
							qcom_host->hba);
			}
			goto out;
		}
	}
+3 −0
Original line number Diff line number Diff line
@@ -337,6 +337,9 @@ struct ufs_qcom_host {
	/* Bitmask for enabling debug prints */
	u32 dbg_print_en;
	struct ufs_qcom_testbus testbus;

	struct work_struct ice_cfg_work;
	struct request *req_pending;
};

static inline u32
+26 −10
Original line number Diff line number Diff line
@@ -1955,14 +1955,6 @@ int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
{
	int ret = 0;

	ret = ufshcd_vops_crypto_engine_cfg_start(hba, task_tag);
	if (ret) {
		dev_err(hba->dev,
			"%s: failed to configure crypto engine %d\n",
			__func__, ret);
		return ret;
	}

	hba->lrb[task_tag].issue_time_stamp = ktime_get();
	hba->lrb[task_tag].complete_time_stamp = ktime_set(0, 0);
	ufshcd_clk_scaling_start_busy(hba);
@@ -2628,6 +2620,22 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
		goto out;
	}

	err = ufshcd_vops_crypto_engine_cfg_start(hba, tag);
	if (err) {
		if (err != -EAGAIN)
			dev_err(hba->dev,
				"%s: failed to configure crypto engine %d\n",
				__func__, err);

		scsi_dma_unmap(lrbp->cmd);
		lrbp->cmd = NULL;
		clear_bit_unlock(tag, &hba->lrb_in_use);
		ufshcd_release_all(hba);
		ufshcd_vops_pm_qos_req_end(hba, cmd->request, true);

		goto out;
	}

	/* Make sure descriptors are ready before ringing the doorbell */
	wmb();
	/* issue command to the controller */
@@ -2641,6 +2649,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
		clear_bit_unlock(tag, &hba->lrb_in_use);
		ufshcd_release_all(hba);
		ufshcd_vops_pm_qos_req_end(hba, cmd->request, true);
		ufshcd_vops_crypto_engine_cfg_end(hba, lrbp, cmd->request);
		dev_err(hba->dev, "%s: failed sending command, %d\n",
							__func__, err);
		err = DID_ERROR;
@@ -4961,7 +4970,7 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result)
			/* Mark completed command as NULL in LRB */
			lrbp->cmd = NULL;
			ufshcd_release_all(hba);
			if (cmd->request)
			if (cmd->request) {
				/*
				 * As we are accessing the "request" structure,
				 * this must be called before calling
@@ -4969,6 +4978,9 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result)
				 */
				ufshcd_vops_pm_qos_req_end(hba, cmd->request,
					true);
				ufshcd_vops_crypto_engine_cfg_end(hba,
						lrbp, cmd->request);
			}
			/* Do not touch lrbp after scsi done */
			cmd->scsi_done(cmd);
		} else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) {
@@ -5013,7 +5025,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
			lrbp->cmd = NULL;
			__ufshcd_release(hba, false);
			__ufshcd_hibern8_release(hba, false);
			if (cmd->request)
			if (cmd->request) {
				/*
				 * As we are accessing the "request" structure,
				 * this must be called before calling
@@ -5021,6 +5033,10 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
				 */
				ufshcd_vops_pm_qos_req_end(hba, cmd->request,
					false);
				ufshcd_vops_crypto_engine_cfg_end(hba,
					lrbp, cmd->request);
			}

			/* Do not touch lrbp after scsi done */
			cmd->scsi_done(cmd);
		} else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) {