]>
Commit | Line | Data |
---|---|---|
ac052d8c SS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * AMD Platform Management Framework Driver - TEE Interface | |
4 | * | |
5 | * Copyright (c) 2023, Advanced Micro Devices, Inc. | |
6 | * All Rights Reserved. | |
7 | * | |
8 | * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> | |
9 | */ | |
10 | ||
10817f28 | 11 | #include <linux/debugfs.h> |
ac052d8c SS |
12 | #include <linux/tee_drv.h> |
13 | #include <linux/uuid.h> | |
14 | #include "pmf.h" | |
15 | ||
16 | #define MAX_TEE_PARAM 4 | |
ae82cef7 SS |
17 | |
18 | /* Policy binary actions sampling frequency (in ms) */ | |
19 | static int pb_actions_ms = MSEC_PER_SEC; | |
10817f28 SS |
20 | /* Sideload policy binaries to debug policy failures */ |
21 | static bool pb_side_load; | |
22 | ||
ae82cef7 SS |
23 | #ifdef CONFIG_AMD_PMF_DEBUG |
24 | module_param(pb_actions_ms, int, 0644); | |
25 | MODULE_PARM_DESC(pb_actions_ms, "Policy binary actions sampling frequency (default = 1000ms)"); | |
10817f28 SS |
26 | module_param(pb_side_load, bool, 0444); |
27 | MODULE_PARM_DESC(pb_side_load, "Sideload policy binaries debug policy failures"); | |
ae82cef7 SS |
28 | #endif |
29 | ||
ac052d8c SS |
30 | static const uuid_t amd_pmf_ta_uuid = UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d, |
31 | 0xb1, 0x2d, 0xc5, 0x29, 0xb1, 0x3d, 0x85, 0x43); | |
32 | ||
d0ba7ad4 SS |
33 | static const char *amd_pmf_uevent_as_str(unsigned int state) |
34 | { | |
35 | switch (state) { | |
36 | case SYSTEM_STATE_S0i3: | |
37 | return "S0i3"; | |
38 | case SYSTEM_STATE_S4: | |
39 | return "S4"; | |
40 | case SYSTEM_STATE_SCREEN_LOCK: | |
41 | return "SCREEN_LOCK"; | |
42 | default: | |
43 | return "Unknown Smart PC event"; | |
44 | } | |
45 | } | |
46 | ||
ae82cef7 SS |
47 | static void amd_pmf_prepare_args(struct amd_pmf_dev *dev, int cmd, |
48 | struct tee_ioctl_invoke_arg *arg, | |
49 | struct tee_param *param) | |
50 | { | |
51 | memset(arg, 0, sizeof(*arg)); | |
52 | memset(param, 0, MAX_TEE_PARAM * sizeof(*param)); | |
53 | ||
54 | arg->func = cmd; | |
55 | arg->session = dev->session_id; | |
56 | arg->num_params = MAX_TEE_PARAM; | |
57 | ||
58 | /* Fill invoke cmd params */ | |
59 | param[0].u.memref.size = sizeof(struct ta_pmf_shared_memory); | |
60 | param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; | |
61 | param[0].u.memref.shm = dev->fw_shm_pool; | |
62 | param[0].u.memref.shm_offs = 0; | |
63 | } | |
64 | ||
d0ba7ad4 SS |
65 | static int amd_pmf_update_uevents(struct amd_pmf_dev *dev, u16 event) |
66 | { | |
67 | char *envp[2] = {}; | |
68 | ||
69 | envp[0] = kasprintf(GFP_KERNEL, "EVENT_ID=%d", event); | |
70 | if (!envp[0]) | |
71 | return -EINVAL; | |
72 | ||
73 | kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, envp); | |
74 | ||
75 | kfree(envp[0]); | |
76 | return 0; | |
77 | } | |
78 | ||
7c45534a SS |
79 | static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out) |
80 | { | |
81 | u32 val; | |
82 | int idx; | |
83 | ||
84 | for (idx = 0; idx < out->actions_count; idx++) { | |
85 | val = out->actions_list[idx].value; | |
86 | switch (out->actions_list[idx].action_index) { | |
87 | case PMF_POLICY_SPL: | |
88 | if (dev->prev_data->spl != val) { | |
89 | amd_pmf_send_cmd(dev, SET_SPL, false, val, NULL); | |
90 | dev_dbg(dev->dev, "update SPL: %u\n", val); | |
91 | dev->prev_data->spl = val; | |
92 | } | |
93 | break; | |
94 | ||
95 | case PMF_POLICY_SPPT: | |
96 | if (dev->prev_data->sppt != val) { | |
97 | amd_pmf_send_cmd(dev, SET_SPPT, false, val, NULL); | |
98 | dev_dbg(dev->dev, "update SPPT: %u\n", val); | |
99 | dev->prev_data->sppt = val; | |
100 | } | |
101 | break; | |
102 | ||
103 | case PMF_POLICY_FPPT: | |
104 | if (dev->prev_data->fppt != val) { | |
105 | amd_pmf_send_cmd(dev, SET_FPPT, false, val, NULL); | |
106 | dev_dbg(dev->dev, "update FPPT: %u\n", val); | |
107 | dev->prev_data->fppt = val; | |
108 | } | |
109 | break; | |
110 | ||
111 | case PMF_POLICY_SPPT_APU_ONLY: | |
112 | if (dev->prev_data->sppt_apuonly != val) { | |
113 | amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, val, NULL); | |
114 | dev_dbg(dev->dev, "update SPPT_APU_ONLY: %u\n", val); | |
115 | dev->prev_data->sppt_apuonly = val; | |
116 | } | |
117 | break; | |
118 | ||
119 | case PMF_POLICY_STT_MIN: | |
120 | if (dev->prev_data->stt_minlimit != val) { | |
121 | amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, val, NULL); | |
122 | dev_dbg(dev->dev, "update STT_MIN: %u\n", val); | |
123 | dev->prev_data->stt_minlimit = val; | |
124 | } | |
125 | break; | |
126 | ||
127 | case PMF_POLICY_STT_SKINTEMP_APU: | |
128 | if (dev->prev_data->stt_skintemp_apu != val) { | |
129 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, val, NULL); | |
130 | dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val); | |
131 | dev->prev_data->stt_skintemp_apu = val; | |
132 | } | |
133 | break; | |
134 | ||
135 | case PMF_POLICY_STT_SKINTEMP_HS2: | |
136 | if (dev->prev_data->stt_skintemp_hs2 != val) { | |
137 | amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, val, NULL); | |
138 | dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val); | |
139 | dev->prev_data->stt_skintemp_hs2 = val; | |
140 | } | |
141 | break; | |
c3b40930 SS |
142 | |
143 | case PMF_POLICY_P3T: | |
144 | if (dev->prev_data->p3t_limit != val) { | |
145 | amd_pmf_send_cmd(dev, SET_P3T, false, val, NULL); | |
146 | dev_dbg(dev->dev, "update P3T: %u\n", val); | |
147 | dev->prev_data->p3t_limit = val; | |
148 | } | |
149 | break; | |
d0ba7ad4 SS |
150 | |
151 | case PMF_POLICY_SYSTEM_STATE: | |
152 | amd_pmf_update_uevents(dev, val); | |
153 | dev_dbg(dev->dev, "update SYSTEM_STATE: %s\n", | |
154 | amd_pmf_uevent_as_str(val)); | |
155 | break; | |
7c45534a SS |
156 | } |
157 | } | |
158 | } | |
159 | ||
ae82cef7 SS |
160 | static int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev) |
161 | { | |
162 | struct ta_pmf_shared_memory *ta_sm = NULL; | |
7c45534a | 163 | struct ta_pmf_enact_result *out = NULL; |
f4627dfd | 164 | struct ta_pmf_enact_table *in = NULL; |
ae82cef7 SS |
165 | struct tee_param param[MAX_TEE_PARAM]; |
166 | struct tee_ioctl_invoke_arg arg; | |
167 | int ret = 0; | |
168 | ||
169 | if (!dev->tee_ctx) | |
170 | return -ENODEV; | |
171 | ||
7c45534a | 172 | memset(dev->shbuf, 0, dev->policy_sz); |
ae82cef7 | 173 | ta_sm = dev->shbuf; |
7c45534a | 174 | out = &ta_sm->pmf_output.policy_apply_table; |
f4627dfd | 175 | in = &ta_sm->pmf_input.enact_table; |
7c45534a | 176 | |
ae82cef7 SS |
177 | memset(ta_sm, 0, sizeof(*ta_sm)); |
178 | ta_sm->command_id = TA_PMF_COMMAND_POLICY_BUILDER_ENACT_POLICIES; | |
179 | ta_sm->if_version = PMF_TA_IF_VERSION_MAJOR; | |
180 | ||
f4627dfd | 181 | amd_pmf_populate_ta_inputs(dev, in); |
ae82cef7 SS |
182 | amd_pmf_prepare_args(dev, TA_PMF_COMMAND_POLICY_BUILDER_ENACT_POLICIES, &arg, param); |
183 | ||
184 | ret = tee_client_invoke_func(dev->tee_ctx, &arg, param); | |
185 | if (ret < 0 || arg.ret != 0) { | |
186 | dev_err(dev->dev, "TEE enact cmd failed. err: %x, ret:%d\n", arg.ret, ret); | |
187 | return ret; | |
188 | } | |
189 | ||
7c45534a | 190 | if (ta_sm->pmf_result == TA_PMF_TYPE_SUCCESS && out->actions_count) { |
69e76c5a | 191 | amd_pmf_dump_ta_inputs(dev, in); |
7c45534a SS |
192 | dev_dbg(dev->dev, "action count:%u result:%x\n", out->actions_count, |
193 | ta_sm->pmf_result); | |
194 | amd_pmf_apply_policies(dev, out); | |
195 | } | |
196 | ||
ae82cef7 SS |
197 | return 0; |
198 | } | |
199 | ||
200 | static int amd_pmf_invoke_cmd_init(struct amd_pmf_dev *dev) | |
201 | { | |
202 | struct ta_pmf_shared_memory *ta_sm = NULL; | |
203 | struct tee_param param[MAX_TEE_PARAM]; | |
7c45534a | 204 | struct ta_pmf_init_table *in = NULL; |
ae82cef7 SS |
205 | struct tee_ioctl_invoke_arg arg; |
206 | int ret = 0; | |
207 | ||
208 | if (!dev->tee_ctx) { | |
209 | dev_err(dev->dev, "Failed to get TEE context\n"); | |
210 | return -ENODEV; | |
211 | } | |
212 | ||
7c45534a SS |
213 | dev_dbg(dev->dev, "Policy Binary size: %u bytes\n", dev->policy_sz); |
214 | memset(dev->shbuf, 0, dev->policy_sz); | |
ae82cef7 | 215 | ta_sm = dev->shbuf; |
7c45534a SS |
216 | in = &ta_sm->pmf_input.init_table; |
217 | ||
ae82cef7 SS |
218 | ta_sm->command_id = TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE; |
219 | ta_sm->if_version = PMF_TA_IF_VERSION_MAJOR; | |
220 | ||
7c45534a SS |
221 | in->metadata_macrocheck = false; |
222 | in->sku_check = false; | |
223 | in->validate = true; | |
224 | in->frequency = pb_actions_ms; | |
225 | in->policies_table.table_size = dev->policy_sz; | |
226 | ||
227 | memcpy(in->policies_table.table, dev->policy_buf, dev->policy_sz); | |
ae82cef7 SS |
228 | amd_pmf_prepare_args(dev, TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE, &arg, param); |
229 | ||
230 | ret = tee_client_invoke_func(dev->tee_ctx, &arg, param); | |
231 | if (ret < 0 || arg.ret != 0) { | |
232 | dev_err(dev->dev, "Failed to invoke TEE init cmd. err: %x, ret:%d\n", arg.ret, ret); | |
233 | return ret; | |
234 | } | |
235 | ||
236 | return ta_sm->pmf_result; | |
237 | } | |
238 | ||
239 | static void amd_pmf_invoke_cmd(struct work_struct *work) | |
240 | { | |
241 | struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, pb_work.work); | |
242 | ||
243 | amd_pmf_invoke_cmd_enact(dev); | |
244 | schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms)); | |
245 | } | |
246 | ||
7c45534a SS |
247 | static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) |
248 | { | |
249 | u32 cookie, length; | |
250 | int res; | |
251 | ||
252 | cookie = readl(dev->policy_buf + POLICY_COOKIE_OFFSET); | |
253 | length = readl(dev->policy_buf + POLICY_COOKIE_LEN); | |
254 | ||
20545af3 ML |
255 | if (cookie != POLICY_SIGN_COOKIE || !length) { |
256 | dev_dbg(dev->dev, "cookie doesn't match\n"); | |
7c45534a | 257 | return -EINVAL; |
20545af3 | 258 | } |
7c45534a SS |
259 | |
260 | /* Update the actual length */ | |
261 | dev->policy_sz = length + 512; | |
262 | res = amd_pmf_invoke_cmd_init(dev); | |
263 | if (res == TA_PMF_TYPE_SUCCESS) { | |
264 | /* Now its safe to announce that smart pc is enabled */ | |
3da01394 | 265 | dev->smart_pc_enabled = true; |
7c45534a SS |
266 | /* |
267 | * Start collecting the data from TA FW after a small delay | |
268 | * or else, we might end up getting stale values. | |
269 | */ | |
270 | schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms * 3)); | |
271 | } else { | |
272 | dev_err(dev->dev, "ta invoke cmd init failed err: %x\n", res); | |
3da01394 | 273 | dev->smart_pc_enabled = false; |
7c45534a SS |
274 | return res; |
275 | } | |
276 | ||
277 | return 0; | |
278 | } | |
279 | ||
10817f28 | 280 | #ifdef CONFIG_AMD_PMF_DEBUG |
f533fa14 SS |
281 | static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev) |
282 | { | |
283 | print_hex_dump_debug("(pb): ", DUMP_PREFIX_OFFSET, 16, 1, dev->policy_buf, | |
284 | dev->policy_sz, false); | |
285 | } | |
286 | ||
10817f28 SS |
287 | static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf, |
288 | size_t length, loff_t *pos) | |
289 | { | |
290 | struct amd_pmf_dev *dev = filp->private_data; | |
291 | unsigned char *new_policy_buf; | |
292 | int ret; | |
293 | ||
294 | /* Policy binary size cannot exceed POLICY_BUF_MAX_SZ */ | |
295 | if (length > POLICY_BUF_MAX_SZ || length == 0) | |
296 | return -EINVAL; | |
297 | ||
298 | /* re-alloc to the new buffer length of the policy binary */ | |
299 | new_policy_buf = kzalloc(length, GFP_KERNEL); | |
300 | if (!new_policy_buf) | |
301 | return -ENOMEM; | |
302 | ||
a692a86e CL |
303 | if (copy_from_user(new_policy_buf, buf, length)) { |
304 | kfree(new_policy_buf); | |
10817f28 | 305 | return -EFAULT; |
a692a86e | 306 | } |
10817f28 SS |
307 | |
308 | kfree(dev->policy_buf); | |
309 | dev->policy_buf = new_policy_buf; | |
310 | dev->policy_sz = length; | |
311 | ||
f533fa14 | 312 | amd_pmf_hex_dump_pb(dev); |
10817f28 SS |
313 | ret = amd_pmf_start_policy_engine(dev); |
314 | if (ret) | |
315 | return -EINVAL; | |
316 | ||
317 | return length; | |
318 | } | |
319 | ||
320 | static const struct file_operations pb_fops = { | |
321 | .write = amd_pmf_get_pb_data, | |
322 | .open = simple_open, | |
323 | }; | |
324 | ||
325 | static void amd_pmf_open_pb(struct amd_pmf_dev *dev, struct dentry *debugfs_root) | |
326 | { | |
327 | dev->esbin = debugfs_create_dir("pb", debugfs_root); | |
328 | debugfs_create_file("update_policy", 0644, dev->esbin, dev, &pb_fops); | |
329 | } | |
330 | ||
331 | static void amd_pmf_remove_pb(struct amd_pmf_dev *dev) | |
332 | { | |
333 | debugfs_remove_recursive(dev->esbin); | |
334 | } | |
335 | #else | |
336 | static void amd_pmf_open_pb(struct amd_pmf_dev *dev, struct dentry *debugfs_root) {} | |
337 | static void amd_pmf_remove_pb(struct amd_pmf_dev *dev) {} | |
f533fa14 | 338 | static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev) {} |
10817f28 SS |
339 | #endif |
340 | ||
ac052d8c SS |
341 | static int amd_pmf_amdtee_ta_match(struct tee_ioctl_version_data *ver, const void *data) |
342 | { | |
343 | return ver->impl_id == TEE_IMPL_ID_AMDTEE; | |
344 | } | |
345 | ||
346 | static int amd_pmf_ta_open_session(struct tee_context *ctx, u32 *id) | |
347 | { | |
348 | struct tee_ioctl_open_session_arg sess_arg = {}; | |
349 | int rc; | |
350 | ||
351 | export_uuid(sess_arg.uuid, &amd_pmf_ta_uuid); | |
352 | sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; | |
353 | sess_arg.num_params = 0; | |
354 | ||
355 | rc = tee_client_open_session(ctx, &sess_arg, NULL); | |
356 | if (rc < 0 || sess_arg.ret != 0) { | |
357 | pr_err("Failed to open TEE session err:%#x, rc:%d\n", sess_arg.ret, rc); | |
358 | return rc; | |
359 | } | |
360 | ||
361 | *id = sess_arg.session; | |
362 | ||
363 | return rc; | |
364 | } | |
365 | ||
366 | static int amd_pmf_tee_init(struct amd_pmf_dev *dev) | |
367 | { | |
368 | u32 size; | |
369 | int ret; | |
370 | ||
371 | dev->tee_ctx = tee_client_open_context(NULL, amd_pmf_amdtee_ta_match, NULL, NULL); | |
372 | if (IS_ERR(dev->tee_ctx)) { | |
373 | dev_err(dev->dev, "Failed to open TEE context\n"); | |
374 | return PTR_ERR(dev->tee_ctx); | |
375 | } | |
376 | ||
377 | ret = amd_pmf_ta_open_session(dev->tee_ctx, &dev->session_id); | |
378 | if (ret) { | |
379 | dev_err(dev->dev, "Failed to open TA session (%d)\n", ret); | |
380 | ret = -EINVAL; | |
381 | goto out_ctx; | |
382 | } | |
383 | ||
7c45534a | 384 | size = sizeof(struct ta_pmf_shared_memory) + dev->policy_sz; |
ac052d8c SS |
385 | dev->fw_shm_pool = tee_shm_alloc_kernel_buf(dev->tee_ctx, size); |
386 | if (IS_ERR(dev->fw_shm_pool)) { | |
387 | dev_err(dev->dev, "Failed to alloc TEE shared memory\n"); | |
388 | ret = PTR_ERR(dev->fw_shm_pool); | |
389 | goto out_sess; | |
390 | } | |
391 | ||
392 | dev->shbuf = tee_shm_get_va(dev->fw_shm_pool, 0); | |
393 | if (IS_ERR(dev->shbuf)) { | |
394 | dev_err(dev->dev, "Failed to get TEE virtual address\n"); | |
395 | ret = PTR_ERR(dev->shbuf); | |
396 | goto out_shm; | |
397 | } | |
398 | dev_dbg(dev->dev, "TEE init done\n"); | |
399 | ||
400 | return 0; | |
401 | ||
402 | out_shm: | |
403 | tee_shm_free(dev->fw_shm_pool); | |
404 | out_sess: | |
405 | tee_client_close_session(dev->tee_ctx, dev->session_id); | |
406 | out_ctx: | |
407 | tee_client_close_context(dev->tee_ctx); | |
408 | ||
409 | return ret; | |
410 | } | |
411 | ||
412 | static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev) | |
413 | { | |
414 | tee_shm_free(dev->fw_shm_pool); | |
415 | tee_client_close_session(dev->tee_ctx, dev->session_id); | |
416 | tee_client_close_context(dev->tee_ctx); | |
417 | } | |
418 | ||
419 | int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) | |
420 | { | |
ae82cef7 SS |
421 | int ret; |
422 | ||
7c45534a SS |
423 | ret = apmf_check_smart_pc(dev); |
424 | if (ret) { | |
425 | /* | |
426 | * Lets not return from here if Smart PC bit is not advertised in | |
427 | * the BIOS. This way, there will be some amount of power savings | |
428 | * to the user with static slider (if enabled). | |
429 | */ | |
430 | dev_info(dev->dev, "PMF Smart PC not advertised in BIOS!:%d\n", ret); | |
431 | return -ENODEV; | |
432 | } | |
433 | ||
ae82cef7 SS |
434 | ret = amd_pmf_tee_init(dev); |
435 | if (ret) | |
436 | return ret; | |
437 | ||
438 | INIT_DELAYED_WORK(&dev->pb_work, amd_pmf_invoke_cmd); | |
e7096150 ML |
439 | |
440 | ret = amd_pmf_set_dram_addr(dev, true); | |
441 | if (ret) | |
442 | goto error; | |
443 | ||
444 | dev->policy_base = devm_ioremap(dev->dev, dev->policy_addr, dev->policy_sz); | |
445 | if (!dev->policy_base) { | |
446 | ret = -ENOMEM; | |
447 | goto error; | |
448 | } | |
449 | ||
450 | dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL); | |
451 | if (!dev->policy_buf) { | |
452 | ret = -ENOMEM; | |
453 | goto error; | |
454 | } | |
455 | ||
456 | memcpy(dev->policy_buf, dev->policy_base, dev->policy_sz); | |
457 | ||
458 | amd_pmf_hex_dump_pb(dev); | |
e7096150 | 459 | |
7c45534a | 460 | dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL); |
0314cebb HM |
461 | if (!dev->prev_data) { |
462 | ret = -ENOMEM; | |
e7096150 | 463 | goto error; |
0314cebb | 464 | } |
7c45534a | 465 | |
e7096150 ML |
466 | ret = amd_pmf_start_policy_engine(dev); |
467 | if (ret) | |
468 | goto error; | |
469 | ||
76d41fb0 ML |
470 | if (pb_side_load) |
471 | amd_pmf_open_pb(dev, dev->dbgfs_dir); | |
472 | ||
e7096150 ML |
473 | return 0; |
474 | ||
475 | error: | |
476 | amd_pmf_deinit_smart_pc(dev); | |
477 | ||
478 | return ret; | |
ac052d8c SS |
479 | } |
480 | ||
481 | void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev) | |
482 | { | |
e7096150 | 483 | if (pb_side_load && dev->esbin) |
10817f28 SS |
484 | amd_pmf_remove_pb(dev); |
485 | ||
e7096150 | 486 | cancel_delayed_work_sync(&dev->pb_work); |
7c45534a | 487 | kfree(dev->prev_data); |
e7096150 | 488 | dev->prev_data = NULL; |
7c45534a | 489 | kfree(dev->policy_buf); |
e7096150 ML |
490 | dev->policy_buf = NULL; |
491 | kfree(dev->buf); | |
492 | dev->buf = NULL; | |
ac052d8c SS |
493 | amd_pmf_tee_deinit(dev); |
494 | } |