Skip to content

Commit d4e95ea

Browse files
Perry Yuanbp3tk0v
authored andcommitted
platform/x86: hfi: Parse CPU core ranking data from shared memory
When `amd_hfi` driver is loaded, it will use PCCT subspace type 4 table to retrieve the shared memory address which contains the CPU core ranking table. This table includes a header that specifies the number of ranking data entries to be parsed and rank each CPU core with the Performance and Energy Efficiency capability as implemented by the CPU power management firmware. Once the table has been parsed, each CPU is assigned a ranking score within its class. Subsequently, when the scheduler selects cores, it chooses from the ranking list based on the assigned scores in each class, thereby ensuring the optimal selection of CPU cores according to their predefined classifications and priorities. Signed-off-by: Perry Yuan <[email protected]> Co-developed-by: Mario Limonciello <[email protected]> Signed-off-by: Mario Limonciello <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Ilpo Järvinen <[email protected]> Acked-by: Ilpo Järvinen <[email protected]> Link: https://lore.kernel.org/[email protected]
1 parent 5d902ee commit d4e95ea

File tree

1 file changed

+198
-0
lines changed
  • drivers/platform/x86/amd/hfi

1 file changed

+198
-0
lines changed

drivers/platform/x86/amd/hfi/hfi.c

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,71 @@
1818
#include <linux/io.h>
1919
#include <linux/kernel.h>
2020
#include <linux/module.h>
21+
#include <linux/mailbox_client.h>
2122
#include <linux/mutex.h>
23+
#include <linux/percpu-defs.h>
2224
#include <linux/platform_device.h>
2325
#include <linux/smp.h>
26+
#include <linux/topology.h>
27+
#include <linux/workqueue.h>
28+
29+
#include <asm/cpu_device_id.h>
30+
31+
#include <acpi/pcc.h>
32+
#include <acpi/cppc_acpi.h>
2433

2534
#define AMD_HFI_DRIVER "amd_hfi"
35+
#define AMD_HFI_MAILBOX_COUNT 1
36+
#define AMD_HETERO_RANKING_TABLE_VER 2
2637

2738
#define AMD_HETERO_CPUID_27 0x80000027
2839

2940
static struct platform_device *device;
3041

42+
/**
43+
* struct amd_shmem_info - Shared memory table for AMD HFI
44+
*
45+
* @header: The PCCT table header including signature, length flags and command.
46+
* @version_number: Version number of the table
47+
* @n_logical_processors: Number of logical processors
48+
* @n_capabilities: Number of ranking dimensions (performance, efficiency, etc)
49+
* @table_update_context: Command being sent over the subspace
50+
* @n_bitmaps: Number of 32-bit bitmaps to enumerate all the APIC IDs
51+
* This is based on the maximum APIC ID enumerated in the system
52+
* @reserved: 24 bit spare
53+
* @table_data: Bit Map(s) of enabled logical processors
54+
* Followed by the ranking data for each logical processor
55+
*/
56+
struct amd_shmem_info {
57+
struct acpi_pcct_ext_pcc_shared_memory header;
58+
u32 version_number :8,
59+
n_logical_processors :8,
60+
n_capabilities :8,
61+
table_update_context :8;
62+
u32 n_bitmaps :8,
63+
reserved :24;
64+
u32 table_data[];
65+
};
66+
3167
struct amd_hfi_data {
3268
const char *name;
3369
struct device *dev;
70+
71+
/* PCCT table related */
72+
struct pcc_mbox_chan *pcc_chan;
73+
void __iomem *pcc_comm_addr;
74+
struct acpi_subtable_header *pcct_entry;
75+
struct amd_shmem_info *shmem;
3476
};
3577

78+
/**
79+
* struct amd_hfi_classes - HFI class capabilities per CPU
80+
* @perf: Performance capability
81+
* @eff: Power efficiency capability
82+
*
83+
* Capabilities of a logical processor in the ranking table. These capabilities
84+
* are unitless and specific to each HFI class.
85+
*/
3686
struct amd_hfi_classes {
3787
u32 perf;
3888
u32 eff;
@@ -41,21 +91,107 @@ struct amd_hfi_classes {
4191
/**
4292
* struct amd_hfi_cpuinfo - HFI workload class info per CPU
4393
* @cpu: CPU index
94+
* @apic_id: APIC id of the current CPU
4495
* @class_index: workload class ID index
4596
* @nr_class: max number of workload class supported
97+
* @ipcc_scores: ipcc scores for each class
4698
* @amd_hfi_classes: current CPU workload class ranking data
4799
*
48100
* Parameters of a logical processor linked with hardware feedback class.
49101
*/
50102
struct amd_hfi_cpuinfo {
51103
int cpu;
104+
u32 apic_id;
52105
s16 class_index;
53106
u8 nr_class;
107+
int *ipcc_scores;
54108
struct amd_hfi_classes *amd_hfi_classes;
55109
};
56110

57111
static DEFINE_PER_CPU(struct amd_hfi_cpuinfo, amd_hfi_cpuinfo) = {.class_index = -1};
58112

113+
static int find_cpu_index_by_apicid(unsigned int target_apicid)
114+
{
115+
int cpu_index;
116+
117+
for_each_possible_cpu(cpu_index) {
118+
struct cpuinfo_x86 *info = &cpu_data(cpu_index);
119+
120+
if (info->topo.apicid == target_apicid) {
121+
pr_debug("match APIC id %u for CPU index: %d\n",
122+
info->topo.apicid, cpu_index);
123+
return cpu_index;
124+
}
125+
}
126+
127+
return -ENODEV;
128+
}
129+
130+
static int amd_hfi_fill_metadata(struct amd_hfi_data *amd_hfi_data)
131+
{
132+
struct acpi_pcct_ext_pcc_slave *pcct_ext =
133+
(struct acpi_pcct_ext_pcc_slave *)amd_hfi_data->pcct_entry;
134+
void __iomem *pcc_comm_addr;
135+
u32 apic_start = 0;
136+
137+
pcc_comm_addr = acpi_os_ioremap(amd_hfi_data->pcc_chan->shmem_base_addr,
138+
amd_hfi_data->pcc_chan->shmem_size);
139+
if (!pcc_comm_addr) {
140+
dev_err(amd_hfi_data->dev, "failed to ioremap PCC common region mem\n");
141+
return -ENOMEM;
142+
}
143+
144+
memcpy_fromio(amd_hfi_data->shmem, pcc_comm_addr, pcct_ext->length);
145+
iounmap(pcc_comm_addr);
146+
147+
if (amd_hfi_data->shmem->header.signature != PCC_SIGNATURE) {
148+
dev_err(amd_hfi_data->dev, "invalid signature in shared memory\n");
149+
return -EINVAL;
150+
}
151+
if (amd_hfi_data->shmem->version_number != AMD_HETERO_RANKING_TABLE_VER) {
152+
dev_err(amd_hfi_data->dev, "invalid version %d\n",
153+
amd_hfi_data->shmem->version_number);
154+
return -EINVAL;
155+
}
156+
157+
for (unsigned int i = 0; i < amd_hfi_data->shmem->n_bitmaps; i++) {
158+
u32 bitmap = amd_hfi_data->shmem->table_data[i];
159+
160+
for (unsigned int j = 0; j < BITS_PER_TYPE(u32); j++) {
161+
u32 apic_id = i * BITS_PER_TYPE(u32) + j;
162+
struct amd_hfi_cpuinfo *info;
163+
int cpu_index, apic_index;
164+
165+
if (!(bitmap & BIT(j)))
166+
continue;
167+
168+
cpu_index = find_cpu_index_by_apicid(apic_id);
169+
if (cpu_index < 0) {
170+
dev_warn(amd_hfi_data->dev, "APIC ID %u not found\n", apic_id);
171+
continue;
172+
}
173+
174+
info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu_index);
175+
info->apic_id = apic_id;
176+
177+
/* Fill the ranking data for each logical processor */
178+
info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu_index);
179+
apic_index = apic_start * info->nr_class * 2;
180+
for (unsigned int k = 0; k < info->nr_class; k++) {
181+
u32 *table = amd_hfi_data->shmem->table_data +
182+
amd_hfi_data->shmem->n_bitmaps +
183+
i * info->nr_class;
184+
185+
info->amd_hfi_classes[k].eff = table[apic_index + 2 * k];
186+
info->amd_hfi_classes[k].perf = table[apic_index + 2 * k + 1];
187+
}
188+
apic_start++;
189+
}
190+
}
191+
192+
return 0;
193+
}
194+
59195
static int amd_hfi_alloc_class_data(struct platform_device *pdev)
60196
{
61197
struct amd_hfi_cpuinfo *hfi_cpuinfo;
@@ -72,21 +208,79 @@ static int amd_hfi_alloc_class_data(struct platform_device *pdev)
72208

73209
for_each_possible_cpu(idx) {
74210
struct amd_hfi_classes *classes;
211+
int *ipcc_scores;
75212

76213
classes = devm_kcalloc(dev,
77214
nr_class_id,
78215
sizeof(struct amd_hfi_classes),
79216
GFP_KERNEL);
80217
if (!classes)
81218
return -ENOMEM;
219+
ipcc_scores = devm_kcalloc(dev, nr_class_id, sizeof(int), GFP_KERNEL);
220+
if (!ipcc_scores)
221+
return -ENOMEM;
82222
hfi_cpuinfo = per_cpu_ptr(&amd_hfi_cpuinfo, idx);
83223
hfi_cpuinfo->amd_hfi_classes = classes;
224+
hfi_cpuinfo->ipcc_scores = ipcc_scores;
84225
hfi_cpuinfo->nr_class = nr_class_id;
85226
}
86227

87228
return 0;
88229
}
89230

231+
static int amd_hfi_metadata_parser(struct platform_device *pdev,
232+
struct amd_hfi_data *amd_hfi_data)
233+
{
234+
struct acpi_pcct_ext_pcc_slave *pcct_ext;
235+
struct acpi_subtable_header *pcct_entry;
236+
struct mbox_chan *pcc_mbox_channels;
237+
struct acpi_table_header *pcct_tbl;
238+
struct pcc_mbox_chan *pcc_chan;
239+
acpi_status status;
240+
int ret;
241+
242+
pcc_mbox_channels = devm_kcalloc(&pdev->dev, AMD_HFI_MAILBOX_COUNT,
243+
sizeof(*pcc_mbox_channels), GFP_KERNEL);
244+
if (!pcc_mbox_channels)
245+
return -ENOMEM;
246+
247+
pcc_chan = devm_kcalloc(&pdev->dev, AMD_HFI_MAILBOX_COUNT,
248+
sizeof(*pcc_chan), GFP_KERNEL);
249+
if (!pcc_chan)
250+
return -ENOMEM;
251+
252+
status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl);
253+
if (ACPI_FAILURE(status) || !pcct_tbl)
254+
return -ENODEV;
255+
256+
/* get pointer to the first PCC subspace entry */
257+
pcct_entry = (struct acpi_subtable_header *) (
258+
(unsigned long)pcct_tbl + sizeof(struct acpi_table_pcct));
259+
260+
pcc_chan->mchan = &pcc_mbox_channels[0];
261+
262+
amd_hfi_data->pcc_chan = pcc_chan;
263+
amd_hfi_data->pcct_entry = pcct_entry;
264+
pcct_ext = (struct acpi_pcct_ext_pcc_slave *)pcct_entry;
265+
266+
if (pcct_ext->length <= 0)
267+
return -EINVAL;
268+
269+
amd_hfi_data->shmem = devm_kzalloc(amd_hfi_data->dev, pcct_ext->length, GFP_KERNEL);
270+
if (!amd_hfi_data->shmem)
271+
return -ENOMEM;
272+
273+
pcc_chan->shmem_base_addr = pcct_ext->base_address;
274+
pcc_chan->shmem_size = pcct_ext->length;
275+
276+
/* parse the shared memory info from the PCCT table */
277+
ret = amd_hfi_fill_metadata(amd_hfi_data);
278+
279+
acpi_put_table(pcct_tbl);
280+
281+
return ret;
282+
}
283+
90284
static const struct acpi_device_id amd_hfi_platform_match[] = {
91285
{"AMDI0104", 0},
92286
{ }
@@ -112,6 +306,10 @@ static int amd_hfi_probe(struct platform_device *pdev)
112306
if (ret)
113307
return ret;
114308

309+
ret = amd_hfi_metadata_parser(pdev, amd_hfi_data);
310+
if (ret)
311+
return ret;
312+
115313
return 0;
116314
}
117315

0 commit comments

Comments
 (0)