crypto: msm: add inline crypto engine (ICE) driver snapshot

This snapshot is taken as of msm-3.18 commit e70ad0c ("Promotion of kernel.lnx.3.18-151201")

Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
This commit is contained in:
Gilad Broner 2016-02-24 12:01:29 +02:00 committed by David Keitel
parent 03bad71331
commit ce93b221ca
9 changed files with 2174 additions and 1 deletions

View file

@ -0,0 +1,235 @@
Introduction:
=============
Storage encryption has been one of the most required feature from security
point of view. QTI based storage encryption solution uses general purpose
crypto engine. While this kind of solution provide a decent amount of
performance, it falls short as storage speed is improving significantly
continuously. To overcome performance degradation, newer chips are going to
have Inline Crypto Engine (ICE) embedded into storage device. ICE is supposed
to meet the line speed of storage devices.
Hardware Description
====================
ICE is a HW block that is embedded into storage device such as UFS/eMMC. By
default, ICE works in bypass mode i.e. ICE HW does not perform any crypto
operation on data to be processed by storage device. If required, ICE can be
configured to perform crypto operation in one direction (i.e. either encryption
or decryption) or in both direction(both encryption & decryption).
When a switch between the operation modes(plain to crypto or crypto to plain)
is desired for a particular partition, SW must complete all transactions for
that particular partition before switching the crypto mode i.e. no crypto, one
direction crypto or both direction crypto operation. Requests for other
partitions are not impacted due to crypto mode switch.
ICE HW currently supports AES128/256 bit ECB & XTS mode encryption algorithms.
Keys for crypto operations are loaded from SW. Keys are stored in a lookup
table(LUT) located inside ICE HW. Maximum of 32 keys can be loaded in ICE key
LUT. A Key inside the LUT can be referred using a key index.
SW Description
==============
ICE HW has catagorized ICE registers in 2 groups: those which can be accessed by
only secure side i.e. TZ and those which can be accessed by non-secure side such
as HLOS as well. This requires that ICE driver to be split in two pieces: one
running from TZ space and another from HLOS space.
ICE driver from TZ would configure keys as requested by HLOS side.
ICE driver on HLOS side is responsible for initialization of ICE HW.
SW Architecture Diagram
=======================
Following are all the components involved in the ICE driver for control path:
+++++++++++++++++++++++++++++++++++++++++
+ App layer +
+++++++++++++++++++++++++++++++++++++++++
+ System layer +
+ ++++++++ +++++++ +
+ + VOLD + + PFM + +
+ ++++++++ +++++++ +
+ || || +
+ || || +
+ \/ \/ +
+ ++++++++++++++ +
+ + LibQSEECom + +
+ ++++++++++++++ +
+++++++++++++++++++++++++++++++++++++++++
+ Kernel + +++++++++++++++++
+ + + KMS +
+ +++++++ +++++++++++ +++++++++++ + +++++++++++++++++
+ + ICE + + Storage + + QSEECom + + + ICE Driver +
+++++++++++++++++++++++++++++++++++++++++ <===> +++++++++++++++++
|| ||
|| ||
\/ \/
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Storage Device +
+ ++++++++++++++ +
+ + ICE HW + +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Use Cases:
----------
a) Device bootup
ICE HW is detected during bootup time and corresponding probe function is
called. ICE driver parses its data from device tree node. ICE HW and storage
HW are tightly coupled. Storage device probing is dependent upon ICE device
probing. ICE driver configures all the required registers to put the ICE HW
in bypass mode.
b) Configuring keys
Currently, there are couple of use cases to configure the keys.
1) Full Disk Encryption(FDE)
System layer(VOLD) at invocation of apps layer would call libqseecom to create
the encryption key. Libqseecom calls qseecom driver to communicate with KMS
module on the secure side i.e. TZ. KMS would call ICE driver on the TZ side to
create and set the keys in ICE HW. At the end of transaction, VOLD would have
key index of key LUT where encryption key is present.
2) Per File Encryption (PFE)
Per File Manager(PFM) calls QSEECom api to create the key. PFM has a peer comp-
onent(PFT) at kernel layer which gets the corresponding key index from PFM.
Following are all the components involved in the ICE driver for data path:
+++++++++++++++++++++++++++++++++++++++++
+ App layer +
+++++++++++++++++++++++++++++++++++++++++
+ VFS +
+---------------------------------------+
+ File System (EXT4) +
+---------------------------------------+
+ Block Layer +
+ --------------------------------------+
+ +++++++ +
+ dm-req-crypt => + PFT + +
+ +++++++ +
+ +
+---------------------------------------+
+ +++++++++++ +++++++ +
+ + Storage + + ICE + +
+++++++++++++++++++++++++++++++++++++++++
+ || +
+ || (Storage Req with +
+ \/ ICE parameters ) +
+++++++++++++++++++++++++++++++++++++++++
+ Storage Device +
+ ++++++++++++++ +
+ + ICE HW + +
+++++++++++++++++++++++++++++++++++++++++
c) Data transaction
Once the crypto key has been configured, VOLD/PFM creates device mapping for
data partition. As part of device mapping VOLD passes key index, crypto
algorithm, mode and key length to dm layer. In case of PFE, keys are provided
by PFT as and when request is processed by dm-req-crypt. When any application
needs to read/write data, it would go through DM layer which would add crypto
information, provided by VOLD/PFT, to Request. For each Request, Storage driver
would ask ICE driver to configure crypto part of request. ICE driver extracts
crypto data from Request structure and provide it to storage driver which would
finally dispatch request to storage device.
d) Error Handling
Due to issue # 1 mentioned in "Known Issues", ICE driver does not register for
any interrupt. However, it enables sources of interrupt for ICE HW. After each
data transaction, Storage driver receives transaction completion event. As part
of event handling, storage driver calls ICE driver to check if any of ICE
interrupt status is set. If yes, storage driver returns error to upper layer.
Error handling would be changed in future chips.
Interfaces
==========
ICE driver exposes interfaces for storage driver to :
1. Get the global instance of ICE driver
2. Get the implemented interfaces of the particular ice instance
3. Initialize the ICE HW
4. Reset the ICE HW
5. Resume/Suspend the ICE HW
6. Get the Crypto configuration for the data request for storage
7. Check if current data transaction has generated any interrupt
Driver Parameters
=================
This driver is built and statically linked into the kernel; therefore,
there are no module parameters supported by this driver.
There are no kernel command line parameters supported by this driver.
Power Management
================
ICE driver does not do power management on its own as it is part of storage
hardware. Whenever storage driver receives request for power collapse/suspend
resume, it would call ICE driver which exposes APIs for Storage HW. ICE HW
during power collapse or reset, wipes crypto configuration data. When ICE
driver receives request to resume, it would ask ICE driver on TZ side to
restore the configuration. ICE driver does not do anything as part of power
collapse or suspend event.
Interface:
==========
ICE driver exposes following APIs for storage driver to use:
int (*init)(struct platform_device *, void *, ice_success_cb, ice_error_cb);
-- This function is invoked by storage controller during initialization of
storage controller. Storage controller would provide success and error call
backs which would be invoked asynchronously once ICE HW init is done.
int (*reset)(struct platform_device *);
-- ICE HW reset as part of storage controller reset. When storage controller
received reset command, it would call reset on ICE HW. As of now, ICE HW
does not need to do anything as part of reset.
int (*resume)(struct platform_device *);
-- ICE HW while going to reset, wipes all crypto keys and other data from ICE
HW. ICE driver would reconfigure those data as part of resume operation.
int (*suspend)(struct platform_device *);
-- This API would be called by storage driver when storage device is going to
suspend mode. As of today, ICE driver does not do anything to handle suspend.
int (*config)(struct platform_device *, struct request* , struct ice_data_setting*);
-- Storage driver would call this interface to get all crypto data required to
perform crypto operation.
int (*status)(struct platform_device *);
-- Storage driver would call this interface to check if previous data transfer
generated any error.
Config options
==============
This driver is enabled by the kernel config option CONFIG_CRYPTO_DEV_MSM_ICE.
Dependencies
============
ICE driver depends upon corresponding ICE driver on TZ side to function
appropriately.
Known Issues
============
1. ICE HW emits 0s even if it has generated an interrupt
This issue has significant impact on how ICE interrupts are handled. Currently,
ICE driver does not register for any of the ICE interrupts but enables the
sources of interrupt. Once storage driver asks to check the status of interrupt,
it reads and clears the clear status and provide read status to storage driver.
This mechanism though not optimal but prevents filesystem curruption.
This issue has been fixed in newer chips.
2. ICE HW wipes all crypto data during power collapse
This issue necessiate that ICE driver on TZ side store the crypto material
which is not required in the case of general purpose crypto engine.
This issue has been fixed in newer chips.
Further Improvements
====================
Currently, Due to PFE use case, ICE driver is dependent upon dm-req-crypt to
provide the keys as part of request structure. This couples ICE driver with
dm-req-crypt based solution. It is under discussion to expose an IOCTL based
and registeration based interface APIs from ICE driver. ICE driver would use
these two interfaces to find out if any key exists for current request. If
yes, choose the right key index received from IOCTL or registeration based
APIs. If not, dont set any crypto parameter in the request.

View file

@ -0,0 +1,32 @@
* Inline Crypto Engine (ICE)
Required properties:
- compatible : should be "qcom,ice"
- reg : <register mapping>
Optional properties:
- interrupt-names : name describing the interrupts for ICE IRQ
- interrupts : <interrupt mapping for ICE IRQ>
- qcom,enable-ice-clk : should enable clocks for ICE HW
- clocks : List of phandle and clock specifier pairs
- clock-names : List of clock input name strings sorted in the same
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 {
compatible = "qcom,ice";
reg = <0x630000 0x8000>;
interrupt-names = "ufs_ice_nonsec_level_irq", "ufs_ice_sec_level_irq";
interrupts = <0 258 0>, <0 257 0>;
qcom,enable-ice-clk;
clock-names = "ice_core_clk_src", "ice_core_clk";
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

@ -556,4 +556,9 @@ config CRYPTO_DEV_SUN4I_SS
To compile this driver as a module, choose M here: the module
will be called sun4i-ss.
if ARCH_QCOM
source "drivers/crypto/msm/Kconfig"
endif # ARCH_QCOM
endif # CRYPTO_HW

View file

@ -30,3 +30,4 @@ obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
obj-$(CONFIG_CRYPTO_DEV_QCOM_MSM_QCE) += msm/
obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/
obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/
obj-$(CONFIG_ARCH_QCOM) += msm/

View file

@ -0,0 +1,9 @@
config CRYPTO_DEV_QCOM_ICE
tristate "Inline Crypto Module"
default n
help
This driver supports Inline Crypto Engine for QTI chipsets, MSM8994
and later, to accelerate crypto operations for storage needs.
To compile this driver as a module, choose M here: the
module will be called ice.

View file

@ -9,4 +9,4 @@ obj-$(CONFIG_CRYPTO_DEV_QCOM_MSM_QCE) += compat_qcedev.o
endif
obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto.o
obj-$(CONFIG_CRYPTO_DEV_OTA_CRYPTO) += ota_crypto.o
obj-$(CONFIG_CRYPTO_DEV_QCOM_ICE) += ice.o

1743
drivers/crypto/msm/ice.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,147 @@
/* Copyright (c) 2014-2015, The 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.
*/
#ifndef _QCOM_INLINE_CRYPTO_ENGINE_REGS_H_
#define _QCOM_INLINE_CRYPTO_ENGINE_REGS_H_
/* Register bits for ICE version */
#define ICE_CORE_CURRENT_MAJOR_VERSION 0x02
#define ICE_CORE_STEP_REV_MASK 0xFFFF
#define ICE_CORE_STEP_REV 0 /* bit 15-0 */
#define ICE_CORE_MAJOR_REV_MASK 0xFF000000
#define ICE_CORE_MAJOR_REV 24 /* bit 31-24 */
#define ICE_CORE_MINOR_REV_MASK 0xFF0000
#define ICE_CORE_MINOR_REV 16 /* bit 23-16 */
#define ICE_FUSE_SETTING_MASK 0x1
#define ICE_FORCE_HW_KEY0_SETTING_MASK 0x2
#define ICE_FORCE_HW_KEY1_SETTING_MASK 0x4
/* QCOM ICE Registers from SWI */
#define QCOM_ICE_REGS_CONTROL 0x0000
#define QCOM_ICE_REGS_RESET 0x0004
#define QCOM_ICE_REGS_VERSION 0x0008
#define QCOM_ICE_REGS_FUSE_SETTING 0x0010
#define QCOM_ICE_REGS_PARAMETERS_1 0x0014
#define QCOM_ICE_REGS_PARAMETERS_2 0x0018
#define QCOM_ICE_REGS_PARAMETERS_3 0x001C
#define QCOM_ICE_REGS_PARAMETERS_4 0x0020
#define QCOM_ICE_REGS_PARAMETERS_5 0x0024
#define QCOM_ICE_REGS_NON_SEC_IRQ_STTS 0x0040
#define QCOM_ICE_REGS_NON_SEC_IRQ_MASK 0x0044
#define QCOM_ICE_REGS_NON_SEC_IRQ_CLR 0x0048
#define QCOM_ICE_REGS_STREAM1_ERROR_SYNDROME1 0x0050
#define QCOM_ICE_REGS_STREAM1_ERROR_SYNDROME2 0x0054
#define QCOM_ICE_REGS_STREAM2_ERROR_SYNDROME1 0x0058
#define QCOM_ICE_REGS_STREAM2_ERROR_SYNDROME2 0x005C
#define QCOM_ICE_REGS_STREAM1_BIST_ERROR_VEC 0x0060
#define QCOM_ICE_REGS_STREAM2_BIST_ERROR_VEC 0x0064
#define QCOM_ICE_REGS_STREAM1_BIST_FINISH_VEC 0x0068
#define QCOM_ICE_REGS_STREAM2_BIST_FINISH_VEC 0x006C
#define QCOM_ICE_REGS_BIST_STATUS 0x0070
#define QCOM_ICE_REGS_BYPASS_STATUS 0x0074
#define QCOM_ICE_REGS_ADVANCED_CONTROL 0x1000
#define QCOM_ICE_REGS_ENDIAN_SWAP 0x1004
#define QCOM_ICE_REGS_TEST_BUS_CONTROL 0x1010
#define QCOM_ICE_REGS_TEST_BUS_REG 0x1014
#define QCOM_ICE_REGS_STREAM1_COUNTERS1 0x1100
#define QCOM_ICE_REGS_STREAM1_COUNTERS2 0x1104
#define QCOM_ICE_REGS_STREAM1_COUNTERS3 0x1108
#define QCOM_ICE_REGS_STREAM1_COUNTERS4 0x110C
#define QCOM_ICE_REGS_STREAM1_COUNTERS5_MSB 0x1110
#define QCOM_ICE_REGS_STREAM1_COUNTERS5_LSB 0x1114
#define QCOM_ICE_REGS_STREAM1_COUNTERS6_MSB 0x1118
#define QCOM_ICE_REGS_STREAM1_COUNTERS6_LSB 0x111C
#define QCOM_ICE_REGS_STREAM1_COUNTERS7_MSB 0x1120
#define QCOM_ICE_REGS_STREAM1_COUNTERS7_LSB 0x1124
#define QCOM_ICE_REGS_STREAM1_COUNTERS8_MSB 0x1128
#define QCOM_ICE_REGS_STREAM1_COUNTERS8_LSB 0x112C
#define QCOM_ICE_REGS_STREAM1_COUNTERS9_MSB 0x1130
#define QCOM_ICE_REGS_STREAM1_COUNTERS9_LSB 0x1134
#define QCOM_ICE_REGS_STREAM2_COUNTERS1 0x1200
#define QCOM_ICE_REGS_STREAM2_COUNTERS2 0x1204
#define QCOM_ICE_REGS_STREAM2_COUNTERS3 0x1208
#define QCOM_ICE_REGS_STREAM2_COUNTERS4 0x120C
#define QCOM_ICE_REGS_STREAM2_COUNTERS5_MSB 0x1210
#define QCOM_ICE_REGS_STREAM2_COUNTERS5_LSB 0x1214
#define QCOM_ICE_REGS_STREAM2_COUNTERS6_MSB 0x1218
#define QCOM_ICE_REGS_STREAM2_COUNTERS6_LSB 0x121C
#define QCOM_ICE_REGS_STREAM2_COUNTERS7_MSB 0x1220
#define QCOM_ICE_REGS_STREAM2_COUNTERS7_LSB 0x1224
#define QCOM_ICE_REGS_STREAM2_COUNTERS8_MSB 0x1228
#define QCOM_ICE_REGS_STREAM2_COUNTERS8_LSB 0x122C
#define QCOM_ICE_REGS_STREAM2_COUNTERS9_MSB 0x1230
#define QCOM_ICE_REGS_STREAM2_COUNTERS9_LSB 0x1234
#define QCOM_ICE_STREAM1_PREMATURE_LBA_CHANGE (1L << 0)
#define QCOM_ICE_STREAM2_PREMATURE_LBA_CHANGE (1L << 1)
#define QCOM_ICE_STREAM1_NOT_EXPECTED_LBO (1L << 2)
#define QCOM_ICE_STREAM2_NOT_EXPECTED_LBO (1L << 3)
#define QCOM_ICE_STREAM1_NOT_EXPECTED_DUN (1L << 4)
#define QCOM_ICE_STREAM2_NOT_EXPECTED_DUN (1L << 5)
#define QCOM_ICE_STREAM1_NOT_EXPECTED_DUS (1L << 6)
#define QCOM_ICE_STREAM2_NOT_EXPECTED_DUS (1L << 7)
#define QCOM_ICE_STREAM1_NOT_EXPECTED_DBO (1L << 8)
#define QCOM_ICE_STREAM2_NOT_EXPECTED_DBO (1L << 9)
#define QCOM_ICE_STREAM1_NOT_EXPECTED_ENC_SEL (1L << 10)
#define QCOM_ICE_STREAM2_NOT_EXPECTED_ENC_SEL (1L << 11)
#define QCOM_ICE_STREAM1_NOT_EXPECTED_CONF_IDX (1L << 12)
#define QCOM_ICE_STREAM2_NOT_EXPECTED_CONF_IDX (1L << 13)
#define QCOM_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS (1L << 14)
#define QCOM_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS (1L << 15)
#define QCOM_ICE_NON_SEC_IRQ_MASK \
(QCOM_ICE_STREAM1_PREMATURE_LBA_CHANGE |\
QCOM_ICE_STREAM2_PREMATURE_LBA_CHANGE |\
QCOM_ICE_STREAM1_NOT_EXPECTED_LBO |\
QCOM_ICE_STREAM2_NOT_EXPECTED_LBO |\
QCOM_ICE_STREAM1_NOT_EXPECTED_DUN |\
QCOM_ICE_STREAM2_NOT_EXPECTED_DUN |\
QCOM_ICE_STREAM2_NOT_EXPECTED_DUN |\
QCOM_ICE_STREAM2_NOT_EXPECTED_DUS |\
QCOM_ICE_STREAM1_NOT_EXPECTED_DBO |\
QCOM_ICE_STREAM2_NOT_EXPECTED_DBO |\
QCOM_ICE_STREAM1_NOT_EXPECTED_ENC_SEL |\
QCOM_ICE_STREAM2_NOT_EXPECTED_ENC_SEL |\
QCOM_ICE_STREAM1_NOT_EXPECTED_CONF_IDX |\
QCOM_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS |\
QCOM_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS)
/* QCOM ICE registers from secure side */
#define QCOM_ICE_TEST_BUS_REG_SECURE_INTR (1L << 28)
#define QCOM_ICE_TEST_BUS_REG_NON_SECURE_INTR (1L << 2)
#define QCOM_ICE_LUT_KEYS_ICE_SEC_IRQ_STTS 0x2050
#define QCOM_ICE_LUT_KEYS_ICE_SEC_IRQ_MASK 0x2054
#define QCOM_ICE_LUT_KEYS_ICE_SEC_IRQ_CLR 0x2058
#define QCOM_ICE_STREAM1_PARTIALLY_SET_KEY_USED (1L << 0)
#define QCOM_ICE_STREAM2_PARTIALLY_SET_KEY_USED (1L << 1)
#define QCOM_ICE_QCOMC_DBG_OPEN_EVENT (1L << 30)
#define QCOM_ICE_KEYS_RAM_RESET_COMPLETED (1L << 31)
#define QCOM_ICE_SEC_IRQ_MASK \
(QCOM_ICE_STREAM1_PARTIALLY_SET_KEY_USED |\
QCOM_ICE_STREAM2_PARTIALLY_SET_KEY_USED |\
QCOM_ICE_QCOMC_DBG_OPEN_EVENT | \
QCOM_ICE_KEYS_RAM_RESET_COMPLETED)
#define qcom_ice_writel(ice, val, reg) \
writel_relaxed((val), (ice)->mmio + (reg))
#define qcom_ice_readl(ice, reg) \
readl_relaxed((ice)->mmio + (reg))
#endif /* _QCOM_INLINE_CRYPTO_ENGINE_REGS_H_ */

View file

@ -134,6 +134,7 @@ struct bio {
*/
#define BIO_RESET_BITS 13
#define BIO_OWNS_VEC 13 /* bio_free() should free bvec */
#define BIO_INLINECRYPT 15
/*
* top 4 bits of bio flags indicate the pool this bio came from