brintos

brintos / linux-shallow public Read only

0
0
Text · 14.7 KiB · 19c27b6 Raw
573 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * AMD Platform Management Framework Driver - TEE Interface4 *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 11#include <linux/debugfs.h>12#include <linux/tee_drv.h>13#include <linux/uuid.h>14#include "pmf.h"15 16#define MAX_TEE_PARAM	417 18/* Policy binary actions sampling frequency (in ms) */19static int pb_actions_ms = MSEC_PER_SEC;20/* Sideload policy binaries to debug policy failures */21static bool pb_side_load;22 23#ifdef CONFIG_AMD_PMF_DEBUG24module_param(pb_actions_ms, int, 0644);25MODULE_PARM_DESC(pb_actions_ms, "Policy binary actions sampling frequency (default = 1000ms)");26module_param(pb_side_load, bool, 0444);27MODULE_PARM_DESC(pb_side_load, "Sideload policy binaries debug policy failures");28#endif29 30static const uuid_t amd_pmf_ta_uuid = UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d,31						0xb1, 0x2d, 0xc5, 0x29, 0xb1, 0x3d, 0x85, 0x43);32 33static 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 47static 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 65static void amd_pmf_update_uevents(struct amd_pmf_dev *dev, u16 event)66{67	input_report_key(dev->pmf_idev, event, 1); /* key press */68	input_sync(dev->pmf_idev);69	input_report_key(dev->pmf_idev, event, 0); /* key release */70	input_sync(dev->pmf_idev);71}72 73static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out)74{75	u32 val;76	int idx;77 78	for (idx = 0; idx < out->actions_count; idx++) {79		val = out->actions_list[idx].value;80		switch (out->actions_list[idx].action_index) {81		case PMF_POLICY_SPL:82			if (dev->prev_data->spl != val) {83				amd_pmf_send_cmd(dev, SET_SPL, false, val, NULL);84				dev_dbg(dev->dev, "update SPL: %u\n", val);85				dev->prev_data->spl = val;86			}87			break;88 89		case PMF_POLICY_SPPT:90			if (dev->prev_data->sppt != val) {91				amd_pmf_send_cmd(dev, SET_SPPT, false, val, NULL);92				dev_dbg(dev->dev, "update SPPT: %u\n", val);93				dev->prev_data->sppt = val;94			}95			break;96 97		case PMF_POLICY_FPPT:98			if (dev->prev_data->fppt != val) {99				amd_pmf_send_cmd(dev, SET_FPPT, false, val, NULL);100				dev_dbg(dev->dev, "update FPPT: %u\n", val);101				dev->prev_data->fppt = val;102			}103			break;104 105		case PMF_POLICY_SPPT_APU_ONLY:106			if (dev->prev_data->sppt_apuonly != val) {107				amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, val, NULL);108				dev_dbg(dev->dev, "update SPPT_APU_ONLY: %u\n", val);109				dev->prev_data->sppt_apuonly = val;110			}111			break;112 113		case PMF_POLICY_STT_MIN:114			if (dev->prev_data->stt_minlimit != val) {115				amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, val, NULL);116				dev_dbg(dev->dev, "update STT_MIN: %u\n", val);117				dev->prev_data->stt_minlimit = val;118			}119			break;120 121		case PMF_POLICY_STT_SKINTEMP_APU:122			if (dev->prev_data->stt_skintemp_apu != val) {123				amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, val, NULL);124				dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val);125				dev->prev_data->stt_skintemp_apu = val;126			}127			break;128 129		case PMF_POLICY_STT_SKINTEMP_HS2:130			if (dev->prev_data->stt_skintemp_hs2 != val) {131				amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, val, NULL);132				dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val);133				dev->prev_data->stt_skintemp_hs2 = val;134			}135			break;136 137		case PMF_POLICY_P3T:138			if (dev->prev_data->p3t_limit != val) {139				amd_pmf_send_cmd(dev, SET_P3T, false, val, NULL);140				dev_dbg(dev->dev, "update P3T: %u\n", val);141				dev->prev_data->p3t_limit = val;142			}143			break;144 145		case PMF_POLICY_SYSTEM_STATE:146			switch (val) {147			case 0:148				amd_pmf_update_uevents(dev, KEY_SLEEP);149				break;150			case 1:151				amd_pmf_update_uevents(dev, KEY_SUSPEND);152				break;153			case 2:154				amd_pmf_update_uevents(dev, KEY_SCREENLOCK);155				break;156			default:157				dev_err(dev->dev, "Invalid PMF policy system state: %d\n", val);158			}159 160			dev_dbg(dev->dev, "update SYSTEM_STATE: %s\n",161				amd_pmf_uevent_as_str(val));162			break;163 164		case PMF_POLICY_BIOS_OUTPUT_1:165			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(0), 0);166			break;167 168		case PMF_POLICY_BIOS_OUTPUT_2:169			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(1), 1);170			break;171 172		case PMF_POLICY_BIOS_OUTPUT_3:173			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(2), 2);174			break;175 176		case PMF_POLICY_BIOS_OUTPUT_4:177			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(3), 3);178			break;179 180		case PMF_POLICY_BIOS_OUTPUT_5:181			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(4), 4);182			break;183 184		case PMF_POLICY_BIOS_OUTPUT_6:185			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(5), 5);186			break;187 188		case PMF_POLICY_BIOS_OUTPUT_7:189			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(6), 6);190			break;191 192		case PMF_POLICY_BIOS_OUTPUT_8:193			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(7), 7);194			break;195 196		case PMF_POLICY_BIOS_OUTPUT_9:197			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(8), 8);198			break;199 200		case PMF_POLICY_BIOS_OUTPUT_10:201			amd_pmf_smartpc_apply_bios_output(dev, val, BIT(9), 9);202			break;203		}204	}205}206 207static int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev)208{209	struct ta_pmf_shared_memory *ta_sm = NULL;210	struct ta_pmf_enact_result *out = NULL;211	struct ta_pmf_enact_table *in = NULL;212	struct tee_param param[MAX_TEE_PARAM];213	struct tee_ioctl_invoke_arg arg;214	int ret = 0;215 216	if (!dev->tee_ctx)217		return -ENODEV;218 219	memset(dev->shbuf, 0, dev->policy_sz);220	ta_sm = dev->shbuf;221	out = &ta_sm->pmf_output.policy_apply_table;222	in = &ta_sm->pmf_input.enact_table;223 224	memset(ta_sm, 0, sizeof(*ta_sm));225	ta_sm->command_id = TA_PMF_COMMAND_POLICY_BUILDER_ENACT_POLICIES;226	ta_sm->if_version = PMF_TA_IF_VERSION_MAJOR;227 228	amd_pmf_populate_ta_inputs(dev, in);229	amd_pmf_prepare_args(dev, TA_PMF_COMMAND_POLICY_BUILDER_ENACT_POLICIES, &arg, param);230 231	ret = tee_client_invoke_func(dev->tee_ctx, &arg, param);232	if (ret < 0 || arg.ret != 0) {233		dev_err(dev->dev, "TEE enact cmd failed. err: %x, ret:%d\n", arg.ret, ret);234		return ret;235	}236 237	if (ta_sm->pmf_result == TA_PMF_TYPE_SUCCESS && out->actions_count) {238		amd_pmf_dump_ta_inputs(dev, in);239		dev_dbg(dev->dev, "action count:%u result:%x\n", out->actions_count,240			ta_sm->pmf_result);241		amd_pmf_apply_policies(dev, out);242	}243 244	return 0;245}246 247static int amd_pmf_invoke_cmd_init(struct amd_pmf_dev *dev)248{249	struct ta_pmf_shared_memory *ta_sm = NULL;250	struct tee_param param[MAX_TEE_PARAM];251	struct ta_pmf_init_table *in = NULL;252	struct tee_ioctl_invoke_arg arg;253	int ret = 0;254 255	if (!dev->tee_ctx) {256		dev_err(dev->dev, "Failed to get TEE context\n");257		return -ENODEV;258	}259 260	dev_dbg(dev->dev, "Policy Binary size: %u bytes\n", dev->policy_sz);261	memset(dev->shbuf, 0, dev->policy_sz);262	ta_sm = dev->shbuf;263	in = &ta_sm->pmf_input.init_table;264 265	ta_sm->command_id = TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE;266	ta_sm->if_version = PMF_TA_IF_VERSION_MAJOR;267 268	in->metadata_macrocheck = false;269	in->sku_check = false;270	in->validate = true;271	in->frequency = pb_actions_ms;272	in->policies_table.table_size = dev->policy_sz;273 274	memcpy(in->policies_table.table, dev->policy_buf, dev->policy_sz);275	amd_pmf_prepare_args(dev, TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE, &arg, param);276 277	ret = tee_client_invoke_func(dev->tee_ctx, &arg, param);278	if (ret < 0 || arg.ret != 0) {279		dev_err(dev->dev, "Failed to invoke TEE init cmd. err: %x, ret:%d\n", arg.ret, ret);280		return ret;281	}282 283	return ta_sm->pmf_result;284}285 286static void amd_pmf_invoke_cmd(struct work_struct *work)287{288	struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, pb_work.work);289 290	amd_pmf_invoke_cmd_enact(dev);291	schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms));292}293 294static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)295{296	struct cookie_header *header;297	int res;298 299	if (dev->policy_sz < POLICY_COOKIE_OFFSET + sizeof(*header))300		return -EINVAL;301 302	header = (struct cookie_header *)(dev->policy_buf + POLICY_COOKIE_OFFSET);303 304	if (header->sign != POLICY_SIGN_COOKIE || !header->length) {305		dev_dbg(dev->dev, "cookie doesn't match\n");306		return -EINVAL;307	}308 309	if (dev->policy_sz < header->length + 512)310		return -EINVAL;311 312	/* Update the actual length */313	dev->policy_sz = header->length + 512;314	res = amd_pmf_invoke_cmd_init(dev);315	if (res == TA_PMF_TYPE_SUCCESS) {316		/* Now its safe to announce that smart pc is enabled */317		dev->smart_pc_enabled = true;318		/*319		 * Start collecting the data from TA FW after a small delay320		 * or else, we might end up getting stale values.321		 */322		schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms * 3));323	} else {324		dev_err(dev->dev, "ta invoke cmd init failed err: %x\n", res);325		dev->smart_pc_enabled = false;326		return -EIO;327	}328 329	return 0;330}331 332#ifdef CONFIG_AMD_PMF_DEBUG333static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev)334{335	print_hex_dump_debug("(pb):  ", DUMP_PREFIX_OFFSET, 16, 1, dev->policy_buf,336			     dev->policy_sz, false);337}338 339static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf,340				   size_t length, loff_t *pos)341{342	struct amd_pmf_dev *dev = filp->private_data;343	unsigned char *new_policy_buf;344	int ret;345 346	/* Policy binary size cannot exceed POLICY_BUF_MAX_SZ */347	if (length > POLICY_BUF_MAX_SZ || length == 0)348		return -EINVAL;349 350	/* re-alloc to the new buffer length of the policy binary */351	new_policy_buf = memdup_user(buf, length);352	if (IS_ERR(new_policy_buf))353		return PTR_ERR(new_policy_buf);354 355	kfree(dev->policy_buf);356	dev->policy_buf = new_policy_buf;357	dev->policy_sz = length;358 359	amd_pmf_hex_dump_pb(dev);360	ret = amd_pmf_start_policy_engine(dev);361	if (ret < 0)362		return ret;363 364	return length;365}366 367static const struct file_operations pb_fops = {368	.write = amd_pmf_get_pb_data,369	.open = simple_open,370};371 372static void amd_pmf_open_pb(struct amd_pmf_dev *dev, struct dentry *debugfs_root)373{374	dev->esbin = debugfs_create_dir("pb", debugfs_root);375	debugfs_create_file("update_policy", 0644, dev->esbin, dev, &pb_fops);376}377 378static void amd_pmf_remove_pb(struct amd_pmf_dev *dev)379{380	debugfs_remove_recursive(dev->esbin);381}382#else383static void amd_pmf_open_pb(struct amd_pmf_dev *dev, struct dentry *debugfs_root) {}384static void amd_pmf_remove_pb(struct amd_pmf_dev *dev) {}385static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev) {}386#endif387 388static int amd_pmf_amdtee_ta_match(struct tee_ioctl_version_data *ver, const void *data)389{390	return ver->impl_id == TEE_IMPL_ID_AMDTEE;391}392 393static int amd_pmf_ta_open_session(struct tee_context *ctx, u32 *id)394{395	struct tee_ioctl_open_session_arg sess_arg = {};396	int rc;397 398	export_uuid(sess_arg.uuid, &amd_pmf_ta_uuid);399	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;400	sess_arg.num_params = 0;401 402	rc = tee_client_open_session(ctx, &sess_arg, NULL);403	if (rc < 0 || sess_arg.ret != 0) {404		pr_err("Failed to open TEE session err:%#x, rc:%d\n", sess_arg.ret, rc);405		return rc;406	}407 408	*id = sess_arg.session;409 410	return rc;411}412 413static int amd_pmf_register_input_device(struct amd_pmf_dev *dev)414{415	int err;416 417	dev->pmf_idev = devm_input_allocate_device(dev->dev);418	if (!dev->pmf_idev)419		return -ENOMEM;420 421	dev->pmf_idev->name = "PMF-TA output events";422	dev->pmf_idev->phys = "amd-pmf/input0";423 424	input_set_capability(dev->pmf_idev, EV_KEY, KEY_SLEEP);425	input_set_capability(dev->pmf_idev, EV_KEY, KEY_SCREENLOCK);426	input_set_capability(dev->pmf_idev, EV_KEY, KEY_SUSPEND);427 428	err = input_register_device(dev->pmf_idev);429	if (err) {430		dev_err(dev->dev, "Failed to register input device: %d\n", err);431		return err;432	}433 434	return 0;435}436 437static int amd_pmf_tee_init(struct amd_pmf_dev *dev)438{439	u32 size;440	int ret;441 442	dev->tee_ctx = tee_client_open_context(NULL, amd_pmf_amdtee_ta_match, NULL, NULL);443	if (IS_ERR(dev->tee_ctx)) {444		dev_err(dev->dev, "Failed to open TEE context\n");445		return PTR_ERR(dev->tee_ctx);446	}447 448	ret = amd_pmf_ta_open_session(dev->tee_ctx, &dev->session_id);449	if (ret) {450		dev_err(dev->dev, "Failed to open TA session (%d)\n", ret);451		ret = -EINVAL;452		goto out_ctx;453	}454 455	size = sizeof(struct ta_pmf_shared_memory) + dev->policy_sz;456	dev->fw_shm_pool = tee_shm_alloc_kernel_buf(dev->tee_ctx, size);457	if (IS_ERR(dev->fw_shm_pool)) {458		dev_err(dev->dev, "Failed to alloc TEE shared memory\n");459		ret = PTR_ERR(dev->fw_shm_pool);460		goto out_sess;461	}462 463	dev->shbuf = tee_shm_get_va(dev->fw_shm_pool, 0);464	if (IS_ERR(dev->shbuf)) {465		dev_err(dev->dev, "Failed to get TEE virtual address\n");466		ret = PTR_ERR(dev->shbuf);467		goto out_shm;468	}469	dev_dbg(dev->dev, "TEE init done\n");470 471	return 0;472 473out_shm:474	tee_shm_free(dev->fw_shm_pool);475out_sess:476	tee_client_close_session(dev->tee_ctx, dev->session_id);477out_ctx:478	tee_client_close_context(dev->tee_ctx);479 480	return ret;481}482 483static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev)484{485	tee_shm_free(dev->fw_shm_pool);486	tee_client_close_session(dev->tee_ctx, dev->session_id);487	tee_client_close_context(dev->tee_ctx);488}489 490int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)491{492	int ret;493 494	ret = apmf_check_smart_pc(dev);495	if (ret) {496		/*497		 * Lets not return from here if Smart PC bit is not advertised in498		 * the BIOS. This way, there will be some amount of power savings499		 * to the user with static slider (if enabled).500		 */501		dev_info(dev->dev, "PMF Smart PC not advertised in BIOS!:%d\n", ret);502		return -ENODEV;503	}504 505	ret = amd_pmf_tee_init(dev);506	if (ret)507		return ret;508 509	INIT_DELAYED_WORK(&dev->pb_work, amd_pmf_invoke_cmd);510 511	ret = amd_pmf_set_dram_addr(dev, true);512	if (ret)513		goto error;514 515	dev->policy_base = devm_ioremap(dev->dev, dev->policy_addr, dev->policy_sz);516	if (!dev->policy_base) {517		ret = -ENOMEM;518		goto error;519	}520 521	dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL);522	if (!dev->policy_buf) {523		ret = -ENOMEM;524		goto error;525	}526 527	memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz);528 529	amd_pmf_hex_dump_pb(dev);530 531	dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL);532	if (!dev->prev_data) {533		ret = -ENOMEM;534		goto error;535	}536 537	ret = amd_pmf_start_policy_engine(dev);538	if (ret)539		goto error;540 541	if (pb_side_load)542		amd_pmf_open_pb(dev, dev->dbgfs_dir);543 544	ret = amd_pmf_register_input_device(dev);545	if (ret)546		goto error;547 548	return 0;549 550error:551	amd_pmf_deinit_smart_pc(dev);552 553	return ret;554}555 556void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev)557{558	if (dev->pmf_idev)559		input_unregister_device(dev->pmf_idev);560 561	if (pb_side_load && dev->esbin)562		amd_pmf_remove_pb(dev);563 564	cancel_delayed_work_sync(&dev->pb_work);565	kfree(dev->prev_data);566	dev->prev_data = NULL;567	kfree(dev->policy_buf);568	dev->policy_buf = NULL;569	kfree(dev->buf);570	dev->buf = NULL;571	amd_pmf_tee_deinit(dev);572}573