crypto: msm: ice: Add support for eMMC based ICE

ICE (Inline Crypto Engine) encrypts/decrypts storage IO requests to
minimize degradation in storage IO throughput. ICE has been added to
eMMC based storage hardware as well. Adding support from ICE driver
side.

Change-Id: I87362bb0de5e94e9146182ee85766e92b72ecfaa
Signed-off-by: Dinesh K Garg <dineshg@codeaurora.org>
This commit is contained in:
Dinesh K Garg 2015-05-11 17:32:46 -07:00 committed by AnilKumar Chimata
parent add3130ee0
commit 9359ab28f6
2 changed files with 111 additions and 60 deletions

View File

@ -13,6 +13,8 @@ Optional properties:
order as the clocks property.
- qocm,op-freq-hz : max clock speed sorted in the same order as the clocks
property.
- qcom,instance-type : describe the storage type for which ICE node is defined
currently, only "ufs" and "sdcc" are supported storage type
Example:
ufs_ice: ufsice@630000 {
@ -25,5 +27,6 @@ Example:
clocks = <&clock_gcc clk_ufs_ice_core_clk_src>,
<&clock_gcc clk_gcc_ufs_ice_core_clk>;
qcom,op-freq-hz = <300000000>, <0>;
qcom,instance-type = "ufs";
status = "disabled";
};

View File

@ -22,6 +22,7 @@
#include <linux/blk_types.h>
#include <linux/blkdev.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <crypto/ice.h>
#include <soc/qcom/scm.h>
#include "iceregs.h"
@ -43,7 +44,8 @@
TZ_SYSCALL_CREATE_PARAM_ID_0
#define ICE_REV(x, y) (((x) & ICE_CORE_##y##_REV_MASK) >> ICE_CORE_##y##_REV)
#define DEFAULT_ICE_CORE_CLK_FREQ 300000000
#define QCOM_ICE_DEV "ice"
#define QCOM_ICE_TYPE_NAME_LEN 8
const struct qcom_ice_variant_ops qcom_ice_ops;
@ -64,6 +66,9 @@ static LIST_HEAD(ice_devices);
struct ice_device {
struct list_head list;
struct device *pdev;
struct cdev cdev;
dev_t device_no;
struct class *driver_class;
void __iomem *mmio;
int irq;
bool is_irq_enabled;
@ -77,15 +82,15 @@ struct ice_device {
struct list_head clk_list_head;
u32 ice_hw_version;
bool is_ice_clk_available;
char ice_instance_type[QCOM_ICE_TYPE_NAME_LEN];
};
static int qcom_ice_enable_clocks(struct ice_device *, bool);
static void qcom_ice_config_proc_ignore(struct ice_device *ice_dev)
{
u32 regval;
if (ICE_REV(ice_dev->ice_hw_version, MAJOR) == 2 &&
ICE_REV(ice_dev->ice_hw_version, MINOR) == 0) {
ICE_REV(ice_dev->ice_hw_version, MINOR) == 0 &&
ICE_REV(ice_dev->ice_hw_version, STEP) == 0) {
regval = qcom_ice_readl(ice_dev,
QCOM_ICE_REGS_ADVANCED_CONTROL);
regval |= 0x800;
@ -316,6 +321,25 @@ static irqreturn_t qcom_ice_isr(int isr, void *data)
return retval;
}
static void qcom_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;
char *type;
ret = of_property_read_string_index(np,
"qcom,instance-type", 0, (const char **)&type);
if (ret) {
pr_err("%s: Could not get ICE instance type\n", __func__);
goto out;
}
strlcpy(ice_dev->ice_instance_type, type, QCOM_ICE_TYPE_NAME_LEN);
out:
return;
}
static int qcom_ice_parse_clock_info(struct platform_device *pdev,
struct ice_device *ice_dev)
{
@ -423,6 +447,7 @@ static int qcom_ice_get_device_tree_data(struct platform_device *pdev,
}
pr_info("ICE IRQ = %d\n", ice_dev->irq);
}
qcom_ice_parse_ice_instance_type(pdev, ice_dev);
return 0;
err_dev:
if (rc && ice_dev->mmio)
@ -431,6 +456,77 @@ out:
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 don't 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 qcom_ice_fops = {
.owner = THIS_MODULE,
};
static int register_ice_device(struct ice_device *ice_dev)
{
int rc = 0;
unsigned baseminor = 0;
unsigned count = 1;
struct device *class_dev;
char tmp_dev_name[16];
memset(tmp_dev_name, 0, 16);
strlcpy(tmp_dev_name, QCOM_ICE_DEV, 8);
strlcat(tmp_dev_name, ice_dev->ice_instance_type, 8);
pr_debug("%s: instance type = %s device name = %s\n", __func__,
ice_dev->ice_instance_type, tmp_dev_name);
rc = alloc_chrdev_region(&ice_dev->device_no, baseminor, count,
tmp_dev_name);
if (rc < 0) {
pr_err("alloc_chrdev_region failed %d for %s\n",
rc, tmp_dev_name);
return rc;
}
ice_dev->driver_class = class_create(THIS_MODULE, tmp_dev_name);
if (IS_ERR(ice_dev->driver_class)) {
rc = -ENOMEM;
pr_err("class_create failed %d for %s\n", rc, tmp_dev_name);
goto exit_unreg_chrdev_region;
}
class_dev = device_create(ice_dev->driver_class, NULL,
ice_dev->device_no, NULL, tmp_dev_name);
if (!class_dev) {
pr_err("class_device_create failed %d for %s\n",
rc, tmp_dev_name);
rc = -ENOMEM;
goto exit_destroy_class;
}
cdev_init(&ice_dev->cdev, &qcom_ice_fops);
ice_dev->cdev.owner = THIS_MODULE;
rc = cdev_add(&ice_dev->cdev, MKDEV(MAJOR(ice_dev->device_no), 0), 1);
if (rc < 0) {
pr_err("cdev_add failed %d for %s\n", rc, tmp_dev_name);
goto exit_destroy_device;
}
return 0;
exit_destroy_device:
device_destroy(ice_dev->driver_class, ice_dev->device_no);
exit_destroy_class:
class_destroy(ice_dev->driver_class);
exit_unreg_chrdev_region:
unregister_chrdev_region(ice_dev->device_no, 1);
return rc;
}
static int qcom_ice_probe(struct platform_device *pdev)
{
struct ice_device *ice_dev;
@ -469,6 +565,13 @@ static int qcom_ice_probe(struct platform_device *pdev)
if (rc)
goto err_ice_dev;
pr_debug("%s: Registering ICE device\n", __func__);
rc = register_ice_device(ice_dev);
if (rc) {
pr_err("create character device failed.\n");
goto err_ice_dev;
}
spin_lock_init(&ice_dev->lock);
/*
* If ICE is enabled here, it would be waste of power.
* We would enable ICE when first request for crypto
@ -510,18 +613,6 @@ static int qcom_ice_remove(struct platform_device *pdev)
static int qcom_ice_suspend(struct platform_device *pdev)
{
struct ice_device *ice_dev;
ice_dev = (struct ice_device *)platform_get_drvdata(pdev);
if (!ice_dev)
return 0;
/*
* Storage driver would take care of storage clocks. ICE Driver should
* disable its clock
*/
if (ice_dev->is_ice_clk_available)
qcom_ice_enable_clocks(ice_dev, false);
return 0;
}
@ -591,45 +682,6 @@ out:
return ret;
}
static int qcom_ice_enable_clocks(struct ice_device *ice, bool enable)
{
int ret = 0;
struct ice_clk_info *clki;
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 int qcom_ice_secure_ice_init(struct ice_device *ice_dev)
{
/* We need to enable source for ICE secure interrupts */
@ -706,9 +758,7 @@ static void qcom_ice_finish_init(void *data, async_cookie_t cookie)
}
if (ice_dev->is_ice_clk_available) {
if (!qcom_ice_init_clocks(ice_dev)) {
qcom_ice_enable_clocks(ice_dev, true);
} else {
if (qcom_ice_init_clocks(ice_dev)) {
ice_dev->error_cb(ice_dev->host_controller_data,
ICE_ERROR_IMPROPER_INITIALIZATION);
return;
@ -816,7 +866,6 @@ static void qcom_ice_finish_power_collapse(void *data, async_cookie_t cookie)
* ICE resets into global bypass mode with optimization and
* low power mode disabled. Hence we need to redo those seq's.
*/
qcom_ice_enable_clocks(ice_dev, true);
qcom_ice_low_power_mode_enable(ice_dev);
qcom_ice_enable_test_bus_config(ice_dev);
@ -866,7 +915,6 @@ static int qcom_ice_resume(struct platform_device *pdev)
return -EINVAL;
if (ice_dev->is_ice_clk_available) {
qcom_ice_enable_clocks(ice_dev, true);
/*
* Storage is calling this function after power collapse which
* would put ICE into GLOBAL_BYPASS mode. Make sure to enable