Merge "msm: ice: Add support for ICE-FDE full disk encryption"

This commit is contained in:
qctecmdr 2021-03-10 23:22:09 -08:00 • committed by Gerrit - the friendly Code Review server
commit 9c40b052d9
9 changed files with 799 additions and 58 deletions

View file

@ -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

View file

@ -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: {

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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");

View file

@ -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_ */

View file

@ -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 */

View file

@ -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 */