BACKPORT: FROMLIST: scsi: ufs: UFS crypto API
Introduce functions to manipulate UFS inline encryption hardware in line with the JEDEC UFSHCI v2.1 specification and to work with the block keyslot manager. Bug: 137270441 Test: tested as series; see I26aac0ac7845a9064f28bb1421eb2522828a6dec Change-Id: I4c6ba30f30eaea83da6822381ae2aa85b40e7b90 Signed-off-by: Satya Tangirala <satyat@google.com> Link: https://patchwork.kernel.org/patch/11214745/
This commit is contained in:
parent
e00aafeeaa
commit
eedb625131
5 changed files with 501 additions and 0 deletions
drivers/scsi/ufs
|
@ -109,3 +109,12 @@ config SCSI_UFS_HISI
|
|||
|
||||
Select this if you have UFS controller on Hisilicon chipset.
|
||||
If unsure, say N.
|
||||
|
||||
config SCSI_UFS_CRYPTO
|
||||
bool "UFS Crypto Engine Support"
|
||||
depends on SCSI_UFSHCD && BLK_INLINE_ENCRYPTION
|
||||
help
|
||||
Enable Crypto Engine Support in UFS.
|
||||
Enabling this makes it possible for the kernel to use the crypto
|
||||
capabilities of the UFS device (if present) to perform crypto
|
||||
operations on data being transferred to/from the device.
|
||||
|
|
|
@ -8,3 +8,4 @@ ufshcd-core-objs := ufshcd.o ufs-sysfs.o
|
|||
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
|
||||
obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
|
||||
ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o
|
||||
|
|
391
drivers/scsi/ufs/ufshcd-crypto.c
Normal file
391
drivers/scsi/ufs/ufshcd-crypto.c
Normal file
|
@ -0,0 +1,391 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
||||
#include <crypto/algapi.h>
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "ufshcd-crypto.h"
|
||||
|
||||
static bool ufshcd_cap_idx_valid(struct ufs_hba *hba, unsigned int cap_idx)
|
||||
{
|
||||
return cap_idx < hba->crypto_capabilities.num_crypto_cap;
|
||||
}
|
||||
|
||||
static u8 get_data_unit_size_mask(unsigned int data_unit_size)
|
||||
{
|
||||
if (data_unit_size < 512 || data_unit_size > 65536 ||
|
||||
!is_power_of_2(data_unit_size))
|
||||
return 0;
|
||||
|
||||
return data_unit_size / 512;
|
||||
}
|
||||
|
||||
static size_t get_keysize_bytes(enum ufs_crypto_key_size size)
|
||||
{
|
||||
switch (size) {
|
||||
case UFS_CRYPTO_KEY_SIZE_128: return 16;
|
||||
case UFS_CRYPTO_KEY_SIZE_192: return 24;
|
||||
case UFS_CRYPTO_KEY_SIZE_256: return 32;
|
||||
case UFS_CRYPTO_KEY_SIZE_512: return 64;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ufshcd_crypto_cap_find(void *hba_p,
|
||||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int data_unit_size)
|
||||
{
|
||||
struct ufs_hba *hba = hba_p;
|
||||
enum ufs_crypto_alg ufs_alg;
|
||||
u8 data_unit_mask;
|
||||
int cap_idx;
|
||||
enum ufs_crypto_key_size ufs_key_size;
|
||||
union ufs_crypto_cap_entry *ccap_array = hba->crypto_cap_array;
|
||||
|
||||
if (!ufshcd_hba_is_crypto_supported(hba))
|
||||
return -EINVAL;
|
||||
|
||||
switch (crypto_mode) {
|
||||
case BLK_ENCRYPTION_MODE_AES_256_XTS:
|
||||
ufs_alg = UFS_CRYPTO_ALG_AES_XTS;
|
||||
ufs_key_size = UFS_CRYPTO_KEY_SIZE_256;
|
||||
break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
|
||||
data_unit_mask = get_data_unit_size_mask(data_unit_size);
|
||||
|
||||
for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap;
|
||||
cap_idx++) {
|
||||
if (ccap_array[cap_idx].algorithm_id == ufs_alg &&
|
||||
(ccap_array[cap_idx].sdus_mask & data_unit_mask) &&
|
||||
ccap_array[cap_idx].key_size == ufs_key_size)
|
||||
return cap_idx;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_crypto_cfg_entry_write_key - Write a key into a crypto_cfg_entry
|
||||
*
|
||||
* Writes the key with the appropriate format - for AES_XTS,
|
||||
* the first half of the key is copied as is, the second half is
|
||||
* copied with an offset halfway into the cfg->crypto_key array.
|
||||
* For the other supported crypto algs, the key is just copied.
|
||||
*
|
||||
* @cfg: The crypto config to write to
|
||||
* @key: The key to write
|
||||
* @cap: The crypto capability (which specifies the crypto alg and key size)
|
||||
*
|
||||
* Returns 0 on success, or -EINVAL
|
||||
*/
|
||||
static int ufshcd_crypto_cfg_entry_write_key(union ufs_crypto_cfg_entry *cfg,
|
||||
const u8 *key,
|
||||
union ufs_crypto_cap_entry cap)
|
||||
{
|
||||
size_t key_size_bytes = get_keysize_bytes(cap.key_size);
|
||||
|
||||
if (key_size_bytes == 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cap.algorithm_id) {
|
||||
case UFS_CRYPTO_ALG_AES_XTS:
|
||||
key_size_bytes *= 2;
|
||||
if (key_size_bytes > UFS_CRYPTO_KEY_MAX_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(cfg->crypto_key, key, key_size_bytes/2);
|
||||
memcpy(cfg->crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2,
|
||||
key + key_size_bytes/2, key_size_bytes/2);
|
||||
return 0;
|
||||
case UFS_CRYPTO_ALG_BITLOCKER_AES_CBC: // fallthrough
|
||||
case UFS_CRYPTO_ALG_AES_ECB: // fallthrough
|
||||
case UFS_CRYPTO_ALG_ESSIV_AES_CBC:
|
||||
memcpy(cfg->crypto_key, key, key_size_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void program_key(struct ufs_hba *hba,
|
||||
const union ufs_crypto_cfg_entry *cfg,
|
||||
int slot)
|
||||
{
|
||||
int i;
|
||||
u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg);
|
||||
|
||||
/* Clear the dword 16 */
|
||||
ufshcd_writel(hba, 0, slot_offset + 16 * sizeof(cfg->reg_val[0]));
|
||||
/* Ensure that CFGE is cleared before programming the key */
|
||||
wmb();
|
||||
for (i = 0; i < 16; i++) {
|
||||
ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[i]),
|
||||
slot_offset + i * sizeof(cfg->reg_val[0]));
|
||||
/* Spec says each dword in key must be written sequentially */
|
||||
wmb();
|
||||
}
|
||||
/* Write dword 17 */
|
||||
ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[17]),
|
||||
slot_offset + 17 * sizeof(cfg->reg_val[0]));
|
||||
/* Dword 16 must be written last */
|
||||
wmb();
|
||||
/* Write dword 16 */
|
||||
ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[16]),
|
||||
slot_offset + 16 * sizeof(cfg->reg_val[0]));
|
||||
wmb();
|
||||
}
|
||||
|
||||
static int ufshcd_crypto_keyslot_program(void *hba_p, const u8 *key,
|
||||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int data_unit_size,
|
||||
unsigned int slot)
|
||||
{
|
||||
struct ufs_hba *hba = hba_p;
|
||||
int err = 0;
|
||||
u8 data_unit_mask;
|
||||
union ufs_crypto_cfg_entry cfg;
|
||||
union ufs_crypto_cfg_entry *cfg_arr = hba->crypto_cfgs;
|
||||
int cap_idx;
|
||||
|
||||
cap_idx = ufshcd_crypto_cap_find(hba_p, crypto_mode,
|
||||
data_unit_size);
|
||||
|
||||
if (!ufshcd_is_crypto_enabled(hba) ||
|
||||
!ufshcd_keyslot_valid(hba, slot) ||
|
||||
!ufshcd_cap_idx_valid(hba, cap_idx))
|
||||
return -EINVAL;
|
||||
|
||||
data_unit_mask = get_data_unit_size_mask(data_unit_size);
|
||||
|
||||
if (!(data_unit_mask & hba->crypto_cap_array[cap_idx].sdus_mask))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.data_unit_size = data_unit_mask;
|
||||
cfg.crypto_cap_idx = cap_idx;
|
||||
cfg.config_enable |= UFS_CRYPTO_CONFIGURATION_ENABLE;
|
||||
|
||||
err = ufshcd_crypto_cfg_entry_write_key(&cfg, key,
|
||||
hba->crypto_cap_array[cap_idx]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
program_key(hba, &cfg, slot);
|
||||
|
||||
memcpy(&cfg_arr[slot], &cfg, sizeof(cfg));
|
||||
memzero_explicit(&cfg, sizeof(cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufshcd_crypto_keyslot_find(void *hba_p,
|
||||
const u8 *key,
|
||||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int data_unit_size)
|
||||
{
|
||||
struct ufs_hba *hba = hba_p;
|
||||
int err = 0;
|
||||
int slot;
|
||||
u8 data_unit_mask;
|
||||
union ufs_crypto_cfg_entry cfg;
|
||||
union ufs_crypto_cfg_entry *cfg_arr = hba->crypto_cfgs;
|
||||
int cap_idx;
|
||||
|
||||
cap_idx = ufshcd_crypto_cap_find(hba_p, crypto_mode,
|
||||
data_unit_size);
|
||||
|
||||
if (!ufshcd_is_crypto_enabled(hba) ||
|
||||
!ufshcd_cap_idx_valid(hba, cap_idx))
|
||||
return -EINVAL;
|
||||
|
||||
data_unit_mask = get_data_unit_size_mask(data_unit_size);
|
||||
|
||||
if (!(data_unit_mask & hba->crypto_cap_array[cap_idx].sdus_mask))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
err = ufshcd_crypto_cfg_entry_write_key(&cfg, key,
|
||||
hba->crypto_cap_array[cap_idx]);
|
||||
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
for (slot = 0; slot < NUM_KEYSLOTS(hba); slot++) {
|
||||
if ((cfg_arr[slot].config_enable &
|
||||
UFS_CRYPTO_CONFIGURATION_ENABLE) &&
|
||||
data_unit_mask == cfg_arr[slot].data_unit_size &&
|
||||
cap_idx == cfg_arr[slot].crypto_cap_idx &&
|
||||
!crypto_memneq(&cfg.crypto_key, cfg_arr[slot].crypto_key,
|
||||
UFS_CRYPTO_KEY_MAX_SIZE)) {
|
||||
memzero_explicit(&cfg, sizeof(cfg));
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
memzero_explicit(&cfg, sizeof(cfg));
|
||||
return -ENOKEY;
|
||||
}
|
||||
|
||||
static int ufshcd_crypto_keyslot_evict(void *hba_p, const u8 *key,
|
||||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int data_unit_size,
|
||||
unsigned int slot)
|
||||
{
|
||||
struct ufs_hba *hba = hba_p;
|
||||
int i = 0;
|
||||
u32 reg_base;
|
||||
union ufs_crypto_cfg_entry *cfg_arr = hba->crypto_cfgs;
|
||||
|
||||
if (!ufshcd_is_crypto_enabled(hba) ||
|
||||
!ufshcd_keyslot_valid(hba, slot))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cfg_arr[slot], 0, sizeof(cfg_arr[slot]));
|
||||
reg_base = hba->crypto_cfg_register + slot * sizeof(cfg_arr[0]);
|
||||
|
||||
/*
|
||||
* Clear the crypto cfg on the device. Clearing CFGE
|
||||
* might not be sufficient, so just clear the entire cfg.
|
||||
*/
|
||||
for (i = 0; i < sizeof(cfg_arr[0]); i += sizeof(__le32))
|
||||
ufshcd_writel(hba, 0, reg_base + i);
|
||||
wmb();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ufshcd_crypto_mode_supported(void *hba_p,
|
||||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int data_unit_size)
|
||||
{
|
||||
return ufshcd_crypto_cap_find(hba_p, crypto_mode, data_unit_size) >= 0;
|
||||
}
|
||||
|
||||
void ufshcd_crypto_enable(struct ufs_hba *hba)
|
||||
{
|
||||
union ufs_crypto_cfg_entry *cfg_arr = hba->crypto_cfgs;
|
||||
int slot;
|
||||
|
||||
if (!ufshcd_hba_is_crypto_supported(hba))
|
||||
return;
|
||||
|
||||
hba->caps |= UFSHCD_CAP_CRYPTO;
|
||||
/*
|
||||
* Reset might clear all keys, so reprogram all the keys.
|
||||
* Also serves to clear keys on driver init.
|
||||
*/
|
||||
for (slot = 0; slot < NUM_KEYSLOTS(hba); slot++)
|
||||
program_key(hba, &cfg_arr[slot], slot);
|
||||
}
|
||||
|
||||
void ufshcd_crypto_disable(struct ufs_hba *hba)
|
||||
{
|
||||
hba->caps &= ~UFSHCD_CAP_CRYPTO;
|
||||
}
|
||||
|
||||
static const struct keyslot_mgmt_ll_ops ufshcd_ksm_ops = {
|
||||
.keyslot_program = ufshcd_crypto_keyslot_program,
|
||||
.keyslot_evict = ufshcd_crypto_keyslot_evict,
|
||||
.keyslot_find = ufshcd_crypto_keyslot_find,
|
||||
.crypto_mode_supported = ufshcd_crypto_mode_supported,
|
||||
};
|
||||
|
||||
/**
|
||||
* ufshcd_hba_init_crypto - Read crypto capabilities, init crypto fields in hba
|
||||
* @hba: Per adapter instance
|
||||
*
|
||||
* Returns 0 on success. Returns -ENODEV if such capabilities don't exist, and
|
||||
* -ENOMEM upon OOM.
|
||||
*/
|
||||
int ufshcd_hba_init_crypto(struct ufs_hba *hba)
|
||||
{
|
||||
int cap_idx = 0;
|
||||
int err = 0;
|
||||
|
||||
/* Default to disabling crypto */
|
||||
hba->caps &= ~UFSHCD_CAP_CRYPTO;
|
||||
|
||||
if (!(hba->capabilities & MASK_CRYPTO_SUPPORT)) {
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Crypto Capabilities should never be 0, because the
|
||||
* config_array_ptr > 04h. So we use a 0 value to indicate that
|
||||
* crypto init failed, and can't be enabled.
|
||||
*/
|
||||
hba->crypto_capabilities.reg_val =
|
||||
cpu_to_le32(ufshcd_readl(hba, REG_UFS_CCAP));
|
||||
hba->crypto_cfg_register =
|
||||
(u32)hba->crypto_capabilities.config_array_ptr * 0x100;
|
||||
hba->crypto_cap_array =
|
||||
devm_kcalloc(hba->dev,
|
||||
hba->crypto_capabilities.num_crypto_cap,
|
||||
sizeof(hba->crypto_cap_array[0]),
|
||||
GFP_KERNEL);
|
||||
if (!hba->crypto_cap_array) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hba->crypto_cfgs =
|
||||
devm_kcalloc(hba->dev,
|
||||
NUM_KEYSLOTS(hba),
|
||||
sizeof(hba->crypto_cfgs[0]),
|
||||
GFP_KERNEL);
|
||||
if (!hba->crypto_cfgs) {
|
||||
err = -ENOMEM;
|
||||
goto out_free_cfg_mem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store all the capabilities now so that we don't need to repeatedly
|
||||
* access the device each time we want to know its capabilities
|
||||
*/
|
||||
for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap;
|
||||
cap_idx++) {
|
||||
hba->crypto_cap_array[cap_idx].reg_val =
|
||||
cpu_to_le32(ufshcd_readl(hba,
|
||||
REG_UFS_CRYPTOCAP +
|
||||
cap_idx * sizeof(__le32)));
|
||||
}
|
||||
|
||||
hba->ksm = keyslot_manager_create(NUM_KEYSLOTS(hba), &ufshcd_ksm_ops,
|
||||
hba);
|
||||
|
||||
if (!hba->ksm) {
|
||||
err = -ENOMEM;
|
||||
goto out_free_crypto_cfgs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_free_crypto_cfgs:
|
||||
devm_kfree(hba->dev, hba->crypto_cfgs);
|
||||
out_free_cfg_mem:
|
||||
devm_kfree(hba->dev, hba->crypto_cap_array);
|
||||
out:
|
||||
// TODO: print error?
|
||||
/* Indicate that init failed by setting crypto_capabilities to 0 */
|
||||
hba->crypto_capabilities.reg_val = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
void ufshcd_crypto_setup_rq_keyslot_manager(struct ufs_hba *hba,
|
||||
struct request_queue *q)
|
||||
{
|
||||
if (!ufshcd_hba_is_crypto_supported(hba) || !q)
|
||||
return;
|
||||
|
||||
q->ksm = hba->ksm;
|
||||
}
|
||||
|
||||
void ufshcd_crypto_destroy_rq_keyslot_manager(struct ufs_hba *hba,
|
||||
struct request_queue *q)
|
||||
{
|
||||
keyslot_manager_destroy(hba->ksm);
|
||||
}
|
86
drivers/scsi/ufs/ufshcd-crypto.h
Normal file
86
drivers/scsi/ufs/ufshcd-crypto.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
||||
#ifndef _UFSHCD_CRYPTO_H
|
||||
#define _UFSHCD_CRYPTO_H
|
||||
|
||||
struct ufs_hba;
|
||||
|
||||
#ifdef CONFIG_SCSI_UFS_CRYPTO
|
||||
#include <linux/keyslot-manager.h>
|
||||
|
||||
#include "ufshci.h"
|
||||
|
||||
#define NUM_KEYSLOTS(hba) (hba->crypto_capabilities.config_count + 1)
|
||||
|
||||
static inline bool ufshcd_keyslot_valid(struct ufs_hba *hba, unsigned int slot)
|
||||
{
|
||||
/*
|
||||
* The actual number of configurations supported is (CFGC+1), so slot
|
||||
* numbers range from 0 to config_count inclusive.
|
||||
*/
|
||||
return slot < NUM_KEYSLOTS(hba);
|
||||
}
|
||||
|
||||
static inline bool ufshcd_hba_is_crypto_supported(struct ufs_hba *hba)
|
||||
{
|
||||
return hba->crypto_capabilities.reg_val != 0;
|
||||
}
|
||||
|
||||
static inline bool ufshcd_is_crypto_enabled(struct ufs_hba *hba)
|
||||
{
|
||||
return hba->caps & UFSHCD_CAP_CRYPTO;
|
||||
}
|
||||
|
||||
void ufshcd_crypto_enable(struct ufs_hba *hba);
|
||||
|
||||
void ufshcd_crypto_disable(struct ufs_hba *hba);
|
||||
|
||||
int ufshcd_hba_init_crypto(struct ufs_hba *hba);
|
||||
|
||||
void ufshcd_crypto_setup_rq_keyslot_manager(struct ufs_hba *hba,
|
||||
struct request_queue *q);
|
||||
|
||||
void ufshcd_crypto_destroy_rq_keyslot_manager(struct ufs_hba *hba,
|
||||
struct request_queue *q);
|
||||
|
||||
#else /* CONFIG_SCSI_UFS_CRYPTO */
|
||||
|
||||
static inline bool ufshcd_keyslot_valid(struct ufs_hba *hba,
|
||||
unsigned int slot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool ufshcd_hba_is_crypto_supported(struct ufs_hba *hba)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool ufshcd_is_crypto_enabled(struct ufs_hba *hba)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void ufshcd_crypto_enable(struct ufs_hba *hba) { }
|
||||
|
||||
static inline void ufshcd_crypto_disable(struct ufs_hba *hba) { }
|
||||
|
||||
static inline int ufshcd_hba_init_crypto(struct ufs_hba *hba)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ufshcd_crypto_setup_rq_keyslot_manager(
|
||||
struct ufs_hba *hba,
|
||||
struct request_queue *q) { }
|
||||
|
||||
static inline void ufshcd_crypto_destroy_rq_keyslot_manager(
|
||||
struct ufs_hba *hba,
|
||||
struct request_queue *q) { }
|
||||
|
||||
#endif /* CONFIG_SCSI_UFS_CRYPTO */
|
||||
|
||||
#endif /* _UFSHCD_CRYPTO_H */
|
|
@ -501,6 +501,11 @@ struct ufs_stats {
|
|||
* @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for
|
||||
* device is known or not.
|
||||
* @scsi_block_reqs_cnt: reference counting for scsi block requests
|
||||
* @crypto_capabilities: Content of crypto capabilities register (0x100)
|
||||
* @crypto_cap_array: Array of crypto capabilities
|
||||
* @crypto_cfg_register: Start of the crypto cfg array
|
||||
* @crypto_cfgs: Array of crypto configurations (i.e. config for each slot)
|
||||
* @ksm: the keyslot manager tied to this hba
|
||||
*/
|
||||
struct ufs_hba {
|
||||
void __iomem *mmio_base;
|
||||
|
@ -713,6 +718,15 @@ struct ufs_hba {
|
|||
struct rw_semaphore clk_scaling_lock;
|
||||
struct ufs_desc_size desc_size;
|
||||
atomic_t scsi_block_reqs_cnt;
|
||||
|
||||
#ifdef CONFIG_SCSI_UFS_CRYPTO
|
||||
/* crypto */
|
||||
union ufs_crypto_capabilities crypto_capabilities;
|
||||
union ufs_crypto_cap_entry *crypto_cap_array;
|
||||
u32 crypto_cfg_register;
|
||||
union ufs_crypto_cfg_entry *crypto_cfgs;
|
||||
struct keyslot_manager *ksm;
|
||||
#endif /* CONFIG_SCSI_UFS_CRYPTO */
|
||||
};
|
||||
|
||||
/* Returns true if clocks can be gated. Otherwise false */
|
||||
|
|
Loading…
Add table
Reference in a new issue