platform/x86/amd/pmf: Add custom BIOS input support for AMD_CPU_ID_PS

The PMF ACPI Specification (APMF) has been revised to version 1.3 to allow
for additional custom BIOS inputs, enabling OEMs to have more precise
thermal management of the system. This update includes adding support to
the driver using the new data structure received from the BIOS through the
existing APMF interfaces.

Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
Tested-by: Yijun Shen <Yijun.Shen@Dell.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Link: https://patch.msgid.link/20250901110140.2519072-7-Shyam-sundar.S-k@amd.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
Shyam Sundar S K 2025-09-01 16:31:37 +05:30 committed by Ilpo Järvinen
parent 4389d38080
commit 04199ef48a
No known key found for this signature in database
GPG Key ID: 59AC4F6153E5CE31
3 changed files with 106 additions and 12 deletions

View File

@ -320,6 +320,11 @@ int apmf_get_sbios_requests_v2(struct amd_pmf_dev *pdev, struct apmf_sbios_req_v
return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS, req, sizeof(*req));
}
int apmf_get_sbios_requests_v1(struct amd_pmf_dev *pdev, struct apmf_sbios_req_v1 *req)
{
return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS, req, sizeof(*req));
}
int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req)
{
return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS,
@ -338,6 +343,18 @@ static void apmf_event_handler_v2(acpi_handle handle, u32 event, void *data)
dev_err(pmf_dev->dev, "Failed to get v2 SBIOS requests: %d\n", ret);
}
static void apmf_event_handler_v1(acpi_handle handle, u32 event, void *data)
{
struct amd_pmf_dev *pmf_dev = data;
int ret;
guard(mutex)(&pmf_dev->cb_mutex);
ret = apmf_get_sbios_requests_v1(pmf_dev, &pmf_dev->req1);
if (ret)
dev_err(pmf_dev->dev, "Failed to get v1 SBIOS requests: %d\n", ret);
}
static void apmf_event_handler(acpi_handle handle, u32 event, void *data)
{
struct amd_pmf_dev *pmf_dev = data;
@ -427,6 +444,11 @@ int apmf_get_dyn_slider_def_dc(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_
return apmf_if_call_store_buffer(pdev, APMF_FUNC_DYN_SLIDER_DC, data, sizeof(*data));
}
static apmf_event_handler_t apmf_event_handlers[] = {
[PMF_IF_V1] = apmf_event_handler_v1,
[PMF_IF_V2] = apmf_event_handler_v2,
};
int apmf_install_handler(struct amd_pmf_dev *pmf_dev)
{
acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
@ -446,13 +468,26 @@ int apmf_install_handler(struct amd_pmf_dev *pmf_dev)
apmf_event_handler(ahandle, 0, pmf_dev);
}
if (pmf_dev->smart_pc_enabled && pmf_dev->pmf_if_version == PMF_IF_V2) {
if (!pmf_dev->smart_pc_enabled)
return -EINVAL;
switch (pmf_dev->pmf_if_version) {
case PMF_IF_V1:
if (!is_apmf_bios_input_notifications_supported(pmf_dev))
break;
fallthrough;
case PMF_IF_V2:
status = acpi_install_notify_handler(ahandle, ACPI_ALL_NOTIFY,
apmf_event_handler_v2, pmf_dev);
apmf_event_handlers[pmf_dev->pmf_if_version], pmf_dev);
if (ACPI_FAILURE(status)) {
dev_err(pmf_dev->dev, "failed to install notify handler for custom BIOS inputs\n");
dev_err(pmf_dev->dev,
"failed to install notify handler v%d for custom BIOS inputs\n",
pmf_dev->pmf_if_version);
return -ENODEV;
}
break;
default:
break;
}
return 0;
@ -506,8 +541,21 @@ void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev)
is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS))
acpi_remove_notify_handler(ahandle, ACPI_ALL_NOTIFY, apmf_event_handler);
if (pmf_dev->smart_pc_enabled && pmf_dev->pmf_if_version == PMF_IF_V2)
acpi_remove_notify_handler(ahandle, ACPI_ALL_NOTIFY, apmf_event_handler_v2);
if (!pmf_dev->smart_pc_enabled)
return;
switch (pmf_dev->pmf_if_version) {
case PMF_IF_V1:
if (!is_apmf_bios_input_notifications_supported(pmf_dev))
break;
fallthrough;
case PMF_IF_V2:
acpi_remove_notify_handler(ahandle, ACPI_ALL_NOTIFY,
apmf_event_handlers[pmf_dev->pmf_if_version]);
break;
default:
break;
}
}
int apmf_acpi_init(struct amd_pmf_dev *pmf_dev)

View File

@ -120,6 +120,8 @@ struct cookie_header {
#define APTS_MAX_STATES 16
#define CUSTOM_BIOS_INPUT_BITS GENMASK(16, 7)
typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data);
/* APTS PMF BIOS Interface */
struct amd_pmf_apts_output {
u16 table_version;
@ -187,6 +189,24 @@ struct apmf_sbios_req {
u8 skin_temp_hs2;
} __packed;
/* As per APMF spec 1.3 */
struct apmf_sbios_req_v1 {
u16 size;
u32 pending_req;
u8 rsvd;
u8 cql_event;
u8 amt_event;
u32 fppt;
u32 sppt;
u32 sppt_apu_only;
u32 spl;
u32 stt_min_limit;
u8 skin_temp_apu;
u8 skin_temp_hs2;
u8 enable_cnqf;
u32 custom_policy[10];
} __packed;
struct apmf_sbios_req_v2 {
u16 size;
u32 pending_req;
@ -379,6 +399,7 @@ struct amd_pmf_dev {
struct apmf_sbios_req_v2 req; /* To get custom bios pending request */
struct mutex cb_mutex;
u32 notifications;
struct apmf_sbios_req_v1 req1;
};
struct apmf_sps_prop_granular_v2 {
@ -835,6 +856,7 @@ void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev);
void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev);
void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms);
int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req);
int apmf_get_sbios_requests_v1(struct amd_pmf_dev *pdev, struct apmf_sbios_req_v1 *req);
int apmf_get_sbios_requests_v2(struct amd_pmf_dev *pdev, struct apmf_sbios_req_v2 *req);
void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event);

View File

@ -132,22 +132,46 @@ static void amd_pmf_set_ta_custom_bios_input(struct ta_pmf_enact_table *in, int
}
}
static void amd_pmf_get_custom_bios_inputs(struct amd_pmf_dev *pdev,
struct ta_pmf_enact_table *in)
static void amd_pmf_update_bios_inputs(struct amd_pmf_dev *pdev, u32 pending_req,
const struct amd_pmf_pb_bitmap *inputs,
const u32 *custom_policy, struct ta_pmf_enact_table *in)
{
unsigned int i;
if (!pdev->req.pending_req)
for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) {
if (!(pending_req & inputs[i].bit_mask))
continue;
amd_pmf_set_ta_custom_bios_input(in, i, custom_policy[i]);
}
}
static void amd_pmf_get_custom_bios_inputs(struct amd_pmf_dev *pdev,
struct ta_pmf_enact_table *in)
{
if (!(pdev->req.pending_req || pdev->req1.pending_req))
return;
for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) {
if (!(pdev->req.pending_req & custom_bios_inputs[i].bit_mask))
continue;
amd_pmf_set_ta_custom_bios_input(in, i, pdev->req.custom_policy[i]);
if (!pdev->smart_pc_enabled)
return;
switch (pdev->pmf_if_version) {
case PMF_IF_V1:
if (!is_apmf_bios_input_notifications_supported(pdev))
return;
amd_pmf_update_bios_inputs(pdev, pdev->req1.pending_req, custom_bios_inputs_v1,
pdev->req1.custom_policy, in);
break;
case PMF_IF_V2:
amd_pmf_update_bios_inputs(pdev, pdev->req.pending_req, custom_bios_inputs,
pdev->req.custom_policy, in);
break;
default:
break;
}
/* Clear pending requests after handling */
memset(&pdev->req, 0, sizeof(pdev->req));
memset(&pdev->req1, 0, sizeof(pdev->req1));
}
static void amd_pmf_get_c0_residency(u16 *core_res, size_t size, struct ta_pmf_enact_table *in)