mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 20:33:58 -04:00
Merge "msm: ice: Add support for ICE-FDE full disk encryption"
This commit is contained in:
commit
9c40b052d9
9 changed files with 799 additions and 58 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#include <soc/qcom/qseecomi.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include "qseecom_kernel.h"
|
||||
#include <crypto/ice.h>
|
||||
#include <linux/crypto-qti-common.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/compat.h>
|
||||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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 <crypto/algapi.h>
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1186,6 +1186,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
|
||||
|
|
|
|||
|
|
@ -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 <linux/crypto-qti-common.h>
|
||||
|
|
@ -10,6 +10,21 @@
|
|||
#include "crypto-qti-ice-regs.h"
|
||||
#include "crypto-qti-platform.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_QTI_CRYPTO_FDE)
|
||||
#include <linux/of.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#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");
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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 <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <linux/bio.h>
|
||||
#include <crypto/ice.h>
|
||||
|
||||
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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue