18
18
#include <linux/io.h>
19
19
#include <linux/kernel.h>
20
20
#include <linux/module.h>
21
+ #include <linux/mailbox_client.h>
21
22
#include <linux/mutex.h>
23
+ #include <linux/percpu-defs.h>
22
24
#include <linux/platform_device.h>
23
25
#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>
24
33
25
34
#define AMD_HFI_DRIVER "amd_hfi"
35
+ #define AMD_HFI_MAILBOX_COUNT 1
36
+ #define AMD_HETERO_RANKING_TABLE_VER 2
26
37
27
38
#define AMD_HETERO_CPUID_27 0x80000027
28
39
29
40
static struct platform_device * device ;
30
41
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
+
31
67
struct amd_hfi_data {
32
68
const char * name ;
33
69
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 ;
34
76
};
35
77
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
+ */
36
86
struct amd_hfi_classes {
37
87
u32 perf ;
38
88
u32 eff ;
@@ -41,21 +91,107 @@ struct amd_hfi_classes {
41
91
/**
42
92
* struct amd_hfi_cpuinfo - HFI workload class info per CPU
43
93
* @cpu: CPU index
94
+ * @apic_id: APIC id of the current CPU
44
95
* @class_index: workload class ID index
45
96
* @nr_class: max number of workload class supported
97
+ * @ipcc_scores: ipcc scores for each class
46
98
* @amd_hfi_classes: current CPU workload class ranking data
47
99
*
48
100
* Parameters of a logical processor linked with hardware feedback class.
49
101
*/
50
102
struct amd_hfi_cpuinfo {
51
103
int cpu ;
104
+ u32 apic_id ;
52
105
s16 class_index ;
53
106
u8 nr_class ;
107
+ int * ipcc_scores ;
54
108
struct amd_hfi_classes * amd_hfi_classes ;
55
109
};
56
110
57
111
static DEFINE_PER_CPU (struct amd_hfi_cpuinfo , amd_hfi_cpuinfo ) = {.class_index = -1 };
58
112
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
+
59
195
static int amd_hfi_alloc_class_data (struct platform_device * pdev )
60
196
{
61
197
struct amd_hfi_cpuinfo * hfi_cpuinfo ;
@@ -72,21 +208,79 @@ static int amd_hfi_alloc_class_data(struct platform_device *pdev)
72
208
73
209
for_each_possible_cpu (idx ) {
74
210
struct amd_hfi_classes * classes ;
211
+ int * ipcc_scores ;
75
212
76
213
classes = devm_kcalloc (dev ,
77
214
nr_class_id ,
78
215
sizeof (struct amd_hfi_classes ),
79
216
GFP_KERNEL );
80
217
if (!classes )
81
218
return - ENOMEM ;
219
+ ipcc_scores = devm_kcalloc (dev , nr_class_id , sizeof (int ), GFP_KERNEL );
220
+ if (!ipcc_scores )
221
+ return - ENOMEM ;
82
222
hfi_cpuinfo = per_cpu_ptr (& amd_hfi_cpuinfo , idx );
83
223
hfi_cpuinfo -> amd_hfi_classes = classes ;
224
+ hfi_cpuinfo -> ipcc_scores = ipcc_scores ;
84
225
hfi_cpuinfo -> nr_class = nr_class_id ;
85
226
}
86
227
87
228
return 0 ;
88
229
}
89
230
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
+
90
284
static const struct acpi_device_id amd_hfi_platform_match [] = {
91
285
{"AMDI0104" , 0 },
92
286
{ }
@@ -112,6 +306,10 @@ static int amd_hfi_probe(struct platform_device *pdev)
112
306
if (ret )
113
307
return ret ;
114
308
309
+ ret = amd_hfi_metadata_parser (pdev , amd_hfi_data );
310
+ if (ret )
311
+ return ret ;
312
+
115
313
return 0 ;
116
314
}
117
315
0 commit comments