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
2940static 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+
3167struct 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+ */
3686struct 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 */
50102struct 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
57111static 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+
59195static 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+
90284static 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