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

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

Merge "scsi: ufs: add crypto related operations"

parents 3e0c1456 1caf99c7
Loading
Loading
Loading
Loading
+37 −157
Original line number Diff line number Diff line
@@ -12,15 +12,11 @@

#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/async.h>
#include <linux/of.h>
#include <linux/device-mapper.h>
#include <linux/blk_types.h>
#include <linux/blkdev.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/regulator/consumer.h>
@@ -30,8 +26,6 @@
#include <soc/qcom/scm.h>
#include "iceregs.h"

#define SCM_IO_READ	0x1
#define SCM_IO_WRITE	0x2
#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
	((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff)))

@@ -52,8 +46,6 @@
#define QCOM_ICE_TYPE_NAME_LEN 8
#define QCOM_ICE_MAX_BIST_CHECK_COUNT 100

const struct qcom_ice_variant_ops qcom_ice_ops;

struct ice_clk_info {
	struct list_head list;
	struct clk *clk;
@@ -87,13 +79,10 @@ struct ice_device {
	void __iomem		*mmio;
	struct resource		*res;
	int			irq;
	bool			is_irq_enabled;
	bool			is_ice_enabled;
	bool			is_ice_disable_fuse_blown;
	bool			is_clear_irq_pending;
	ice_error_cb		error_cb;
	void			*host_controller_data; /* UFS/EMMC/other? */
	spinlock_t		lock;
	struct list_head	clk_list_head;
	u32			ice_hw_version;
	bool			is_ice_clk_available;
@@ -126,7 +115,7 @@ static int qti_ice_setting_config(struct request *req,

	if (ice_dev->is_ice_disable_fuse_blown) {
		pr_err("%s ICE disabled fuse is blown\n", __func__);
		return -ENODEV;
		return -EPERM;
	}

	if ((short)(crypto_data->key_index) >= 0) {
@@ -403,7 +392,6 @@ static void qcom_ice_enable(struct ice_device *ice_dev)
	 */
	mb();


	if ((ICE_REV(ice_dev->ice_hw_version, MAJOR) > 2) ||
		((ICE_REV(ice_dev->ice_hw_version, MAJOR) == 2) &&
		 (ICE_REV(ice_dev->ice_hw_version, MINOR) >= 1))) {
@@ -430,7 +418,7 @@ static int qcom_ice_verify_ice(struct ice_device *ice_dev)
		pr_err("%s: Unknown QC ICE device at 0x%lu, rev %d.%d.%d\n",
			__func__, (unsigned long)ice_dev->mmio,
			maj_rev, min_rev, step_rev);
		return -EIO;
		return -ENODEV;
	}
	ice_dev->ice_hw_version = rev;

@@ -467,99 +455,22 @@ static void qcom_ice_disable_intr(struct ice_device *ice_dev)
	mb();
}

static int qcom_ice_clear_irq(struct ice_device *ice_dev)
{
	qcom_ice_writel(ice_dev, QCOM_ICE_NON_SEC_IRQ_MASK,
			QCOM_ICE_REGS_NON_SEC_IRQ_CLR);
	/*
	 * Ensure previous instructions was completed before issuing next
	 * ICE initialization/optimization instruction
	 */
	mb();
	ice_dev->is_clear_irq_pending = false;

	return 0;
}

static irqreturn_t qcom_ice_isr(int isr, void *data)
{
	irqreturn_t retval = IRQ_NONE;
	unsigned int intr_status, clear_reg;
	u32 status;
	struct ice_device *ice_dev = data;
	enum ice_error_code err;
	unsigned long flags;

	spin_lock_irqsave(&ice_dev->lock, flags);
	intr_status = qcom_ice_readl(ice_dev, QCOM_ICE_REGS_NON_SEC_IRQ_STTS);
	if (intr_status) {
		clear_reg = qcom_ice_readl(ice_dev,
				QCOM_ICE_REGS_NON_SEC_IRQ_CLR);

		/* Check the source of interrupt */
		if (intr_status & QCOM_ICE_STREAM1_PREMATURE_LBA_CHANGE) {
			err = ICE_ERROR_STREAM1_PREMATURE_LBA_CHANGE;
			clear_reg |= QCOM_ICE_STREAM1_PREMATURE_LBA_CHANGE;
		} else if (intr_status &
				QCOM_ICE_STREAM2_PREMATURE_LBA_CHANGE) {
			err = ICE_ERROR_STREAM2_PREMATURE_LBA_CHANGE;
			clear_reg |= QCOM_ICE_STREAM2_PREMATURE_LBA_CHANGE;
		} else if (intr_status & QCOM_ICE_STREAM1_NOT_EXPECTED_LBO) {
			err = ICE_ERROR_STREAM1_UNEXPECTED_LBA;
			clear_reg |= QCOM_ICE_STREAM1_NOT_EXPECTED_LBO;
		} else if (intr_status & QCOM_ICE_STREAM2_NOT_EXPECTED_LBO) {
			err = ICE_ERROR_STREAM2_UNEXPECTED_LBA;
			clear_reg |= QCOM_ICE_STREAM2_NOT_EXPECTED_LBO;
		} else if (intr_status & QCOM_ICE_STREAM1_NOT_EXPECTED_DUN) {
			err = ICE_ERROR_STREAM1_NOT_EXPECTED_DUN;
			clear_reg |= QCOM_ICE_STREAM1_NOT_EXPECTED_DUN;
		} else if (intr_status & QCOM_ICE_STREAM2_NOT_EXPECTED_DUN) {
			err = ICE_ERROR_STREAM2_NOT_EXPECTED_DUN;
			clear_reg |= QCOM_ICE_STREAM2_NOT_EXPECTED_DUN;
		}  else if (intr_status & QCOM_ICE_STREAM1_NOT_EXPECTED_DUS) {
			err = ICE_ERROR_STREAM1_NOT_EXPECTED_DUS;
			clear_reg |= QCOM_ICE_STREAM1_NOT_EXPECTED_DUS;
		} else if (intr_status & QCOM_ICE_STREAM2_NOT_EXPECTED_DUS) {
			err = ICE_ERROR_STREAM2_NOT_EXPECTED_DUS;
			clear_reg |= QCOM_ICE_STREAM2_NOT_EXPECTED_DUS;
		} else if (intr_status & QCOM_ICE_STREAM1_NOT_EXPECTED_DBO) {
			err = ICE_ERROR_STREAM1_NOT_EXPECTED_DBO;
			clear_reg |= QCOM_ICE_STREAM1_NOT_EXPECTED_DBO;
		} else if (intr_status & QCOM_ICE_STREAM2_NOT_EXPECTED_DBO) {
			err = ICE_ERROR_STREAM2_NOT_EXPECTED_DBO;
			clear_reg |= QCOM_ICE_STREAM2_NOT_EXPECTED_DBO;
		} else if (intr_status &
			QCOM_ICE_STREAM1_NOT_EXPECTED_ENC_SEL) {
			err = ICE_ERROR_STREAM1_NOT_EXPECTED_ENC_SEL;
			clear_reg |= QCOM_ICE_STREAM1_NOT_EXPECTED_ENC_SEL;
		} else if (intr_status &
			QCOM_ICE_STREAM2_NOT_EXPECTED_ENC_SEL) {
			err = ICE_ERROR_STREAM2_NOT_EXPECTED_ENC_SEL;
			clear_reg |= QCOM_ICE_STREAM2_NOT_EXPECTED_ENC_SEL;
		} else if (intr_status &
			QCOM_ICE_STREAM1_NOT_EXPECTED_CONF_IDX) {
			err = ICE_ERROR_STREAM1_NOT_EXPECTED_CONF_IDX;
			clear_reg |= QCOM_ICE_STREAM1_NOT_EXPECTED_CONF_IDX;
		} else if (intr_status &
			QCOM_ICE_STREAM2_NOT_EXPECTED_CONF_IDX) {
			err = ICE_ERROR_STREAM2_NOT_EXPECTED_CONF_IDX;
			clear_reg |= QCOM_ICE_STREAM2_NOT_EXPECTED_CONF_IDX;
		} else if (intr_status &
			QCOM_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS) {
			err = ICE_ERROR_STREAM1_NOT_EXPECTED_NEW_TRNS;
			clear_reg |= QCOM_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS;
		} else if (intr_status &
			QCOM_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS) {
			err = ICE_ERROR_STREAM2_NOT_EXPECTED_NEW_TRNS;
			clear_reg |= QCOM_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS;
		}

		ice_dev->error_cb(ice_dev->host_controller_data, err);

	status = qcom_ice_readl(ice_dev, QCOM_ICE_REGS_NON_SEC_IRQ_STTS);
	if (status) {
		ice_dev->error_cb(ice_dev->host_controller_data, status);

		/* Interrupt has been handled. Clear the IRQ */
		qcom_ice_clear_irq(ice_dev);
		qcom_ice_writel(ice_dev, status, QCOM_ICE_REGS_NON_SEC_IRQ_CLR);
		/* Ensure instruction is completed */
		mb();
		retval = IRQ_HANDLED;
	}
	spin_unlock_irqrestore(&ice_dev->lock, flags);
	return retval;
}

@@ -672,7 +583,6 @@ static int qcom_ice_get_device_tree_data(struct platform_device *pdev,
						(&pdev->dev)->of_node,
						"qcom,enable-ice-clk");


	if (ice_dev->is_ice_clk_available) {
		rc = qcom_ice_parse_clock_info(pdev, ice_dev);
		if (rc)
@@ -686,12 +596,9 @@ static int qcom_ice_get_device_tree_data(struct platform_device *pdev,
		}
		rc = devm_request_irq(dev, irq, qcom_ice_isr, 0,
				dev_name(dev), ice_dev);
		if (rc) {
		if (rc)
			goto err_dev;
		} else {
		ice_dev->irq = irq;
			ice_dev->is_irq_enabled = true;
		}
		pr_info("ICE IRQ = %d\n", ice_dev->irq);
		qcom_ice_parse_ice_instance_type(pdev, ice_dev);
	}
@@ -815,7 +722,7 @@ static int qcom_ice_probe(struct platform_device *pdev)
		pr_err("create character device failed.\n");
		goto err_ice_dev;
	}
	spin_lock_init(&ice_dev->lock);

	/*
	 * If ICE is enabled here, it would be waste of power.
	 * We would enable ICE when first request for crypto
@@ -884,7 +791,7 @@ static int qcom_ice_restore_config(void)

static int qcom_ice_init_clocks(struct ice_device *ice)
{
	int ret = -1;
	int ret = -EINVAL;
	struct ice_clk_info *clki;
	struct device *dev = ice->pdev;
	struct list_head *head = &ice->clk_list_head;
@@ -993,7 +900,7 @@ static int qcom_ice_update_sec_cfg(struct ice_device *ice_dev)
{
	int ret = 0, scm_ret = 0;

	/* scm command buffer structrue */
	/* scm command buffer structure */
	struct qcom_scm_cmd_buf {
		unsigned int device_id;
		unsigned int spare;
@@ -1039,15 +946,14 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev)
	}

	if (ice_dev->is_ice_clk_available) {
		if (qcom_ice_init_clocks(ice_dev)) {
			err = -ICE_ERROR_IMPROPER_INITIALIZATION;
		err = qcom_ice_init_clocks(ice_dev);
		if (err)
			goto out;
		}
		if (qcom_ice_bus_register(ice_dev)) {
			err = -ICE_ERROR_IMPROPER_INITIALIZATION;

		err = qcom_ice_bus_register(ice_dev);
		if (err)
			goto out;
	}
	}

	/*
	 * It is possible that ICE device is not probed when host is probed
@@ -1055,15 +961,13 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev)
	 * defered, it can cause power collapse for host and that can wipe
	 * configurations of host & ice. It is prudent to restore the config
	 */
	if (qcom_ice_update_sec_cfg(ice_dev)) {
		err = -ICE_ERROR_ICE_TZ_INIT_FAILED;
	err = qcom_ice_update_sec_cfg(ice_dev);
	if (err)
		goto out;
	}

	if (qcom_ice_verify_ice(ice_dev)) {
		err = -ICE_ERROR_UNEXPECTED_ICE_DEVICE;
	err = qcom_ice_verify_ice(ice_dev);
	if (err)
		goto out;
	}

	/* if ICE_DISABLE_FUSE is blown, return immediately
	 * Currently, FORCE HW Keys are also disabled, since
@@ -1079,7 +983,7 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev)
		ice_dev->is_ice_disable_fuse_blown = true;
		pr_err("%s: Error: ICE_ERROR_HW_DISABLE_FUSE_BLOWN\n",
								__func__);
		err = -ICE_ERROR_HW_DISABLE_FUSE_BLOWN;
		err = -EPERM;
		goto out;
	}

@@ -1087,7 +991,7 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev)
	if (ICE_REV(ice_dev->ice_hw_version, MAJOR) == 1 &&
		!qcom_ice_secure_ice_init(ice_dev)) {
		pr_err("%s: Error: ICE_ERROR_ICE_TZ_INIT_FAILED\n", __func__);
		err = -ICE_ERROR_ICE_TZ_INIT_FAILED;
		err = -EFAULT;
		goto out;
	}

@@ -1127,14 +1031,13 @@ static int qcom_ice_init(struct platform_device *pdev,

	return qcom_ice_finish_init(ice_dev);
}
EXPORT_SYMBOL(qcom_ice_init);

static int qcom_ice_finish_power_collapse(struct ice_device *ice_dev)
{
	int err = 0;

	if (ice_dev->is_ice_disable_fuse_blown) {
		err = -ICE_ERROR_HW_DISABLE_FUSE_BLOWN;
		err = -EPERM;
		goto out;
	}

@@ -1156,15 +1059,10 @@ static int qcom_ice_finish_power_collapse(struct ice_device *ice_dev)
			 * ICE driver should call TZ to restore keys
			 */
			if (qcom_ice_restore_config()) {
				err = -ICE_ERROR_ICE_KEY_RESTORE_FAILED;
				err = -EFAULT;
				goto out;
			}
		}
		/*
		 * INTR Status are not retained. So there is no need to
		 * clear those.
		 */
		ice_dev->is_clear_irq_pending = false;
	}

	ice_dev->ice_reset_complete_time = ktime_get();
@@ -1202,7 +1100,6 @@ static int qcom_ice_resume(struct platform_device *pdev)

	return 0;
}
EXPORT_SYMBOL(qcom_ice_resume);

static void qcom_ice_dump_test_bus(struct ice_device *ice_dev)
{
@@ -1409,8 +1306,6 @@ static void qcom_ice_debug(struct platform_device *pdev)
out:
	return;
}
EXPORT_SYMBOL(qcom_ice_debug);


static int qcom_ice_reset(struct  platform_device *pdev)
{
@@ -1426,7 +1321,6 @@ static int qcom_ice_reset(struct platform_device *pdev)

	return qcom_ice_finish_power_collapse(ice_dev);
}
EXPORT_SYMBOL(qcom_ice_reset);

static int qcom_ice_config(struct platform_device *pdev, struct request *req,
		struct ice_data_setting *setting)
@@ -1509,7 +1403,6 @@ static int qcom_ice_config(struct platform_device *pdev, struct request *req,
	 */
	return 0;
}
EXPORT_SYMBOL(qcom_ice_config);

static int qcom_ice_status(struct platform_device *pdev)
{
@@ -1535,9 +1428,8 @@ static int qcom_ice_status(struct platform_device *pdev)
	return !!(test_bus_reg_status & QCOM_ICE_TEST_BUS_REG_NON_SECURE_INTR);

}
EXPORT_SYMBOL(qcom_ice_status);

const struct qcom_ice_variant_ops qcom_ice_ops = {
struct qcom_ice_variant_ops qcom_ice_ops = {
	.name             = "qcom",
	.init             = qcom_ice_init,
	.reset            = qcom_ice_reset,
@@ -1548,14 +1440,6 @@ const struct qcom_ice_variant_ops qcom_ice_ops = {
	.debug            = qcom_ice_debug,
};

/* Following struct is required to match device with driver from dts file */
static struct of_device_id qcom_ice_match[] = {
	{	.compatible = "qcom,ice",
		.data = (void *)&qcom_ice_ops},
	{},
};
MODULE_DEVICE_TABLE(of, qcom_ice_match);

struct platform_device *qcom_ice_get_pdevice(struct device_node *node)
{
	struct platform_device *ice_pdev = NULL;
@@ -1571,7 +1455,6 @@ struct platform_device *qcom_ice_get_pdevice(struct device_node *node)
		goto out;
	}


	if (list_empty(&ice_devices)) {
		pr_err("%s: invalid device list\n", __func__);
		ice_pdev = ERR_PTR(-EPROBE_DEFER);
@@ -1612,7 +1495,6 @@ out:
	return ice_dev;
}


static int enable_ice_setup(struct ice_device *ice_dev)
{
	int ret = -1, vote;
@@ -1715,19 +1597,17 @@ int qcom_ice_setup_ice_hw(const char *storage_type, int enable)

struct qcom_ice_variant_ops *qcom_ice_get_variant_ops(struct device_node *node)
{
	if (node) {
		const struct of_device_id *match;
		match = of_match_node(qcom_ice_match, node);
		if (match)
			return (struct qcom_ice_variant_ops *)(match->data);
		pr_err("%s: error matching\n", __func__);
	} else {
		pr_err("%s: invalid node\n", __func__);
	}
	return NULL;
	return &qcom_ice_ops;
}
EXPORT_SYMBOL(qcom_ice_get_variant_ops);

/* Following struct is required to match device with driver from dts file */
static struct of_device_id qcom_ice_match[] = {
	{ .compatible = "qcom,ice" },
	{},
};
MODULE_DEVICE_TABLE(of, qcom_ice_match);

static struct platform_driver qcom_ice_driver = {
	.probe          = qcom_ice_probe,
	.remove         = qcom_ice_remove,
+3 −3
Original line number Diff line number Diff line
@@ -13,12 +13,12 @@

#include "sdhci-msm-ice.h"

static void sdhci_msm_ice_error_cb(void *host_ctrl, enum ice_error_code evt)
static void sdhci_msm_ice_error_cb(void *host_ctrl, u32 error)
{
	struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)host_ctrl;

	dev_err(&msm_host->pdev->dev, "%s: Error in ice operation %d",
		__func__, evt);
	dev_err(&msm_host->pdev->dev, "%s: Error in ice operation 0x%x",
		__func__, error);

	if (msm_host->ice.state == SDHCI_MSM_ICE_STATE_ACTIVE)
		msm_host->ice.state = SDHCI_MSM_ICE_STATE_DISABLED;
+32 −3
Original line number Diff line number Diff line
@@ -56,12 +56,12 @@ void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host)

}

static void ufs_qcom_ice_error_cb(void *host_ctrl, enum ice_error_code evt)
static void ufs_qcom_ice_error_cb(void *host_ctrl, u32 error)
{
	struct ufs_qcom_host *qcom_host = (struct ufs_qcom_host *)host_ctrl;

	dev_err(qcom_host->hba->dev, "%s: Error in ice operation %d",
		__func__, evt);
	dev_err(qcom_host->hba->dev, "%s: Error in ice operation 0x%x",
		__func__, error);

	if (qcom_host->ice.state == UFS_QCOM_ICE_STATE_ACTIVE)
		qcom_host->ice.state = UFS_QCOM_ICE_STATE_DISABLED;
@@ -210,6 +210,35 @@ static inline bool ufs_qcom_is_data_cmd(char cmd_op, bool is_write)
	return false;
}

int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
		struct scsi_cmnd *cmd, u8 *cc_index, bool *enable)
{
	struct ice_data_setting ice_set;
	char cmd_op = cmd->cmnd[0];
	int err;

	if (qcom_host->ice.vops->config) {
		memset(&ice_set, 0, sizeof(ice_set));
		err = qcom_host->ice.vops->config(qcom_host->ice.pdev,
			cmd->request, &ice_set);
		if (err) {
			dev_err(qcom_host->hba->dev,
				"%s: error in ice_vops->config %d\n",
				__func__, err);
			return err;
		}

		if (ufs_qcom_is_data_cmd(cmd_op, true))
			*enable = !ice_set.encr_bypass;
		else if (ufs_qcom_is_data_cmd(cmd_op, false))
			*enable = !ice_set.decr_bypass;

		if (ice_set.crypto_data.key_index >= 0)
			*cc_index = (u8)ice_set.crypto_data.key_index;
	}
	return 0;
}

/**
 * ufs_qcom_ice_cfg() - configures UFS's ICE registers for an ICE transaction
 * @qcom_host:	Pointer to a UFS QCom internal host structure.
+2 −0
Original line number Diff line number Diff line
@@ -72,6 +72,8 @@ enum {
#ifdef CONFIG_SCSI_UFS_QCOM_ICE
int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host);
int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host);
int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
			   struct scsi_cmnd *cmd, u8 *cc_index, bool *enable);
int ufs_qcom_ice_cfg(struct ufs_qcom_host *qcom_host, struct scsi_cmnd *cmd);
int ufs_qcom_ice_reset(struct ufs_qcom_host *qcom_host);
int ufs_qcom_ice_resume(struct ufs_qcom_host *qcom_host);
+25 −1
Original line number Diff line number Diff line
@@ -374,7 +374,6 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
		/* check if UFS PHY moved from DISABLED to HIBERN8 */
		err = ufs_qcom_check_hibern8(hba);
		ufs_qcom_enable_hw_clk_gating(hba);

		break;
	default:
		dev_err(hba->dev, "%s: invalid status %d\n", __func__, status);
@@ -677,6 +676,30 @@ out:
	return ret;
}

static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba,
	struct ufshcd_lrb *lrbp, u8 *cc_index, bool *enable, u64 *dun)
{
	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
	struct request *req;
	int ret;

	if (lrbp->cmd && lrbp->cmd->request)
		req = lrbp->cmd->request;
	else
		return 0;

	/* Use request LBA as the DUN value */
	if (req->bio)
		*dun = req->bio->bi_iter.bi_sector;

	ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable);
	if (ret)
		dev_err(hba->dev, "%s: ufs_qcom_ice_req_setup failed (%d)\n",
			__func__, ret);

	return ret;
}

static
int ufs_qcom_crytpo_engine_cfg(struct ufs_hba *hba, unsigned int task_tag)
{
@@ -2245,6 +2268,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
};

static struct ufs_hba_crypto_variant_ops ufs_hba_crypto_variant_ops = {
	.crypto_req_setup	= ufs_qcom_crypto_req_setup,
	.crypto_engine_cfg	  = ufs_qcom_crytpo_engine_cfg,
	.crypto_engine_reset	  = ufs_qcom_crytpo_engine_reset,
	.crypto_engine_get_status = ufs_qcom_crypto_engine_get_status,
Loading