1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AMD Platform Management Framework Util Layer
*
* Copyright (c) 2026, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
* Sanket Goswami <Sanket.Goswami@amd.com>
*/
#include <linux/amd-pmf.h>
#include <linux/minmax.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include "pmf.h"
static struct amd_pmf_dev *pmf_dev_handle;
static DEFINE_MUTEX(pmf_util_lock);
static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info)
{
struct ta_pmf_shared_memory *ta_sm = NULL;
struct ta_pmf_enact_table *in = NULL;
int idx;
if (!pdev || !info)
return -EINVAL;
if (!pdev->shbuf)
return -EINVAL;
ta_sm = pdev->shbuf;
in = &ta_sm->pmf_input.enact_table;
/* Set size */
info->size = sizeof(*info);
/* PMF Feature support flags */
if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE))
info->features_supported |= AMD_PMF_FEAT_AUTO_MODE;
if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER;
if (pdev->smart_pc_enabled)
info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER;
if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC))
info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC;
if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC))
info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC;
/* Device States */
info->platform_type = in->ev_info.platform_type;
info->laptop_placement = in->ev_info.device_state;
info->lid_state = in->ev_info.lid_state;
info->user_presence = in->ev_info.user_present;
info->slider_position = in->ev_info.power_slider;
/* Thermal and Power Metrics */
info->power_source = in->ev_info.power_source;
info->skin_temp = in->ev_info.skin_temperature;
info->gfx_busy = in->ev_info.gfx_busy;
info->ambient_light = in->ev_info.ambient_light;
info->avg_c0_residency = in->ev_info.avg_c0residency;
info->max_c0_residency = in->ev_info.max_c0residency;
info->socket_power = in->ev_info.socket_power;
/* Custom BIOS input parameters */
for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx);
/* BIOS output parameters */
for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
info->bios_output[idx] = pdev->bios_output[idx];
return 0;
}
static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct amd_pmf_dev *pdev = filp->private_data;
void __user *argp = (void __user *)arg;
struct amd_pmf_info info = {};
size_t copy_size;
__u64 user_size;
int ret;
if (cmd != IOCTL_AMD_PMF_POPULATE_DATA)
return -ENOTTY;
/* First read just the size field from userspace */
if (copy_from_user(&user_size, argp, sizeof(user_size)))
return -EFAULT;
guard(mutex)(&pmf_util_lock);
ret = amd_pmf_populate_data(pdev, &info);
if (ret)
return ret;
copy_size = min_t(size_t, user_size, sizeof(info));
/* Set actual size being copied */
info.size = copy_size;
if (copy_to_user(argp, &info, copy_size))
return -EFAULT;
return 0;
}
static int amd_pmf_open(struct inode *inode, struct file *filp)
{
guard(mutex)(&pmf_util_lock);
if (!pmf_dev_handle)
return -ENODEV;
filp->private_data = pmf_dev_handle;
return 0;
}
static const struct file_operations pmf_if_ops = {
.owner = THIS_MODULE,
.open = amd_pmf_open,
.unlocked_ioctl = amd_pmf_set_ioctl,
};
static struct miscdevice amd_pmf_util_if = {
.minor = MISC_DYNAMIC_MINOR,
.name = "amdpmf_interface",
.fops = &pmf_if_ops,
};
int amd_pmf_cdev_register(struct amd_pmf_dev *dev)
{
int ret;
guard(mutex)(&pmf_util_lock);
pmf_dev_handle = dev;
ret = misc_register(&amd_pmf_util_if);
if (ret)
pmf_dev_handle = NULL;
return ret;
}
void amd_pmf_cdev_unregister(void)
{
guard(mutex)(&pmf_util_lock);
if (pmf_dev_handle)
misc_deregister(&amd_pmf_util_if);
pmf_dev_handle = NULL;
}
|