Commit ac052d8c authored by Shyam Sundar S K's avatar Shyam Sundar S K Committed by Hans de Goede
Browse files

platform/x86/amd/pmf: Add PMF TEE interface



AMD PMF driver loads the PMF TA (Trusted Application) into the AMD
ASP's (AMD Security Processor) TEE (Trusted Execution Environment).

PMF Trusted Application is a secured firmware placed under
/lib/firmware/amdtee gets loaded only when the TEE environment is
initialized. Add the initial code path to build these pipes.

Reviewed-by: default avatarMario Limonciello <mario.limonciello@amd.com>
Signed-off-by: default avatarShyam Sundar S K <Shyam-sundar.S-k@amd.com>
Link: https://lore.kernel.org/r/20231212014705.2017474-2-Shyam-sundar.S-k@amd.com


Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent ed289b98
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ config AMD_PMF
	depends on POWER_SUPPLY
	depends on AMD_NB
	select ACPI_PLATFORM_PROFILE
	depends on TEE
	help
	  This driver provides support for the AMD Platform Management Framework.
	  The goal is to enhance end user experience by making AMD PCs smarter,
+2 −1
Original line number Diff line number Diff line
@@ -6,4 +6,5 @@

obj-$(CONFIG_AMD_PMF) += amd-pmf.o
amd-pmf-objs := core.o acpi.o sps.o \
		auto-mode.o cnqf.o
		auto-mode.o cnqf.o \
		tee-if.o
+6 −4
Original line number Diff line number Diff line
@@ -309,13 +309,13 @@ static void amd_pmf_init_features(struct amd_pmf_dev *dev)
		dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n");
	}

	/* Enable Auto Mode */
	if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
	if (!amd_pmf_init_smart_pc(dev)) {
		dev_dbg(dev->dev, "Smart PC Solution Enabled\n");
	} else if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
		amd_pmf_init_auto_mode(dev);
		dev_dbg(dev->dev, "Auto Mode Init done\n");
	} else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
			  is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
		/* Enable Cool n Quiet Framework (CnQF) */
		ret = amd_pmf_init_cnqf(dev);
		if (ret)
			dev_warn(dev->dev, "CnQF Init failed\n");
@@ -330,7 +330,9 @@ static void amd_pmf_deinit_features(struct amd_pmf_dev *dev)
		amd_pmf_deinit_sps(dev);
	}

	if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
	if (!dev->smart_pc_enabled) {
		amd_pmf_deinit_smart_pc(dev);
	} else if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
		amd_pmf_deinit_auto_mode(dev);
	} else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
			  is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
+16 −0
Original line number Diff line number Diff line
@@ -179,6 +179,12 @@ struct amd_pmf_dev {
	bool cnqf_enabled;
	bool cnqf_supported;
	struct notifier_block pwr_src_notifier;
	/* Smart PC solution builder */
	struct tee_context *tee_ctx;
	struct tee_shm *fw_shm_pool;
	u32 session_id;
	void *shbuf;
	bool smart_pc_enabled;
};

struct apmf_sps_prop_granular {
@@ -389,6 +395,13 @@ struct apmf_dyn_slider_output {
	struct apmf_cnqf_power_set ps[APMF_CNQF_MAX];
} __packed;

struct ta_pmf_shared_memory {
	int command_id;
	int resp_id;
	u32 pmf_result;
	u32 if_version;
};

/* Core Layer */
int apmf_acpi_init(struct amd_pmf_dev *pmf_dev);
void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev);
@@ -433,4 +446,7 @@ void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev);
int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms);
extern const struct attribute_group cnqf_feature_attribute_group;

/* Smart PC builder Layer */
int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev);
void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev);
#endif /* PMF_H */
+105 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * AMD Platform Management Framework Driver - TEE Interface
 *
 * Copyright (c) 2023, Advanced Micro Devices, Inc.
 * All Rights Reserved.
 *
 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
 */

#include <linux/tee_drv.h>
#include <linux/uuid.h>
#include "pmf.h"

#define MAX_TEE_PARAM	4
static const uuid_t amd_pmf_ta_uuid = UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d,
						0xb1, 0x2d, 0xc5, 0x29, 0xb1, 0x3d, 0x85, 0x43);

static int amd_pmf_amdtee_ta_match(struct tee_ioctl_version_data *ver, const void *data)
{
	return ver->impl_id == TEE_IMPL_ID_AMDTEE;
}

static int amd_pmf_ta_open_session(struct tee_context *ctx, u32 *id)
{
	struct tee_ioctl_open_session_arg sess_arg = {};
	int rc;

	export_uuid(sess_arg.uuid, &amd_pmf_ta_uuid);
	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
	sess_arg.num_params = 0;

	rc = tee_client_open_session(ctx, &sess_arg, NULL);
	if (rc < 0 || sess_arg.ret != 0) {
		pr_err("Failed to open TEE session err:%#x, rc:%d\n", sess_arg.ret, rc);
		return rc;
	}

	*id = sess_arg.session;

	return rc;
}

static int amd_pmf_tee_init(struct amd_pmf_dev *dev)
{
	u32 size;
	int ret;

	dev->tee_ctx = tee_client_open_context(NULL, amd_pmf_amdtee_ta_match, NULL, NULL);
	if (IS_ERR(dev->tee_ctx)) {
		dev_err(dev->dev, "Failed to open TEE context\n");
		return PTR_ERR(dev->tee_ctx);
	}

	ret = amd_pmf_ta_open_session(dev->tee_ctx, &dev->session_id);
	if (ret) {
		dev_err(dev->dev, "Failed to open TA session (%d)\n", ret);
		ret = -EINVAL;
		goto out_ctx;
	}

	size = sizeof(struct ta_pmf_shared_memory);
	dev->fw_shm_pool = tee_shm_alloc_kernel_buf(dev->tee_ctx, size);
	if (IS_ERR(dev->fw_shm_pool)) {
		dev_err(dev->dev, "Failed to alloc TEE shared memory\n");
		ret = PTR_ERR(dev->fw_shm_pool);
		goto out_sess;
	}

	dev->shbuf = tee_shm_get_va(dev->fw_shm_pool, 0);
	if (IS_ERR(dev->shbuf)) {
		dev_err(dev->dev, "Failed to get TEE virtual address\n");
		ret = PTR_ERR(dev->shbuf);
		goto out_shm;
	}
	dev_dbg(dev->dev, "TEE init done\n");

	return 0;

out_shm:
	tee_shm_free(dev->fw_shm_pool);
out_sess:
	tee_client_close_session(dev->tee_ctx, dev->session_id);
out_ctx:
	tee_client_close_context(dev->tee_ctx);

	return ret;
}

static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev)
{
	tee_shm_free(dev->fw_shm_pool);
	tee_client_close_session(dev->tee_ctx, dev->session_id);
	tee_client_close_context(dev->tee_ctx);
}

int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
{
	return amd_pmf_tee_init(dev);
}

void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev)
{
	amd_pmf_tee_deinit(dev);
}