Commit | Line | Data |
---|---|---|
70297a8a ST |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright 2019 Google LLC | |
4 | */ | |
5 | ||
6 | #include "ufshcd.h" | |
7 | #include "ufshcd-crypto.h" | |
8 | ||
9 | /* Blk-crypto modes supported by UFS crypto */ | |
10 | static const struct ufs_crypto_alg_entry { | |
11 | enum ufs_crypto_alg ufs_alg; | |
12 | enum ufs_crypto_key_size ufs_key_size; | |
13 | } ufs_crypto_algs[BLK_ENCRYPTION_MODE_MAX] = { | |
14 | [BLK_ENCRYPTION_MODE_AES_256_XTS] = { | |
15 | .ufs_alg = UFS_CRYPTO_ALG_AES_XTS, | |
16 | .ufs_key_size = UFS_CRYPTO_KEY_SIZE_256, | |
17 | }, | |
18 | }; | |
19 | ||
1bc726e2 EB |
20 | static int ufshcd_program_key(struct ufs_hba *hba, |
21 | const union ufs_crypto_cfg_entry *cfg, int slot) | |
70297a8a ST |
22 | { |
23 | int i; | |
24 | u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg); | |
1bc726e2 | 25 | int err = 0; |
70297a8a ST |
26 | |
27 | ufshcd_hold(hba, false); | |
1bc726e2 EB |
28 | |
29 | if (hba->vops && hba->vops->program_key) { | |
30 | err = hba->vops->program_key(hba, cfg, slot); | |
31 | goto out; | |
32 | } | |
33 | ||
70297a8a ST |
34 | /* Ensure that CFGE is cleared before programming the key */ |
35 | ufshcd_writel(hba, 0, slot_offset + 16 * sizeof(cfg->reg_val[0])); | |
36 | for (i = 0; i < 16; i++) { | |
37 | ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[i]), | |
38 | slot_offset + i * sizeof(cfg->reg_val[0])); | |
39 | } | |
40 | /* Write dword 17 */ | |
41 | ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[17]), | |
42 | slot_offset + 17 * sizeof(cfg->reg_val[0])); | |
43 | /* Dword 16 must be written last */ | |
44 | ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[16]), | |
45 | slot_offset + 16 * sizeof(cfg->reg_val[0])); | |
1bc726e2 | 46 | out: |
70297a8a | 47 | ufshcd_release(hba); |
1bc726e2 | 48 | return err; |
70297a8a ST |
49 | } |
50 | ||
51 | static int ufshcd_crypto_keyslot_program(struct blk_keyslot_manager *ksm, | |
52 | const struct blk_crypto_key *key, | |
53 | unsigned int slot) | |
54 | { | |
55 | struct ufs_hba *hba = container_of(ksm, struct ufs_hba, ksm); | |
56 | const union ufs_crypto_cap_entry *ccap_array = hba->crypto_cap_array; | |
57 | const struct ufs_crypto_alg_entry *alg = | |
58 | &ufs_crypto_algs[key->crypto_cfg.crypto_mode]; | |
59 | u8 data_unit_mask = key->crypto_cfg.data_unit_size / 512; | |
60 | int i; | |
61 | int cap_idx = -1; | |
6500251e | 62 | union ufs_crypto_cfg_entry cfg = {}; |
1bc726e2 | 63 | int err; |
70297a8a ST |
64 | |
65 | BUILD_BUG_ON(UFS_CRYPTO_KEY_SIZE_INVALID != 0); | |
66 | for (i = 0; i < hba->crypto_capabilities.num_crypto_cap; i++) { | |
67 | if (ccap_array[i].algorithm_id == alg->ufs_alg && | |
68 | ccap_array[i].key_size == alg->ufs_key_size && | |
69 | (ccap_array[i].sdus_mask & data_unit_mask)) { | |
70 | cap_idx = i; | |
71 | break; | |
72 | } | |
73 | } | |
74 | ||
75 | if (WARN_ON(cap_idx < 0)) | |
76 | return -EOPNOTSUPP; | |
77 | ||
78 | cfg.data_unit_size = data_unit_mask; | |
79 | cfg.crypto_cap_idx = cap_idx; | |
80 | cfg.config_enable = UFS_CRYPTO_CONFIGURATION_ENABLE; | |
81 | ||
82 | if (ccap_array[cap_idx].algorithm_id == UFS_CRYPTO_ALG_AES_XTS) { | |
83 | /* In XTS mode, the blk_crypto_key's size is already doubled */ | |
84 | memcpy(cfg.crypto_key, key->raw, key->size/2); | |
85 | memcpy(cfg.crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2, | |
86 | key->raw + key->size/2, key->size/2); | |
87 | } else { | |
88 | memcpy(cfg.crypto_key, key->raw, key->size); | |
89 | } | |
90 | ||
1bc726e2 | 91 | err = ufshcd_program_key(hba, &cfg, slot); |
70297a8a ST |
92 | |
93 | memzero_explicit(&cfg, sizeof(cfg)); | |
1bc726e2 | 94 | return err; |
70297a8a ST |
95 | } |
96 | ||
1bc726e2 | 97 | static int ufshcd_clear_keyslot(struct ufs_hba *hba, int slot) |
70297a8a ST |
98 | { |
99 | /* | |
100 | * Clear the crypto cfg on the device. Clearing CFGE | |
101 | * might not be sufficient, so just clear the entire cfg. | |
102 | */ | |
6500251e | 103 | union ufs_crypto_cfg_entry cfg = {}; |
70297a8a | 104 | |
1bc726e2 | 105 | return ufshcd_program_key(hba, &cfg, slot); |
70297a8a ST |
106 | } |
107 | ||
108 | static int ufshcd_crypto_keyslot_evict(struct blk_keyslot_manager *ksm, | |
109 | const struct blk_crypto_key *key, | |
110 | unsigned int slot) | |
111 | { | |
112 | struct ufs_hba *hba = container_of(ksm, struct ufs_hba, ksm); | |
113 | ||
1bc726e2 | 114 | return ufshcd_clear_keyslot(hba, slot); |
70297a8a ST |
115 | } |
116 | ||
117 | bool ufshcd_crypto_enable(struct ufs_hba *hba) | |
118 | { | |
119 | if (!(hba->caps & UFSHCD_CAP_CRYPTO)) | |
120 | return false; | |
121 | ||
122 | /* Reset might clear all keys, so reprogram all the keys. */ | |
123 | blk_ksm_reprogram_all_keys(&hba->ksm); | |
124 | return true; | |
125 | } | |
126 | ||
127 | static const struct blk_ksm_ll_ops ufshcd_ksm_ops = { | |
128 | .keyslot_program = ufshcd_crypto_keyslot_program, | |
129 | .keyslot_evict = ufshcd_crypto_keyslot_evict, | |
130 | }; | |
131 | ||
132 | static enum blk_crypto_mode_num | |
133 | ufshcd_find_blk_crypto_mode(union ufs_crypto_cap_entry cap) | |
134 | { | |
135 | int i; | |
136 | ||
137 | for (i = 0; i < ARRAY_SIZE(ufs_crypto_algs); i++) { | |
138 | BUILD_BUG_ON(UFS_CRYPTO_KEY_SIZE_INVALID != 0); | |
139 | if (ufs_crypto_algs[i].ufs_alg == cap.algorithm_id && | |
140 | ufs_crypto_algs[i].ufs_key_size == cap.key_size) { | |
141 | return i; | |
142 | } | |
143 | } | |
144 | return BLK_ENCRYPTION_MODE_INVALID; | |
145 | } | |
146 | ||
147 | /** | |
148 | * ufshcd_hba_init_crypto_capabilities - Read crypto capabilities, init crypto | |
149 | * fields in hba | |
150 | * @hba: Per adapter instance | |
151 | * | |
152 | * Return: 0 if crypto was initialized or is not supported, else a -errno value. | |
153 | */ | |
154 | int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba) | |
155 | { | |
156 | int cap_idx; | |
157 | int err = 0; | |
158 | enum blk_crypto_mode_num blk_mode_num; | |
159 | ||
160 | /* | |
161 | * Don't use crypto if either the hardware doesn't advertise the | |
162 | * standard crypto capability bit *or* if the vendor specific driver | |
163 | * hasn't advertised that crypto is supported. | |
164 | */ | |
165 | if (!(hba->capabilities & MASK_CRYPTO_SUPPORT) || | |
166 | !(hba->caps & UFSHCD_CAP_CRYPTO)) | |
167 | goto out; | |
168 | ||
169 | hba->crypto_capabilities.reg_val = | |
170 | cpu_to_le32(ufshcd_readl(hba, REG_UFS_CCAP)); | |
171 | hba->crypto_cfg_register = | |
172 | (u32)hba->crypto_capabilities.config_array_ptr * 0x100; | |
173 | hba->crypto_cap_array = | |
174 | devm_kcalloc(hba->dev, hba->crypto_capabilities.num_crypto_cap, | |
175 | sizeof(hba->crypto_cap_array[0]), GFP_KERNEL); | |
176 | if (!hba->crypto_cap_array) { | |
177 | err = -ENOMEM; | |
178 | goto out; | |
179 | } | |
180 | ||
181 | /* The actual number of configurations supported is (CFGC+1) */ | |
d76d9d7d EB |
182 | err = devm_blk_ksm_init(hba->dev, &hba->ksm, |
183 | hba->crypto_capabilities.config_count + 1); | |
70297a8a ST |
184 | if (err) |
185 | goto out_free_caps; | |
186 | ||
187 | hba->ksm.ksm_ll_ops = ufshcd_ksm_ops; | |
188 | /* UFS only supports 8 bytes for any DUN */ | |
189 | hba->ksm.max_dun_bytes_supported = 8; | |
190 | hba->ksm.dev = hba->dev; | |
191 | ||
192 | /* | |
193 | * Cache all the UFS crypto capabilities and advertise the supported | |
194 | * crypto modes and data unit sizes to the block layer. | |
195 | */ | |
196 | for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap; | |
197 | cap_idx++) { | |
198 | hba->crypto_cap_array[cap_idx].reg_val = | |
199 | cpu_to_le32(ufshcd_readl(hba, | |
200 | REG_UFS_CRYPTOCAP + | |
201 | cap_idx * sizeof(__le32))); | |
202 | blk_mode_num = ufshcd_find_blk_crypto_mode( | |
203 | hba->crypto_cap_array[cap_idx]); | |
204 | if (blk_mode_num != BLK_ENCRYPTION_MODE_INVALID) | |
205 | hba->ksm.crypto_modes_supported[blk_mode_num] |= | |
206 | hba->crypto_cap_array[cap_idx].sdus_mask * 512; | |
207 | } | |
208 | ||
209 | return 0; | |
210 | ||
211 | out_free_caps: | |
212 | devm_kfree(hba->dev, hba->crypto_cap_array); | |
213 | out: | |
214 | /* Indicate that init failed by clearing UFSHCD_CAP_CRYPTO */ | |
215 | hba->caps &= ~UFSHCD_CAP_CRYPTO; | |
216 | return err; | |
217 | } | |
218 | ||
219 | /** | |
220 | * ufshcd_init_crypto - Initialize crypto hardware | |
221 | * @hba: Per adapter instance | |
222 | */ | |
223 | void ufshcd_init_crypto(struct ufs_hba *hba) | |
224 | { | |
225 | int slot; | |
226 | ||
227 | if (!(hba->caps & UFSHCD_CAP_CRYPTO)) | |
228 | return; | |
229 | ||
230 | /* Clear all keyslots - the number of keyslots is (CFGC + 1) */ | |
231 | for (slot = 0; slot < hba->crypto_capabilities.config_count + 1; slot++) | |
232 | ufshcd_clear_keyslot(hba, slot); | |
233 | } | |
234 | ||
235 | void ufshcd_crypto_setup_rq_keyslot_manager(struct ufs_hba *hba, | |
236 | struct request_queue *q) | |
237 | { | |
238 | if (hba->caps & UFSHCD_CAP_CRYPTO) | |
239 | blk_ksm_register(&hba->ksm, q); | |
240 | } |