Files
kernel_xiaomi_sm8250/drivers/soc/qcom/crypto-qti-common.c
Vaibhav Agrawal 927d042434 soc: qcom: Return correct error code when program_key fails fails
When we call crypto_qti_program_key to program the key, and
it fails due to trustzone busy issue, we try to call invalidate
key method just after that, and in the process, overwrite the
error code returned by the program key failure. Fix this by handling
the errors from both program key and invalidate key separately,
and return the program key error code to caller.

Test: Verified device boot up and reboot.

Change-Id: Iaff0844f68b4886c23e1840d7e0e4a404d38fc96
Signed-off-by: Vaibhav Agrawal <vagrawa@codeaurora.org>
2021-07-05 09:20:24 -07:00

472 lines
13 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/crypto-qti-common.h>
#include "crypto-qti-ice-regs.h"
#include "crypto-qti-platform.h"
static int ice_check_fuse_setting(struct crypto_vops_qti_entry *ice_entry)
{
uint32_t regval;
uint32_t major, minor;
major = (ice_entry->ice_hw_version & ICE_CORE_MAJOR_REV_MASK) >>
ICE_CORE_MAJOR_REV;
minor = (ice_entry->ice_hw_version & ICE_CORE_MINOR_REV_MASK) >>
ICE_CORE_MINOR_REV;
//Check fuse setting is not supported on ICE 3.2 onwards
if ((major == 0x03) && (minor >= 0x02))
return 0;
regval = ice_readl(ice_entry, ICE_REGS_FUSE_SETTING);
regval &= (ICE_FUSE_SETTING_MASK |
ICE_FORCE_HW_KEY0_SETTING_MASK |
ICE_FORCE_HW_KEY1_SETTING_MASK);
if (regval) {
pr_err("%s: error: ICE_ERROR_HW_DISABLE_FUSE_BLOWN\n",
__func__);
return -EPERM;
}
return 0;
}
static int ice_check_version(struct crypto_vops_qti_entry *ice_entry)
{
uint32_t version, major, minor, step;
version = ice_readl(ice_entry, ICE_REGS_VERSION);
major = (version & ICE_CORE_MAJOR_REV_MASK) >> ICE_CORE_MAJOR_REV;
minor = (version & ICE_CORE_MINOR_REV_MASK) >> ICE_CORE_MINOR_REV;
step = (version & ICE_CORE_STEP_REV_MASK) >> ICE_CORE_STEP_REV;
if (major < ICE_CORE_CURRENT_MAJOR_VERSION) {
pr_err("%s: Unknown ICE device at %lu, rev %d.%d.%d\n",
__func__, (unsigned long)ice_entry->icemmio_base,
major, minor, step);
return -ENODEV;
}
ice_entry->ice_hw_version = version;
return 0;
}
int crypto_qti_init_crypto(struct device *dev, void __iomem *mmio_base,
void **priv_data)
{
int err = 0;
struct crypto_vops_qti_entry *ice_entry;
ice_entry = devm_kzalloc(dev,
sizeof(struct crypto_vops_qti_entry),
GFP_KERNEL);
if (!ice_entry)
return -ENOMEM;
ice_entry->icemmio_base = mmio_base;
ice_entry->flags = 0;
err = ice_check_version(ice_entry);
if (err) {
pr_err("%s: check version failed, err %d\n", __func__, err);
return err;
}
err = ice_check_fuse_setting(ice_entry);
if (err)
return err;
*priv_data = (void *)ice_entry;
return err;
}
static void ice_low_power_and_optimization_enable(
struct crypto_vops_qti_entry *ice_entry)
{
uint32_t regval;
regval = ice_readl(ice_entry, ICE_REGS_ADVANCED_CONTROL);
/* Enable low power mode sequence
* [0]-0,[1]-0,[2]-0,[3]-7,[4]-0,[5]-0,[6]-0,[7]-0,
* Enable CONFIG_CLK_GATING, STREAM2_CLK_GATING and STREAM1_CLK_GATING
*/
regval |= 0x7000;
/* Optimization enable sequence
*/
regval |= 0xD807100;
ice_writel(ice_entry, regval, ICE_REGS_ADVANCED_CONTROL);
/*
* Memory barrier - to ensure write completion before next transaction
*/
wmb();
}
static int ice_wait_bist_status(struct crypto_vops_qti_entry *ice_entry)
{
int count;
uint32_t regval;
for (count = 0; count < QTI_ICE_MAX_BIST_CHECK_COUNT; count++) {
regval = ice_readl(ice_entry, ICE_REGS_BIST_STATUS);
if (!(regval & ICE_BIST_STATUS_MASK))
break;
udelay(50);
}
if (regval) {
pr_err("%s: wait bist status failed, reg %d\n",
__func__, regval);
return -ETIMEDOUT;
}
return 0;
}
static void ice_enable_intr(struct crypto_vops_qti_entry *ice_entry)
{
uint32_t regval;
regval = ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK);
regval &= ~ICE_REGS_NON_SEC_IRQ_MASK;
ice_writel(ice_entry, regval, ICE_REGS_NON_SEC_IRQ_MASK);
/*
* Memory barrier - to ensure write completion before next transaction
*/
wmb();
}
static void ice_disable_intr(struct crypto_vops_qti_entry *ice_entry)
{
uint32_t regval;
regval = ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK);
regval |= ICE_REGS_NON_SEC_IRQ_MASK;
ice_writel(ice_entry, regval, ICE_REGS_NON_SEC_IRQ_MASK);
/*
* Memory barrier - to ensure write completion before next transaction
*/
wmb();
}
int crypto_qti_enable(void *priv_data)
{
int err = 0;
struct crypto_vops_qti_entry *ice_entry;
ice_entry = (struct crypto_vops_qti_entry *) priv_data;
if (!ice_entry) {
pr_err("%s: vops ice data is invalid\n", __func__);
return -EINVAL;
}
ice_low_power_and_optimization_enable(ice_entry);
err = ice_wait_bist_status(ice_entry);
if (err)
return err;
ice_enable_intr(ice_entry);
return err;
}
void crypto_qti_disable(void *priv_data)
{
struct crypto_vops_qti_entry *ice_entry;
ice_entry = (struct crypto_vops_qti_entry *) priv_data;
if (!ice_entry) {
pr_err("%s: vops ice data is invalid\n", __func__);
return;
}
crypto_qti_disable_platform(ice_entry);
ice_disable_intr(ice_entry);
}
int crypto_qti_resume(void *priv_data)
{
int err = 0;
struct crypto_vops_qti_entry *ice_entry;
ice_entry = (struct crypto_vops_qti_entry *) priv_data;
if (!ice_entry) {
pr_err("%s: vops ice data is invalid\n", __func__);
return -EINVAL;
}
err = ice_wait_bist_status(ice_entry);
return err;
}
static void ice_dump_test_bus(struct crypto_vops_qti_entry *ice_entry)
{
uint32_t regval = 0x1;
uint32_t val;
uint8_t bus_selector;
uint8_t stream_selector;
pr_err("ICE TEST BUS DUMP:\n");
for (bus_selector = 0; bus_selector <= 0xF; bus_selector++) {
regval = 0x1; /* enable test bus */
regval |= bus_selector << 28;
if (bus_selector == 0xD)
continue;
ice_writel(ice_entry, regval, ICE_REGS_TEST_BUS_CONTROL);
/*
* make sure test bus selector is written before reading
* the test bus register
*/
wmb();
val = ice_readl(ice_entry, ICE_REGS_TEST_BUS_REG);
pr_err("ICE_TEST_BUS_CONTROL: 0x%08x | ICE_TEST_BUS_REG: 0x%08x\n",
regval, val);
}
pr_err("ICE TEST BUS DUMP (ICE_STREAM1_DATAPATH_TEST_BUS):\n");
for (stream_selector = 0; stream_selector <= 0xF; stream_selector++) {
regval = 0xD0000001; /* enable stream test bus */
regval |= stream_selector << 16;
ice_writel(ice_entry, regval, ICE_REGS_TEST_BUS_CONTROL);
/*
* make sure test bus selector is written before reading
* the test bus register
*/
wmb();
val = ice_readl(ice_entry, ICE_REGS_TEST_BUS_REG);
pr_err("ICE_TEST_BUS_CONTROL: 0x%08x | ICE_TEST_BUS_REG: 0x%08x\n",
regval, val);
}
}
int crypto_qti_debug(void *priv_data)
{
struct crypto_vops_qti_entry *ice_entry;
ice_entry = (struct crypto_vops_qti_entry *) priv_data;
if (!ice_entry) {
pr_err("%s: vops ice data is invalid\n", __func__);
return -EINVAL;
}
pr_err("%s: ICE Control: 0x%08x | ICE Reset: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_CONTROL),
ice_readl(ice_entry, ICE_REGS_RESET));
pr_err("%s: ICE Version: 0x%08x | ICE FUSE: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_VERSION),
ice_readl(ice_entry, ICE_REGS_FUSE_SETTING));
pr_err("%s: ICE Param1: 0x%08x | ICE Param2: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_PARAMETERS_1),
ice_readl(ice_entry, ICE_REGS_PARAMETERS_2));
pr_err("%s: ICE Param3: 0x%08x | ICE Param4: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_PARAMETERS_3),
ice_readl(ice_entry, ICE_REGS_PARAMETERS_4));
pr_err("%s: ICE Param5: 0x%08x | ICE IRQ STTS: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_PARAMETERS_5),
ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_STTS));
pr_err("%s: ICE IRQ MASK: 0x%08x | ICE IRQ CLR: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK),
ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_CLR));
pr_err("%s: ICE INVALID CCFG ERR STTS: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_INVALID_CCFG_ERR_STTS));
pr_err("%s: ICE BIST Sts: 0x%08x | ICE Bypass Sts: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_BIST_STATUS),
ice_readl(ice_entry, ICE_REGS_BYPASS_STATUS));
pr_err("%s: ICE ADV CTRL: 0x%08x | ICE ENDIAN SWAP: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_ADVANCED_CONTROL),
ice_readl(ice_entry, ICE_REGS_ENDIAN_SWAP));
pr_err("%s: ICE_STM1_ERR_SYND1: 0x%08x | ICE_STM1_ERR_SYND2: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_ERROR_SYNDROME1),
ice_readl(ice_entry, ICE_REGS_STREAM1_ERROR_SYNDROME2));
pr_err("%s: ICE_STM2_ERR_SYND1: 0x%08x | ICE_STM2_ERR_SYND2: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_ERROR_SYNDROME1),
ice_readl(ice_entry, ICE_REGS_STREAM2_ERROR_SYNDROME2));
pr_err("%s: ICE_STM1_COUNTER1: 0x%08x | ICE_STM1_COUNTER2: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS1),
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS2));
pr_err("%s: ICE_STM1_COUNTER3: 0x%08x | ICE_STM1_COUNTER4: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS3),
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS4));
pr_err("%s: ICE_STM2_COUNTER1: 0x%08x | ICE_STM2_COUNTER2: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS1),
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS2));
pr_err("%s: ICE_STM2_COUNTER3: 0x%08x | ICE_STM2_COUNTER4: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS3),
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS4));
pr_err("%s: ICE_STM1_CTR5_MSB: 0x%08x | ICE_STM1_CTR5_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS5_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS5_LSB));
pr_err("%s: ICE_STM1_CTR6_MSB: 0x%08x | ICE_STM1_CTR6_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS6_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS6_LSB));
pr_err("%s: ICE_STM1_CTR7_MSB: 0x%08x | ICE_STM1_CTR7_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS7_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS7_LSB));
pr_err("%s: ICE_STM1_CTR8_MSB: 0x%08x | ICE_STM1_CTR8_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS8_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS8_LSB));
pr_err("%s: ICE_STM1_CTR9_MSB: 0x%08x | ICE_STM1_CTR9_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS9_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS9_LSB));
pr_err("%s: ICE_STM2_CTR5_MSB: 0x%08x | ICE_STM2_CTR5_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS5_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS5_LSB));
pr_err("%s: ICE_STM2_CTR6_MSB: 0x%08x | ICE_STM2_CTR6_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS6_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS6_LSB));
pr_err("%s: ICE_STM2_CTR7_MSB: 0x%08x | ICE_STM2_CTR7_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS7_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS7_LSB));
pr_err("%s: ICE_STM2_CTR8_MSB: 0x%08x | ICE_STM2_CTR8_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS8_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS8_LSB));
pr_err("%s: ICE_STM2_CTR9_MSB: 0x%08x | ICE_STM2_CTR9_LSB: 0x%08x\n",
ice_entry->ice_dev_type,
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS9_MSB),
ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS9_LSB));
ice_dump_test_bus(ice_entry);
return 0;
}
int crypto_qti_keyslot_program(void *priv_data,
const struct blk_crypto_key *key,
unsigned int slot,
u8 data_unit_mask, int capid)
{
int err1 = 0, err2 = 0;
struct crypto_vops_qti_entry *ice_entry;
ice_entry = (struct crypto_vops_qti_entry *) priv_data;
if (!ice_entry) {
pr_err("%s: vops ice data is invalid\n", __func__);
return -EINVAL;
}
err1 = crypto_qti_program_key(ice_entry, key, slot,
data_unit_mask, capid);
if (err1) {
pr_err("%s: program key failed with error %d\n",
__func__, err1);
err2 = crypto_qti_invalidate_key(ice_entry, slot);
if (err2) {
pr_err("%s: invalidate key failed with error %d\n",
__func__, err2);
}
}
return err1;
}
int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot)
{
int err = 0;
struct crypto_vops_qti_entry *ice_entry;
ice_entry = (struct crypto_vops_qti_entry *) priv_data;
if (!ice_entry) {
pr_err("%s: vops ice data is invalid\n", __func__);
return -EINVAL;
}
err = crypto_qti_invalidate_key(ice_entry, slot);
if (err) {
pr_err("%s: invalidate key failed with error %d\n",
__func__, err);
return err;
}
return err;
}
int crypto_qti_derive_raw_secret(const u8 *wrapped_key,
unsigned int wrapped_key_size, u8 *secret,
unsigned int secret_size)
{
int err = 0;
if (wrapped_key_size <= RAW_SECRET_SIZE) {
pr_err("%s: Invalid wrapped_key_size: %u\n",
__func__, wrapped_key_size);
err = -EINVAL;
return err;
}
if (secret_size != RAW_SECRET_SIZE) {
pr_err("%s: Invalid secret size: %u\n", __func__, secret_size);
err = -EINVAL;
return err;
}
if (wrapped_key_size > 64)
err = crypto_qti_tz_raw_secret(wrapped_key, wrapped_key_size,
secret, secret_size);
else
memcpy(secret, wrapped_key, secret_size);
return err;
}