From 5e5e43c13652699f86493f6a78bdf6bbf091ae92 Mon Sep 17 00:00:00 2001 From: Victor Zaharchuk Date: Mon, 22 Feb 2021 13:32:55 +0200 Subject: [PATCH] msm: ice: Add support for ICE-FDE full disk encryption Porting the FDE functionality from msm-4.14 branch commit (Add support for block disk encryption). Modified to be compatible with the 5.4 Kernel. Test: 1. Basic_SimpleEncryption. 2. ModifyEnforcedFiles_FileCreationWithinEnforcedFolder. 3. PIN, pattern, password. 4. Verified filename encryption. 5. Generate/set ICE keys. 6. Enable ICE state for userdata partition. 7. Format the userdata partition. 8. Check if partition is encrypted via ICE. Change-Id: I307d75b7cdf25f7a9ad2b4f948e64d13278e6f03 Signed-off-by: Neeraj Soni Signed-off-by: Victor Zaharchuk --- arch/arm64/configs/vendor/gen3auto_GKI.config | 1 + drivers/misc/qseecom.c | 16 +- drivers/scsi/ufs/ufshcd-crypto-qti.c | 66 +- drivers/scsi/ufs/ufshcd-crypto-qti.h | 8 +- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/crypto-qti-common.c | 642 +++++++++++++++++- drivers/soc/qcom/crypto-qti-ice-regs.h | 9 +- include/linux/crypto-qti-common.h | 64 +- include/linux/pfk.h | 42 +- 9 files changed, 799 insertions(+), 58 deletions(-) diff --git a/arch/arm64/configs/vendor/gen3auto_GKI.config b/arch/arm64/configs/vendor/gen3auto_GKI.config index ddd8f3ed792a..dabdfc8a0778 100644 --- a/arch/arm64/configs/vendor/gen3auto_GKI.config +++ b/arch/arm64/configs/vendor/gen3auto_GKI.config @@ -44,6 +44,7 @@ CONFIG_SCSI_UFS_QCOM=m CONFIG_SCSI_UFS_BSG=y CONFIG_SCSI_UFS_CRYPTO_QTI=m CONFIG_QTI_CRYPTO_COMMON=m +CONFIG_QTI_CRYPTO_FDE=m CONFIG_PCI_MSM=m CONFIG_MHI_BUS=m CONFIG_MHI_UCI=m diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 5fbb2bc6550b..f90cbf9309c5 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -36,7 +36,7 @@ #include #include #include "qseecom_kernel.h" -#include +#include #include #include #include @@ -90,7 +90,9 @@ #define TWO 2 #define QSEECOM_UFS_ICE_CE_NUM 10 #define QSEECOM_SDCC_ICE_CE_NUM 20 -#define QSEECOM_ICE_FDE_KEY_INDEX 0 + +/* Assume the ice device contains 32 slots (0-31) and reserve the last one for the FDE */ +#define QSEECOM_ICE_FDE_KEY_INDEX 31 #define PHY_ADDR_4G (1ULL<<32) @@ -6412,9 +6414,9 @@ static int qseecom_enable_ice_setup(int usage) int ret = 0; if (usage == QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION) - ret = qcom_ice_setup_ice_hw("ufs", true); + ret = crypto_qti_ice_setup_ice_hw("ufs", true); else if (usage == QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION) - ret = qcom_ice_setup_ice_hw("sdcc", true); + ret = crypto_qti_ice_setup_ice_hw("sdcc", true); return ret; } @@ -6424,9 +6426,9 @@ static int qseecom_disable_ice_setup(int usage) int ret = 0; if (usage == QSEOS_KM_USAGE_UFS_ICE_DISK_ENCRYPTION) - ret = qcom_ice_setup_ice_hw("ufs", false); + ret = crypto_qti_ice_setup_ice_hw("ufs", false); else if (usage == QSEOS_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION) - ret = qcom_ice_setup_ice_hw("sdcc", false); + ret = crypto_qti_ice_setup_ice_hw("sdcc", false); return ret; } @@ -8289,7 +8291,7 @@ long qseecom_ioctl(struct file *file, pr_err("copy_from_user failed\n"); return -EFAULT; } - qcom_ice_set_fde_flag(ice_data.flag); + crypto_qti_ice_set_fde_flag(ice_data.flag); break; } case QSEECOM_IOCTL_FBE_CLEAR_KEY: { diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.c b/drivers/scsi/ufs/ufshcd-crypto-qti.c index fcaa01b612c9..f14860d1ef1e 100644 --- a/drivers/scsi/ufs/ufshcd-crypto-qti.c +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.c @@ -2,7 +2,7 @@ /* * UFS Crypto ops QTI implementation. * - * Copyright (c) 2020, Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, Linux Foundation. All rights reserved. */ #include @@ -22,6 +22,9 @@ static struct ufs_hba_crypto_variant_ops ufshcd_crypto_qti_variant_ops = { .disable = ufshcd_crypto_qti_disable, .resume = ufshcd_crypto_qti_resume, .debug = ufshcd_crypto_qti_debug, +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) + .prepare_lrbp_crypto = ufshcd_crypto_qti_prep_lrbp_crypto, +#endif }; static uint8_t get_data_unit_size_mask(unsigned int data_unit_size) @@ -34,6 +37,59 @@ static uint8_t get_data_unit_size_mask(unsigned int data_unit_size) return data_unit_size / MINIMUM_DUN_SIZE; } +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) +int ufshcd_crypto_qti_prep_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp) +{ + struct bio_crypt_ctx *bc; + int ret = 0; + struct ice_data_setting setting; + bool bypass = true; + short key_index = 0; + struct request *req; + + lrbp->crypto_enable = false; + req = cmd->request; + if (!req || !req->bio) + return ret; + + if (!bio_crypt_should_process(req)) { + ret = crypto_qti_ice_config_start(req, &setting); + if (!ret) { + key_index = setting.crypto_data.key_index; + bypass = (rq_data_dir(req) == WRITE) ? + setting.encr_bypass : setting.decr_bypass; + lrbp->crypto_enable = !bypass; + lrbp->crypto_key_slot = key_index; + lrbp->data_unit_num = req->bio->bi_iter.bi_sector >> + ICE_CRYPTO_DATA_UNIT_4_KB; + } else { + pr_err("%s crypto config failed err = %d\n", __func__, + ret); + } + return ret; + } + bc = req->bio->bi_crypt_context; + + if (WARN_ON(!ufshcd_is_crypto_enabled(hba))) { + /* + * Upper layer asked us to do inline encryption + * but that isn't enabled, so we fail this request. + */ + return -EINVAL; + } + if (!ufshcd_keyslot_valid(hba, bc->bc_keyslot)) + return -EINVAL; + + lrbp->crypto_enable = true; + lrbp->crypto_key_slot = bc->bc_keyslot; + lrbp->data_unit_num = bc->bc_dun[0]; + + return 0; +} +#endif //IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) + static bool ice_cap_idx_valid(struct ufs_hba *hba, unsigned int cap_idx) { @@ -194,6 +250,7 @@ static int ufshcd_hba_init_crypto_qti_spec(struct ufs_hba *hba, int err = 0; unsigned int crypto_modes_supported[BLK_ENCRYPTION_MODE_MAX]; enum blk_crypto_mode_num blk_mode_num; + unsigned int num_slots = 0; /* Default to disabling crypto */ hba->caps &= ~UFSHCD_CAP_CRYPTO; @@ -242,7 +299,12 @@ static int ufshcd_hba_init_crypto_qti_spec(struct ufs_hba *hba, hba->crypto_cap_array[cap_idx].sdus_mask * 512; } - hba->ksm = keyslot_manager_create(hba->dev, ufshcd_num_keyslots(hba), + num_slots = ufshcd_num_keyslots(hba); +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) + if (num_slots > 0) + --num_slots; +#endif + hba->ksm = keyslot_manager_create(hba->dev, num_slots, ksm_ops, BLK_CRYPTO_FEATURE_WRAPPED_KEYS, crypto_modes_supported, hba); diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.h b/drivers/scsi/ufs/ufshcd-crypto-qti.h index aa4090f226af..96f00853a2e6 100644 --- a/drivers/scsi/ufs/ufshcd-crypto-qti.h +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef _UFSHCD_CRYPTO_QTI_H @@ -34,6 +34,12 @@ int ufshcd_crypto_qti_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op); int ufshcd_crypto_qti_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op); +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) +int ufshcd_crypto_qti_prep_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, + struct ufshcd_lrb *lrbp); +#endif + #if IS_ENABLED(CONFIG_SCSI_UFS_CRYPTO_QTI) void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba); #else diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index a7a487560410..fc2f5fde81f5 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -1178,6 +1178,15 @@ config QTI_CRYPTO_TZ programmed and managed through SCM calls to TZ where ICE driver will configure keys. +config QTI_CRYPTO_FDE + tristate "Enable common crypto functionality used for FDE" + depends on QTI_CRYPTO_COMMON + help + Say 'Y' to enable hardware Full Disk Encryption implementation to be used by + different storage layers such as UFS. Enabling the FDE will reserve one slot + of KSM(Key Slot Manager) for the FDE. Making one less slot available for FBE + (File based encryption) in case both encryption mechanism are enabled on device. + config QTI_HW_KEY_MANAGER tristate "Enable QTI Hardware Key Manager for storage encryption" default n diff --git a/drivers/soc/qcom/crypto-qti-common.c b/drivers/soc/qcom/crypto-qti-common.c index b958c9be8f7e..c86ca588d1d2 100644 --- a/drivers/soc/qcom/crypto-qti-common.c +++ b/drivers/soc/qcom/crypto-qti-common.c @@ -2,7 +2,7 @@ /* * Common crypto library for storage encryption. * - * Copyright (c) 2020, Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, Linux Foundation. All rights reserved. */ #include @@ -10,6 +10,21 @@ #include "crypto-qti-ice-regs.h" #include "crypto-qti-platform.h" +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) +#include +#include +#include +#include + +#define CRYPTO_ICE_TYPE_NAME_LEN 8 +#define CRYPTO_ICE_ENCRYPT 0x1 +#define CRYPTO_ICE_DECRYPT 0x2 +#define CRYPTO_SECT_LEN_IN_BYTE 512 +#define CRYPTO_ICE_CXT_FDE 1 +#define CRYPTO_ICE_FDE_KEY_INDEX 31 +#define CRYPTO_UD_VOLNAME "userdata" +#endif //CONFIG_QTI_CRYPTO_FDE + static int ice_check_fuse_setting(struct crypto_vops_qti_entry *ice_entry) { uint32_t regval; @@ -476,5 +491,630 @@ int crypto_qti_derive_raw_secret(void *priv_data, } EXPORT_SYMBOL(crypto_qti_derive_raw_secret); +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) +static int ice_fde_flag; +struct ice_clk_info { + struct list_head list; + struct clk *clk; + const char *name; + u32 max_freq; + u32 min_freq; + u32 curr_freq; + bool enabled; +}; + +static LIST_HEAD(ice_devices); +/* + * ICE HW device structure. + */ +struct ice_device { + struct list_head list; + struct device *pdev; + dev_t device_no; + void __iomem *mmio; + int irq; + bool is_ice_enabled; + ice_error_cb error_cb; + void *host_controller_data; /* UFS/EMMC/other? */ + struct list_head clk_list_head; + u32 ice_hw_version; + bool is_ice_clk_available; + char ice_instance_type[CRYPTO_ICE_TYPE_NAME_LEN]; + struct regulator *reg; + bool is_regulator_available; +}; + +static int crypto_qti_ice_init(struct ice_device *ice_dev, void *host_controller_data, + ice_error_cb error_cb); + +static int crypto_qti_ice_get_vreg(struct ice_device *ice_dev) +{ + int ret = 0; + + if (!ice_dev->is_regulator_available) + return 0; + + if (ice_dev->reg) + return 0; + + ice_dev->reg = devm_regulator_get(ice_dev->pdev, "vdd-hba"); + if (IS_ERR(ice_dev->reg)) { + ret = PTR_ERR(ice_dev->reg); + dev_err(ice_dev->pdev, "%s: %s get failed, err=%d\n", + __func__, "vdd-hba-supply", ret); + } + return ret; +} + +static int crypto_qti_ice_setting_config(struct request *req, + struct ice_crypto_setting *crypto_data, + struct ice_data_setting *setting, uint32_t cxt) +{ + if (!setting) + return -EINVAL; + + if ((short)(crypto_data->key_index) >= 0) { + memcpy(&setting->crypto_data, crypto_data, + sizeof(setting->crypto_data)); + + if (rq_data_dir(req) == WRITE) { + if (((cxt == CRYPTO_ICE_CXT_FDE) && + (ice_fde_flag & CRYPTO_ICE_ENCRYPT))) + setting->encr_bypass = false; + } else if (rq_data_dir(req) == READ) { + if (((cxt == CRYPTO_ICE_CXT_FDE) && + (ice_fde_flag & CRYPTO_ICE_DECRYPT))) + setting->decr_bypass = false; + } else { + /* Should I say BUG_ON */ + setting->encr_bypass = true; + setting->decr_bypass = true; + } + } + + return 0; +} + +static void crypto_qti_ice_disable_intr(struct ice_device *ice_dev) +{ + unsigned int reg; + + reg = crypto_qti_ice_readl(ice_dev, ICE_REGS_NON_SEC_IRQ_MASK); + reg |= ICE_NON_SEC_IRQ_MASK; + crypto_qti_ice_writel(ice_dev, reg, ICE_REGS_NON_SEC_IRQ_MASK); + /* + * Ensure previous instructions was completed before issuing next + * ICE initialization/optimization instruction + */ + mb(); +} + +static void crypto_qti_ice_parse_ice_instance_type(struct platform_device *pdev, + struct ice_device *ice_dev) +{ + int ret = -1; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const char *type; + + ret = of_property_read_string_index(np, "qcom,instance-type", 0, &type); + if (ret) { + pr_err("%s: Could not get ICE instance type\n", __func__); + goto out; + } + strlcpy(ice_dev->ice_instance_type, type, CRYPTO_ICE_TYPE_NAME_LEN); +out: + return; +} + +static int crypto_qti_ice_parse_clock_info(struct platform_device *pdev, struct ice_device *ice_dev) +{ + int ret = -1, cnt, i, len; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + char *name; + struct ice_clk_info *clki; + u32 *clkfreq = NULL; + + if (!np) + goto out; + + cnt = of_property_count_strings(np, "clock-names"); + if (cnt <= 0) { + dev_info(dev, "%s: Unable to find clocks, assuming enabled\n", + __func__); + ret = cnt; + goto out; + } + + if (!of_get_property(np, "qcom,op-freq-hz", &len)) { + dev_info(dev, "qcom,op-freq-hz property not specified\n"); + goto out; + } + + len = len/sizeof(*clkfreq); + if (len != cnt) + goto out; + + clkfreq = devm_kzalloc(dev, len * sizeof(*clkfreq), GFP_KERNEL); + if (!clkfreq) { + ret = -ENOMEM; + goto out; + } + ret = of_property_read_u32_array(np, "qcom,op-freq-hz", clkfreq, len); + + INIT_LIST_HEAD(&ice_dev->clk_list_head); + + for (i = 0; i < cnt; i++) { + ret = of_property_read_string_index(np, + "clock-names", i, (const char **)&name); + if (ret) + goto out; + + clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); + if (!clki) { + ret = -ENOMEM; + goto out; + } + clki->max_freq = clkfreq[i]; + clki->name = kstrdup(name, GFP_KERNEL); + list_add_tail(&clki->list, &ice_dev->clk_list_head); + } +out: + return ret; +} + +static int crypto_qti_ice_get_dts_data(struct platform_device *pdev, struct ice_device *ice_dev) +{ + int rc = -1; + + ice_dev->mmio = NULL; + if (!of_parse_phandle(pdev->dev.of_node, "vdd-hba-supply", 0)) { + pr_err("%s: No vdd-hba-supply regulator, assuming not needed\n", + __func__); + ice_dev->is_regulator_available = false; + } else { + ice_dev->is_regulator_available = true; + } + ice_dev->is_ice_clk_available = of_property_read_bool( + (&pdev->dev)->of_node, + "qcom,enable-ice-clk"); + + if (ice_dev->is_ice_clk_available) { + rc = crypto_qti_ice_parse_clock_info(pdev, ice_dev); + if (rc) { + pr_err("%s: crypto_qti_ice_parse_clock_info failed (%d)\n", + __func__, rc); + goto err_dev; + } + } + + crypto_qti_ice_parse_ice_instance_type(pdev, ice_dev); + + return 0; +err_dev: + return rc; +} + +/* + * ICE HW instance can exist in UFS or eMMC based storage HW + * Userspace does not know what kind of ICE it is dealing with. + * Though userspace can find which storage device it is booting + * from but all kind of storage types dont support ICE from + * beginning. So ICE device is created for user space to ping + * if ICE exist for that kind of storage + */ +static const struct file_operations crypto_qti_ice_fops = { + .owner = THIS_MODULE, +}; + + + +static int crypto_qti_ice_probe(struct platform_device *pdev) +{ + struct ice_device *ice_dev; + int rc = 0; + + if (!pdev) { + pr_err("%s: Invalid platform_device passed\n", + __func__); + return -EINVAL; + } + + ice_dev = kzalloc(sizeof(struct ice_device), GFP_KERNEL); + + if (!ice_dev) { + rc = -ENOMEM; + pr_err("%s: Error %d allocating memory for ICE device:\n", + __func__, rc); + goto out; + } + + ice_dev->pdev = &pdev->dev; + if (!ice_dev->pdev) { + rc = -EINVAL; + pr_err("%s: Invalid device passed in platform_device\n", + __func__); + goto err_ice_dev; + } + + if (pdev->dev.of_node) + rc = crypto_qti_ice_get_dts_data(pdev, ice_dev); + else { + rc = -EINVAL; + pr_err("%s: ICE device node not found\n", __func__); + } + + if (rc) + goto err_ice_dev; + + /* + * If ICE is enabled here, it would be waste of power. + * We would enable ICE when first request for crypto + * operation arrives. + */ + rc = crypto_qti_ice_init(ice_dev, NULL, NULL); + if (rc) { + pr_err("ice_init failed.\n"); + goto err_ice_dev; + } + ice_dev->is_ice_enabled = true; + platform_set_drvdata(pdev, ice_dev); + list_add_tail(&ice_dev->list, &ice_devices); + + goto out; + +err_ice_dev: + kfree(ice_dev); +out: + return rc; +} + +static int crypto_qti_ice_remove(struct platform_device *pdev) +{ + struct ice_device *ice_dev; + + ice_dev = (struct ice_device *)platform_get_drvdata(pdev); + + if (!ice_dev) + return 0; + + crypto_qti_ice_disable_intr(ice_dev); + + device_init_wakeup(&pdev->dev, false); + if (ice_dev->mmio) + iounmap(ice_dev->mmio); + + list_del_init(&ice_dev->list); + kfree(ice_dev); + + return 1; +} + + +int crypto_qti_ice_config_start(struct request *req, struct ice_data_setting *setting) +{ + struct ice_crypto_setting ice_data = {0}; + unsigned long sec_end = 0; + sector_t data_size; + + ice_data.key_index = CRYPTO_ICE_FDE_KEY_INDEX; + + if (!req) { + pr_err("%s: Invalid params passed\n", __func__); + return -EINVAL; + } + + /* + * It is not an error to have a request with no bio + * Such requests must bypass ICE. So first set bypass and then + * return if bio is not available in request + */ + if (setting) { + setting->encr_bypass = true; + setting->decr_bypass = true; + } + + if (!req->bio) { + /* It is not an error to have a request with no bio */ + return 0; + } + + if (ice_fde_flag && req->part && req->part->info + && req->part->info->volname[0]) { + if (!strcmp(req->part->info->volname, CRYPTO_UD_VOLNAME)) { + sec_end = req->part->start_sect + req->part->nr_sects; + if ((req->__sector >= req->part->start_sect) && + (req->__sector < sec_end)) { + /* + * Ugly hack to address non-block-size aligned + * userdata end address in eMMC based devices. + * for eMMC based devices, since sector and + * block sizes are not same i.e. 4K, it is + * possible that partition is not a multiple of + * block size. For UFS based devices sector + * size and block size are same. Hence ensure + * that data is within userdata partition using + * sector based calculation + */ + data_size = req->__data_len / + CRYPTO_SECT_LEN_IN_BYTE; + + if ((req->__sector + data_size) > sec_end) + return 0; + else + return crypto_qti_ice_setting_config(req, + &ice_data, setting, + CRYPTO_ICE_CXT_FDE); + } + } + } + + /* + * It is not an error. If target is not req-crypt based, all request + * from storage driver would come here to check if there is any ICE + * setting required + */ + return 0; +} +EXPORT_SYMBOL(crypto_qti_ice_config_start); + +void crypto_qti_ice_set_fde_flag(int flag) +{ + ice_fde_flag = flag; + pr_debug("%s flag = %d\n", __func__, ice_fde_flag); +} +EXPORT_SYMBOL(crypto_qti_ice_set_fde_flag); + +/* Following struct is required to match device with driver from dts file */ + +static const struct of_device_id crypto_qti_ice_match[] = { + { .compatible = "qcom,ice" }, + {}, +}; +MODULE_DEVICE_TABLE(of, crypto_qti_ice_match); + +static int crypto_qti_ice_enable_clocks(struct ice_device *ice, bool enable) +{ + int ret = 0; + struct ice_clk_info *clki = NULL; + struct device *dev = ice->pdev; + struct list_head *head = &ice->clk_list_head; + + if (!head || list_empty(head)) { + dev_err(dev, "%s:ICE Clock list null/empty\n", __func__); + ret = -EINVAL; + goto out; + } + + if (!ice->is_ice_clk_available) { + dev_err(dev, "%s:ICE Clock not available\n", __func__); + ret = -EINVAL; + goto out; + } + + list_for_each_entry(clki, head, list) { + if (!clki->name) + continue; + + if (enable) + ret = clk_prepare_enable(clki->clk); + else + clk_disable_unprepare(clki->clk); + + if (ret) { + dev_err(dev, "Unable to %s ICE core clk\n", + enable?"enable":"disable"); + goto out; + } + } +out: + return ret; +} + +static struct ice_device *crypto_qti_get_ice_device_from_storage_type + (const char *storage_type) +{ + struct ice_device *ice_dev = NULL; + + if (list_empty(&ice_devices)) { + pr_err("%s: invalid device list\n", __func__); + ice_dev = ERR_PTR(-EPROBE_DEFER); + goto out; + } + + list_for_each_entry(ice_dev, &ice_devices, list) { + if (!strcmp(ice_dev->ice_instance_type, storage_type)) { + pr_debug("%s: ice device %pK\n", __func__, ice_dev); + return ice_dev; + } + } +out: + return NULL; +} + + +static int crypto_qti_ice_enable_setup(struct ice_device *ice_dev) +{ + int ret = -1; + + /* Setup Regulator */ + if (ice_dev->is_regulator_available) { + if (crypto_qti_ice_get_vreg(ice_dev)) { + pr_err("%s: Could not get regulator\n", __func__); + goto out; + } + ret = regulator_enable(ice_dev->reg); + if (ret) { + pr_err("%s:%pK: Could not enable regulator\n", + __func__, ice_dev); + goto out; + } + } + + /* Setup Clocks */ + if (crypto_qti_ice_enable_clocks(ice_dev, true)) { + pr_err("%s:%pK:%s Could not enable clocks\n", __func__, + ice_dev, ice_dev->ice_instance_type); + goto out_reg; + } + + return ret; + +out_reg: + if (ice_dev->is_regulator_available) { + if (crypto_qti_ice_get_vreg(ice_dev)) { + pr_err("%s: Could not get regulator\n", __func__); + goto out; + } + ret = regulator_disable(ice_dev->reg); + if (ret) { + pr_err("%s:%pK: Could not disable regulator\n", + __func__, ice_dev); + goto out; + } + } +out: + return ret; +} + +static int crypto_qti_ice_disable_setup(struct ice_device *ice_dev) +{ + int ret = 0; + + /* Setup Clocks */ + if (crypto_qti_ice_enable_clocks(ice_dev, false)) + pr_err("%s:%pK:%s Could not disable clocks\n", __func__, + ice_dev, ice_dev->ice_instance_type); + + /* Setup Regulator */ + if (ice_dev->is_regulator_available) { + if (crypto_qti_ice_get_vreg(ice_dev)) { + pr_err("%s: Could not get regulator\n", __func__); + goto out; + } + ret = regulator_disable(ice_dev->reg); + if (ret) { + pr_err("%s:%pK: Could not disable regulator\n", + __func__, ice_dev); + goto out; + } + } +out: + return ret; +} + + +static int crypto_qti_ice_init_clocks(struct ice_device *ice) +{ + int ret = -EINVAL; + struct ice_clk_info *clki = NULL; + struct device *dev = ice->pdev; + struct list_head *head = &ice->clk_list_head; + + if (!head || list_empty(head)) { + dev_err(dev, "%s:ICE Clock list null/empty\n", __func__); + goto out; + } + + list_for_each_entry(clki, head, list) { + if (!clki->name) + continue; + + clki->clk = devm_clk_get(dev, clki->name); + if (IS_ERR(clki->clk)) { + ret = PTR_ERR(clki->clk); + dev_err(dev, "%s: %s clk get failed, %d\n", + __func__, clki->name, ret); + goto out; + } + + /* Not all clocks would have a rate to be set */ + ret = 0; + if (clki->max_freq) { + ret = clk_set_rate(clki->clk, clki->max_freq); + if (ret) { + dev_err(dev, + "%s: %s clk set rate(%dHz) failed, %d\n", + __func__, clki->name, + clki->max_freq, ret); + goto out; + } + clki->curr_freq = clki->max_freq; + dev_dbg(dev, "%s: clk: %s, rate: %lu\n", __func__, + clki->name, clk_get_rate(clki->clk)); + } + } +out: + return ret; +} + +static int crypto_qti_ice_finish_init(struct ice_device *ice_dev) +{ + int err = 0; + + if (!ice_dev) { + pr_err("%s: Null data received\n", __func__); + err = -ENODEV; + goto out; + } + + if (ice_dev->is_ice_clk_available) { + err = crypto_qti_ice_init_clocks(ice_dev); + if (err) + goto out; + } +out: + return err; +} + +static int crypto_qti_ice_init(struct ice_device *ice_dev, + void *host_controller_data, + ice_error_cb error_cb) +{ + /* + * A completion event for host controller would be triggered upon + * initialization completion + * When ICE is initialized, it would put ICE into Global Bypass mode + * When any request for data transfer is received, it would enable + * the ICE for that particular request + */ + + ice_dev->error_cb = error_cb; + ice_dev->host_controller_data = host_controller_data; + + return crypto_qti_ice_finish_init(ice_dev); +} + + +int crypto_qti_ice_setup_ice_hw(const char *storage_type, int enable) +{ + int ret = -1; + struct ice_device *ice_dev = NULL; + + ice_dev = crypto_qti_get_ice_device_from_storage_type(storage_type); + if (ice_dev == ERR_PTR(-EPROBE_DEFER)) + return -EPROBE_DEFER; + + if (!ice_dev || !ice_dev->is_ice_enabled) + return ret; + if (enable) + return crypto_qti_ice_enable_setup(ice_dev); + else + return crypto_qti_ice_disable_setup(ice_dev); +} +EXPORT_SYMBOL(crypto_qti_ice_setup_ice_hw); + +static struct platform_driver crypto_qti_ice_driver = { + .probe = crypto_qti_ice_probe, + .remove = crypto_qti_ice_remove, + .driver = { + .name = "qcom_ice", + .of_match_table = crypto_qti_ice_match, + }, +}; +module_platform_driver(crypto_qti_ice_driver); +#endif //CONFIG_QTI_CRYPTO_FDE + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Common crypto library for storage encryption"); diff --git a/drivers/soc/qcom/crypto-qti-ice-regs.h b/drivers/soc/qcom/crypto-qti-ice-regs.h index 38e5c3543c01..56aefa90c1a6 100644 --- a/drivers/soc/qcom/crypto-qti-ice-regs.h +++ b/drivers/soc/qcom/crypto-qti-ice-regs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ @@ -153,4 +153,11 @@ #define ice_readl(ice_entry, reg) \ readl_relaxed((ice_entry)->icemmio_base + (reg)) +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) +#define crypto_qti_ice_writel(ice, val, reg) \ + writel_relaxed((val), (ice)->mmio + (reg)) +#define crypto_qti_ice_readl(ice, reg) \ + readl_relaxed((ice)->mmio + (reg)) +#endif //CONFIG_QTI_CRYPTO_FDE + #endif /* _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ */ diff --git a/include/linux/crypto-qti-common.h b/include/linux/crypto-qti-common.h index 62cc3b196083..c42e20a692b7 100644 --- a/include/linux/crypto-qti-common.h +++ b/include/linux/crypto-qti-common.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef _CRYPTO_QTI_COMMON_H @@ -11,6 +11,7 @@ #include #include #include +#include #define RAW_SECRET_SIZE 32 #define QTI_ICE_MAX_BIST_CHECK_COUNT 100 @@ -41,6 +42,57 @@ int crypto_qti_derive_raw_secret(void *priv_data, unsigned int wrapped_key_size, u8 *secret, unsigned int secret_size); +//ICE +#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE) +/* MSM ICE Crypto Data Unit of target DUN of Transfer Request */ +enum ice_crypto_data_unit { + ICE_CRYPTO_DATA_UNIT_512_B = 0, + ICE_CRYPTO_DATA_UNIT_1_KB = 1, + ICE_CRYPTO_DATA_UNIT_2_KB = 2, + ICE_CRYPTO_DATA_UNIT_4_KB = 3, + ICE_CRYPTO_DATA_UNIT_8_KB = 4, + ICE_CRYPTO_DATA_UNIT_16_KB = 5, + ICE_CRYPTO_DATA_UNIT_32_KB = 6, + ICE_CRYPTO_DATA_UNIT_64_KB = 7, +}; +struct request; + +enum ice_cryto_algo_mode { + ICE_CRYPTO_ALGO_MODE_AES_ECB = 0x0, + ICE_CRYPTO_ALGO_MODE_AES_XTS = 0x3, +}; + +enum ice_crpto_key_size { + ICE_CRYPTO_KEY_SIZE_128 = 0x0, + ICE_CRYPTO_KEY_SIZE_256 = 0x2, +}; + +struct ice_crypto_setting { + enum ice_crpto_key_size key_size; + enum ice_cryto_algo_mode algo_mode; + short key_index; +}; + +struct ice_data_setting { + struct ice_crypto_setting crypto_data; + bool sw_forced_context_switch; + bool decr_bypass; + bool encr_bypass; +}; +typedef void (*ice_error_cb)(void *, u32 error); +int crypto_qti_ice_setup_ice_hw(const char *storage_type, int enable); +void crypto_qti_ice_set_fde_flag(int flag); +int crypto_qti_ice_config_start(struct request *req, + struct ice_data_setting *setting); +#else //CONFIG_QTI_CRYPTO_FDE +static inline int crypto_qti_ice_setup_ice_hw(const char *storage_type, int enable) +{ + return 0; +} +static inline void crypto_qti_ice_set_fde_flag(int flag) {} +#endif //CONFIG_QTI_CRYPTO_FDE + + #else static inline int crypto_qti_init_crypto(struct device *dev, void __iomem *mmio_base, @@ -53,10 +105,7 @@ static inline int crypto_qti_enable(void *priv_data) { return -EOPNOTSUPP; } -static inline void crypto_qti_disable(void *priv_data) -{ - return -EOPNOTSUPP; -} +static inline void crypto_qti_disable(void *priv_data) {} static inline int crypto_qti_resume(void *priv_data) { return -EOPNOTSUPP; @@ -85,6 +134,11 @@ static inline int crypto_qti_derive_raw_secret(void *priv_data, { return -EOPNOTSUPP; } +static inline int crypto_qti_ice_setup_ice_hw(const char *storage_type, int enable) +{ + return 0; +} +static inline void crypto_qti_ice_set_fde_flag(int flag) {} #endif /* CONFIG_QTI_CRYPTO_COMMON */ diff --git a/include/linux/pfk.h b/include/linux/pfk.h index 903eb102ad70..23eab7b1ce97 100644 --- a/include/linux/pfk.h +++ b/include/linux/pfk.h @@ -1,15 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef PFK_H_ #define PFK_H_ #include -#include -struct ice_crypto_setting; #ifdef CONFIG_PFK @@ -26,54 +24,16 @@ struct blk_encryption_key { u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS]; }; -int pfk_load_key_start(const struct bio *bio, struct ice_device *ice_dev, - struct ice_crypto_setting *ice_setting, - bool *is_pfe, bool async); -int pfk_load_key_end(const struct bio *bio, struct ice_device *ice_dev, - bool *is_pfe); int pfk_fbe_clear_key(const unsigned char *key, size_t key_size, const unsigned char *salt, size_t salt_size); -bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2); -void pfk_clear_on_reset(struct ice_device *ice_dev); -int pfk_initialize_key_table(struct ice_device *ice_dev); -int pfk_remove(struct ice_device *ice_dev); #else -static inline int pfk_load_key_start(const struct bio *bio, - struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async) -{ - return -ENODEV; -} - -static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe) -{ - return -ENODEV; -} - -static inline bool pfk_allow_merge_bio(const struct bio *bio1, - const struct bio *bio2) -{ - return true; -} - static inline int pfk_fbe_clear_key(const unsigned char *key, size_t key_size, const unsigned char *salt, size_t salt_size) { return -ENODEV; } -static inline void pfk_clear_on_reset(void) -{} - -static inline int pfk_initialize_key_table(struct ice_device *ice_dev) -{ - return -ENODEV; -} -static inline int pfk_remove(struct ice_device *ice_dev) -{ - return -ENODEV; -} - #endif /* CONFIG_PFK */ #endif /* PFK_H */