Skip to content

Commit 7c45534

Browse files
Shyam Sundar S Kjwrdegoede
authored andcommitted
platform/x86/amd/pmf: Add support for PMF Policy Binary
PMF Policy binary is a encrypted and signed binary that will be part of the BIOS. PMF driver via the ACPI interface checks the existence of Smart PC bit. If the advertised bit is found, PMF driver walks the acpi namespace to find out the policy binary size and the address which has to be passed to the TA during the TA init sequence. The policy binary is comprised of inputs (or the events) and outputs (or the actions). With the PMF ecosystem, OEMs generate the policy binary (or could be multiple binaries) that contains a supported set of inputs and outputs which could be specifically carved out for each usage segment (or for each user also) that could influence the system behavior either by enriching the user experience or/and boost/throttle power limits. Once the TA init command succeeds, the PMF driver sends the changing events in the current environment to the TA for a constant sampling frequency time (the event here could be a lid close or open) and if the policy binary has corresponding action built within it, the TA sends the action for it in the subsequent enact command. If the inputs sent to the TA has no output defined in the policy binary generated by OEMs, there will be no action to be performed by the PMF driver. Example policies: 1) if slider is performance ; set the SPL to 40W Here PMF driver registers with the platform profile interface and when the slider position is changed, PMF driver lets the TA know about this. TA sends back an action to update the Sustained Power Limit (SPL). PMF driver updates this limit via the PMFW mailbox. 2) if user_away ; then lock the system Here PMF driver hooks to the AMD SFH driver to know the user presence and send the inputs to TA and if the condition is met, the TA sends the action of locking the system. PMF driver generates a uevent and based on the udev rule in the userland the system gets locked with systemctl. The intent here is to provide the OEM's to make a policy to lock the system when the user is away ; but the userland can make a choice to ignore it. The OEMs will have an utility to create numerous such policies and the policies shall be reviewed by AMD before signing and encrypting them. Policies are shared between operating systems to have seemless user experience. Since all this action has to happen via the "amdtee" driver, currently there is no caller for it in the kernel which can load the amdtee driver. Without amdtee driver loading onto the system the "tee" calls shall fail from the PMF driver. Hence an explicit MODULE_SOFTDEP has been added to address this. Signed-off-by: Shyam Sundar S K <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Hans de Goede <[email protected]>
1 parent 2b3a7f0 commit 7c45534

File tree

5 files changed

+336
-3
lines changed

5 files changed

+336
-3
lines changed

drivers/platform/x86/amd/pmf/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ config AMD_PMF
99
depends on POWER_SUPPLY
1010
depends on AMD_NB
1111
select ACPI_PLATFORM_PROFILE
12-
depends on TEE
12+
depends on TEE && AMDTEE
1313
help
1414
This driver provides support for the AMD Platform Management Framework.
1515
The goal is to enhance end user experience by making AMD PCs smarter,

drivers/platform/x86/amd/pmf/acpi.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,43 @@ int apmf_install_handler(struct amd_pmf_dev *pmf_dev)
286286
return 0;
287287
}
288288

289+
static acpi_status apmf_walk_resources(struct acpi_resource *res, void *data)
290+
{
291+
struct amd_pmf_dev *dev = data;
292+
293+
switch (res->type) {
294+
case ACPI_RESOURCE_TYPE_ADDRESS64:
295+
dev->policy_addr = res->data.address64.address.minimum;
296+
dev->policy_sz = res->data.address64.address.address_length;
297+
break;
298+
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
299+
dev->policy_addr = res->data.fixed_memory32.address;
300+
dev->policy_sz = res->data.fixed_memory32.address_length;
301+
break;
302+
}
303+
304+
if (!dev->policy_addr || dev->policy_sz > POLICY_BUF_MAX_SZ || dev->policy_sz == 0) {
305+
pr_err("Incorrect Policy params, possibly a SBIOS bug\n");
306+
return AE_ERROR;
307+
}
308+
309+
return AE_OK;
310+
}
311+
312+
int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev)
313+
{
314+
acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
315+
acpi_status status;
316+
317+
status = acpi_walk_resources(ahandle, METHOD_NAME__CRS, apmf_walk_resources, pmf_dev);
318+
if (ACPI_FAILURE(status)) {
319+
dev_err(pmf_dev->dev, "acpi_walk_resources failed :%d\n", status);
320+
return -EINVAL;
321+
}
322+
323+
return 0;
324+
}
325+
289326
void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev)
290327
{
291328
acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);

drivers/platform/x86/amd/pmf/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,4 @@ module_platform_driver(amd_pmf_driver);
471471

472472
MODULE_LICENSE("GPL");
473473
MODULE_DESCRIPTION("AMD Platform Management Framework Driver");
474+
MODULE_SOFTDEP("pre: amdtee");

drivers/platform/x86/amd/pmf/pmf.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
#include <linux/acpi.h>
1515
#include <linux/platform_profile.h>
1616

17+
#define POLICY_BUF_MAX_SZ 0x4b000
18+
#define POLICY_SIGN_COOKIE 0x31535024
19+
#define POLICY_COOKIE_OFFSET 0x10
20+
#define POLICY_COOKIE_LEN 0x14
21+
1722
/* APMF Functions */
1823
#define APMF_FUNC_VERIFY_INTERFACE 0
1924
#define APMF_FUNC_GET_SYS_PARAMS 1
@@ -59,8 +64,21 @@
5964
#define ARG_NONE 0
6065
#define AVG_SAMPLE_SIZE 3
6166

67+
/* Policy Actions */
68+
#define PMF_POLICY_SPL 2
69+
#define PMF_POLICY_SPPT 3
70+
#define PMF_POLICY_FPPT 4
71+
#define PMF_POLICY_SPPT_APU_ONLY 5
72+
#define PMF_POLICY_STT_MIN 6
73+
#define PMF_POLICY_STT_SKINTEMP_APU 7
74+
#define PMF_POLICY_STT_SKINTEMP_HS2 8
75+
6276
/* TA macros */
6377
#define PMF_TA_IF_VERSION_MAJOR 1
78+
#define TA_PMF_ACTION_MAX 32
79+
#define TA_PMF_UNDO_MAX 8
80+
#define TA_OUTPUT_RESERVED_MEM 906
81+
#define MAX_OPERATION_PARAMS 4
6482

6583
/* AMD PMF BIOS interfaces */
6684
struct apmf_verify_interface {
@@ -183,11 +201,16 @@ struct amd_pmf_dev {
183201
bool cnqf_supported;
184202
struct notifier_block pwr_src_notifier;
185203
/* Smart PC solution builder */
204+
unsigned char *policy_buf;
205+
u32 policy_sz;
186206
struct tee_context *tee_ctx;
187207
struct tee_shm *fw_shm_pool;
188208
u32 session_id;
189209
void *shbuf;
190210
struct delayed_work pb_work;
211+
struct pmf_action_table *prev_data;
212+
u64 policy_addr;
213+
void *policy_base;
191214
bool smart_pc_enabled;
192215
};
193216

@@ -399,17 +422,134 @@ struct apmf_dyn_slider_output {
399422
struct apmf_cnqf_power_set ps[APMF_CNQF_MAX];
400423
} __packed;
401424

425+
enum smart_pc_status {
426+
PMF_SMART_PC_ENABLED,
427+
PMF_SMART_PC_DISABLED,
428+
};
429+
430+
/* Smart PC - TA internals */
431+
enum ta_slider {
432+
TA_BEST_BATTERY,
433+
TA_BETTER_BATTERY,
434+
TA_BETTER_PERFORMANCE,
435+
TA_BEST_PERFORMANCE,
436+
TA_MAX,
437+
};
438+
402439
/* Command ids for TA communication */
403440
enum ta_pmf_command {
404441
TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE,
405442
TA_PMF_COMMAND_POLICY_BUILDER_ENACT_POLICIES,
406443
};
407444

445+
enum ta_pmf_error_type {
446+
TA_PMF_TYPE_SUCCESS,
447+
TA_PMF_ERROR_TYPE_GENERIC,
448+
TA_PMF_ERROR_TYPE_CRYPTO,
449+
TA_PMF_ERROR_TYPE_CRYPTO_VALIDATE,
450+
TA_PMF_ERROR_TYPE_CRYPTO_VERIFY_OEM,
451+
TA_PMF_ERROR_TYPE_POLICY_BUILDER,
452+
TA_PMF_ERROR_TYPE_PB_CONVERT,
453+
TA_PMF_ERROR_TYPE_PB_SETUP,
454+
TA_PMF_ERROR_TYPE_PB_ENACT,
455+
TA_PMF_ERROR_TYPE_ASD_GET_DEVICE_INFO,
456+
TA_PMF_ERROR_TYPE_ASD_GET_DEVICE_PCIE_INFO,
457+
TA_PMF_ERROR_TYPE_SYS_DRV_FW_VALIDATION,
458+
TA_PMF_ERROR_TYPE_MAX,
459+
};
460+
461+
struct pmf_action_table {
462+
u32 spl; /* in mW */
463+
u32 sppt; /* in mW */
464+
u32 sppt_apuonly; /* in mW */
465+
u32 fppt; /* in mW */
466+
u32 stt_minlimit; /* in mW */
467+
u32 stt_skintemp_apu; /* in C */
468+
u32 stt_skintemp_hs2; /* in C */
469+
};
470+
471+
/* Input conditions */
472+
struct ta_pmf_condition_info {
473+
u32 power_source;
474+
u32 bat_percentage;
475+
u32 power_slider;
476+
u32 lid_state;
477+
bool user_present;
478+
u32 rsvd1[2];
479+
u32 monitor_count;
480+
u32 rsvd2[2];
481+
u32 bat_design;
482+
u32 full_charge_capacity;
483+
int drain_rate;
484+
bool user_engaged;
485+
u32 device_state;
486+
u32 socket_power;
487+
u32 skin_temperature;
488+
u32 rsvd3[5];
489+
u32 ambient_light;
490+
u32 length;
491+
u32 avg_c0residency;
492+
u32 max_c0residency;
493+
u32 s0i3_entry;
494+
u32 gfx_busy;
495+
u32 rsvd4[7];
496+
bool camera_state;
497+
u32 workload_type;
498+
u32 display_type;
499+
u32 display_state;
500+
u32 rsvd5[150];
501+
};
502+
503+
struct ta_pmf_load_policy_table {
504+
u32 table_size;
505+
u8 table[POLICY_BUF_MAX_SZ];
506+
};
507+
508+
/* TA initialization params */
509+
struct ta_pmf_init_table {
510+
u32 frequency; /* SMU sampling frequency */
511+
bool validate;
512+
bool sku_check;
513+
bool metadata_macrocheck;
514+
struct ta_pmf_load_policy_table policies_table;
515+
};
516+
517+
/* Everything the TA needs to Enact Policies */
518+
struct ta_pmf_enact_table {
519+
struct ta_pmf_condition_info ev_info;
520+
u32 name;
521+
};
522+
523+
struct ta_pmf_action {
524+
u32 action_index;
525+
u32 value;
526+
};
527+
528+
/* Output actions from TA */
529+
struct ta_pmf_enact_result {
530+
u32 actions_count;
531+
struct ta_pmf_action actions_list[TA_PMF_ACTION_MAX];
532+
u32 undo_count;
533+
struct ta_pmf_action undo_list[TA_PMF_UNDO_MAX];
534+
};
535+
536+
union ta_pmf_input {
537+
struct ta_pmf_enact_table enact_table;
538+
struct ta_pmf_init_table init_table;
539+
};
540+
541+
union ta_pmf_output {
542+
struct ta_pmf_enact_result policy_apply_table;
543+
u32 rsvd[TA_OUTPUT_RESERVED_MEM];
544+
};
545+
408546
struct ta_pmf_shared_memory {
409547
int command_id;
410548
int resp_id;
411549
u32 pmf_result;
412550
u32 if_version;
551+
union ta_pmf_output pmf_output;
552+
union ta_pmf_input pmf_input;
413553
};
414554

415555
/* Core Layer */
@@ -460,4 +600,5 @@ extern const struct attribute_group cnqf_feature_attribute_group;
460600
/* Smart PC builder Layer */
461601
int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev);
462602
void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev);
603+
int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev);
463604
#endif /* PMF_H */

0 commit comments

Comments
 (0)