46
46
#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE
47
47
#define AMD_PMC_RESULT_FAILED 0xFF
48
48
49
+ /* FCH SSC Registers */
50
+ #define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30
51
+ #define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34
52
+ #define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38
53
+ #define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C
54
+ #define FCH_SSC_MAPPING_SIZE 0x800
55
+ #define FCH_BASE_PHY_ADDR_LOW 0xFED81100
56
+ #define FCH_BASE_PHY_ADDR_HIGH 0x00000000
57
+
58
+ /* SMU Message Definations */
59
+ #define SMU_MSG_GETSMUVERSION 0x02
60
+ #define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04
61
+ #define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05
62
+ #define SMU_MSG_LOG_START 0x06
63
+ #define SMU_MSG_LOG_RESET 0x07
64
+ #define SMU_MSG_LOG_DUMP_DATA 0x08
65
+ #define SMU_MSG_GET_SUP_CONSTRAINTS 0x09
49
66
/* List of supported CPU ids */
50
67
#define AMD_CPU_ID_RV 0x15D0
51
68
#define AMD_CPU_ID_RN 0x1630
52
69
#define AMD_CPU_ID_PCO AMD_CPU_ID_RV
53
70
#define AMD_CPU_ID_CZN AMD_CPU_ID_RN
71
+ #define AMD_CPU_ID_YC 0x14B5
54
72
55
- #define AMD_SMU_FW_VERSION 0x0
56
73
#define PMC_MSG_DELAY_MIN_US 100
57
74
#define RESPONSE_REGISTER_LOOP_MAX 200
58
75
76
+ #define SOC_SUBSYSTEM_IP_MAX 12
77
+ #define DELAY_MIN_US 2000
78
+ #define DELAY_MAX_US 3000
59
79
enum amd_pmc_def {
60
80
MSG_TEST = 0x01 ,
61
81
MSG_OS_HINT_PCO ,
62
82
MSG_OS_HINT_RN ,
63
83
};
64
84
85
+ struct amd_pmc_bit_map {
86
+ const char * name ;
87
+ u32 bit_mask ;
88
+ };
89
+
90
+ static const struct amd_pmc_bit_map soc15_ip_blk [] = {
91
+ {"DISPLAY" , BIT (0 )},
92
+ {"CPU" , BIT (1 )},
93
+ {"GFX" , BIT (2 )},
94
+ {"VDD" , BIT (3 )},
95
+ {"ACP" , BIT (4 )},
96
+ {"VCN" , BIT (5 )},
97
+ {"ISP" , BIT (6 )},
98
+ {"NBIO" , BIT (7 )},
99
+ {"DF" , BIT (8 )},
100
+ {"USB0" , BIT (9 )},
101
+ {"USB1" , BIT (10 )},
102
+ {"LAPIC" , BIT (11 )},
103
+ {}
104
+ };
105
+
65
106
struct amd_pmc_dev {
66
107
void __iomem * regbase ;
67
- void __iomem * smu_base ;
108
+ void __iomem * smu_virt_addr ;
109
+ void __iomem * fch_virt_addr ;
68
110
u32 base_addr ;
69
111
u32 cpu_id ;
112
+ u32 active_ips ;
70
113
struct device * dev ;
114
+ struct mutex lock ; /* generic mutex lock */
71
115
#if IS_ENABLED (CONFIG_DEBUG_FS )
72
116
struct dentry * dbgfs_dir ;
73
117
#endif /* CONFIG_DEBUG_FS */
74
118
};
75
119
76
120
static struct amd_pmc_dev pmc ;
121
+ static int amd_pmc_send_cmd (struct amd_pmc_dev * dev , bool set , u32 * data , u8 msg , bool ret );
77
122
78
123
static inline u32 amd_pmc_reg_read (struct amd_pmc_dev * dev , int reg_offset )
79
124
{
@@ -85,18 +130,77 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3
85
130
iowrite32 (val , dev -> regbase + reg_offset );
86
131
}
87
132
133
+ struct smu_metrics {
134
+ u32 table_version ;
135
+ u32 hint_count ;
136
+ u32 s0i3_cyclecount ;
137
+ u32 timein_s0i2 ;
138
+ u64 timeentering_s0i3_lastcapture ;
139
+ u64 timeentering_s0i3_totaltime ;
140
+ u64 timeto_resume_to_os_lastcapture ;
141
+ u64 timeto_resume_to_os_totaltime ;
142
+ u64 timein_s0i3_lastcapture ;
143
+ u64 timein_s0i3_totaltime ;
144
+ u64 timein_swdrips_lastcapture ;
145
+ u64 timein_swdrips_totaltime ;
146
+ u64 timecondition_notmet_lastcapture [SOC_SUBSYSTEM_IP_MAX ];
147
+ u64 timecondition_notmet_totaltime [SOC_SUBSYSTEM_IP_MAX ];
148
+ } __packed ;
149
+
88
150
#ifdef CONFIG_DEBUG_FS
89
151
static int smu_fw_info_show (struct seq_file * s , void * unused )
90
152
{
91
153
struct amd_pmc_dev * dev = s -> private ;
92
- u32 value ;
154
+ struct smu_metrics table ;
155
+ int idx ;
156
+
157
+ if (dev -> cpu_id == AMD_CPU_ID_PCO )
158
+ return - EINVAL ;
159
+
160
+ memcpy_fromio (& table , dev -> smu_virt_addr , sizeof (struct smu_metrics ));
161
+
162
+ seq_puts (s , "\n=== SMU Statistics ===\n" );
163
+ seq_printf (s , "Table Version: %d\n" , table .table_version );
164
+ seq_printf (s , "Hint Count: %d\n" , table .hint_count );
165
+ seq_printf (s , "S0i3 Cycle Count: %d\n" , table .s0i3_cyclecount );
166
+ seq_printf (s , "Time (in us) to S0i3: %lld\n" , table .timeentering_s0i3_lastcapture );
167
+ seq_printf (s , "Time (in us) in S0i3: %lld\n" , table .timein_s0i3_lastcapture );
168
+
169
+ seq_puts (s , "\n=== Active time (in us) ===\n" );
170
+ for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx ++ ) {
171
+ if (soc15_ip_blk [idx ].bit_mask & dev -> active_ips )
172
+ seq_printf (s , "%-8s : %lld\n" , soc15_ip_blk [idx ].name ,
173
+ table .timecondition_notmet_lastcapture [idx ]);
174
+ }
93
175
94
- value = ioread32 (dev -> smu_base + AMD_SMU_FW_VERSION );
95
- seq_printf (s , "SMU FW Info: %x\n" , value );
96
176
return 0 ;
97
177
}
98
178
DEFINE_SHOW_ATTRIBUTE (smu_fw_info );
99
179
180
+ static int s0ix_stats_show (struct seq_file * s , void * unused )
181
+ {
182
+ struct amd_pmc_dev * dev = s -> private ;
183
+ u64 entry_time , exit_time , residency ;
184
+
185
+ entry_time = ioread32 (dev -> fch_virt_addr + FCH_S0I3_ENTRY_TIME_H_OFFSET );
186
+ entry_time = entry_time << 32 | ioread32 (dev -> fch_virt_addr + FCH_S0I3_ENTRY_TIME_L_OFFSET );
187
+
188
+ exit_time = ioread32 (dev -> fch_virt_addr + FCH_S0I3_EXIT_TIME_H_OFFSET );
189
+ exit_time = exit_time << 32 | ioread32 (dev -> fch_virt_addr + FCH_S0I3_EXIT_TIME_L_OFFSET );
190
+
191
+ /* It's in 48MHz. We need to convert it */
192
+ residency = exit_time - entry_time ;
193
+ do_div (residency , 48 );
194
+
195
+ seq_puts (s , "=== S0ix statistics ===\n" );
196
+ seq_printf (s , "S0ix Entry Time: %lld\n" , entry_time );
197
+ seq_printf (s , "S0ix Exit Time: %lld\n" , exit_time );
198
+ seq_printf (s , "Residency Time: %lld\n" , residency );
199
+
200
+ return 0 ;
201
+ }
202
+ DEFINE_SHOW_ATTRIBUTE (s0ix_stats );
203
+
100
204
static void amd_pmc_dbgfs_unregister (struct amd_pmc_dev * dev )
101
205
{
102
206
debugfs_remove_recursive (dev -> dbgfs_dir );
@@ -107,6 +211,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
107
211
dev -> dbgfs_dir = debugfs_create_dir ("amd_pmc" , NULL );
108
212
debugfs_create_file ("smu_fw_info" , 0644 , dev -> dbgfs_dir , dev ,
109
213
& smu_fw_info_fops );
214
+ debugfs_create_file ("s0ix_stats" , 0644 , dev -> dbgfs_dir , dev ,
215
+ & s0ix_stats_fops );
110
216
}
111
217
#else
112
218
static inline void amd_pmc_dbgfs_register (struct amd_pmc_dev * dev )
@@ -118,6 +224,32 @@ static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
118
224
}
119
225
#endif /* CONFIG_DEBUG_FS */
120
226
227
+ static int amd_pmc_setup_smu_logging (struct amd_pmc_dev * dev )
228
+ {
229
+ u32 phys_addr_low , phys_addr_hi ;
230
+ u64 smu_phys_addr ;
231
+
232
+ if (dev -> cpu_id == AMD_CPU_ID_PCO )
233
+ return - EINVAL ;
234
+
235
+ /* Get Active devices list from SMU */
236
+ amd_pmc_send_cmd (dev , 0 , & dev -> active_ips , SMU_MSG_GET_SUP_CONSTRAINTS , 1 );
237
+
238
+ /* Get dram address */
239
+ amd_pmc_send_cmd (dev , 0 , & phys_addr_low , SMU_MSG_LOG_GETDRAM_ADDR_LO , 1 );
240
+ amd_pmc_send_cmd (dev , 0 , & phys_addr_hi , SMU_MSG_LOG_GETDRAM_ADDR_HI , 1 );
241
+ smu_phys_addr = ((u64 )phys_addr_hi << 32 | phys_addr_low );
242
+
243
+ dev -> smu_virt_addr = devm_ioremap (dev -> dev , smu_phys_addr , sizeof (struct smu_metrics ));
244
+ if (!dev -> smu_virt_addr )
245
+ return - ENOMEM ;
246
+
247
+ /* Start the logging */
248
+ amd_pmc_send_cmd (dev , 0 , NULL , SMU_MSG_LOG_START , 0 );
249
+
250
+ return 0 ;
251
+ }
252
+
121
253
static void amd_pmc_dump_registers (struct amd_pmc_dev * dev )
122
254
{
123
255
u32 value ;
@@ -132,19 +264,19 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
132
264
dev_dbg (dev -> dev , "AMD_PMC_REGISTER_MESSAGE:%x\n" , value );
133
265
}
134
266
135
- static int amd_pmc_send_cmd (struct amd_pmc_dev * dev , bool set )
267
+ static int amd_pmc_send_cmd (struct amd_pmc_dev * dev , bool set , u32 * data , u8 msg , bool ret )
136
268
{
137
269
int rc ;
138
- u8 msg ;
139
270
u32 val ;
140
271
272
+ mutex_lock (& dev -> lock );
141
273
/* Wait until we get a valid response */
142
274
rc = readx_poll_timeout (ioread32 , dev -> regbase + AMD_PMC_REGISTER_RESPONSE ,
143
- val , val > 0 , PMC_MSG_DELAY_MIN_US ,
275
+ val , val != 0 , PMC_MSG_DELAY_MIN_US ,
144
276
PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX );
145
277
if (rc ) {
146
278
dev_err (dev -> dev , "failed to talk to SMU\n" );
147
- return rc ;
279
+ goto out_unlock ;
148
280
}
149
281
150
282
/* Write zero to response register */
@@ -154,34 +286,91 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set)
154
286
amd_pmc_reg_write (dev , AMD_PMC_REGISTER_ARGUMENT , set );
155
287
156
288
/* Write message ID to message ID register */
157
- msg = (dev -> cpu_id == AMD_CPU_ID_RN ) ? MSG_OS_HINT_RN : MSG_OS_HINT_PCO ;
158
289
amd_pmc_reg_write (dev , AMD_PMC_REGISTER_MESSAGE , msg );
159
- return 0 ;
290
+
291
+ /* Wait until we get a valid response */
292
+ rc = readx_poll_timeout (ioread32 , dev -> regbase + AMD_PMC_REGISTER_RESPONSE ,
293
+ val , val != 0 , PMC_MSG_DELAY_MIN_US ,
294
+ PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX );
295
+ if (rc ) {
296
+ dev_err (dev -> dev , "SMU response timed out\n" );
297
+ goto out_unlock ;
298
+ }
299
+
300
+ switch (val ) {
301
+ case AMD_PMC_RESULT_OK :
302
+ if (ret ) {
303
+ /* PMFW may take longer time to return back the data */
304
+ usleep_range (DELAY_MIN_US , 10 * DELAY_MAX_US );
305
+ * data = amd_pmc_reg_read (dev , AMD_PMC_REGISTER_ARGUMENT );
306
+ }
307
+ break ;
308
+ case AMD_PMC_RESULT_CMD_REJECT_BUSY :
309
+ dev_err (dev -> dev , "SMU not ready. err: 0x%x\n" , val );
310
+ rc = - EBUSY ;
311
+ goto out_unlock ;
312
+ case AMD_PMC_RESULT_CMD_UNKNOWN :
313
+ dev_err (dev -> dev , "SMU cmd unknown. err: 0x%x\n" , val );
314
+ rc = - EINVAL ;
315
+ goto out_unlock ;
316
+ case AMD_PMC_RESULT_CMD_REJECT_PREREQ :
317
+ case AMD_PMC_RESULT_FAILED :
318
+ default :
319
+ dev_err (dev -> dev , "SMU cmd failed. err: 0x%x\n" , val );
320
+ rc = - EIO ;
321
+ goto out_unlock ;
322
+ }
323
+
324
+ out_unlock :
325
+ mutex_unlock (& dev -> lock );
326
+ amd_pmc_dump_registers (dev );
327
+ return rc ;
328
+ }
329
+
330
+ static int amd_pmc_get_os_hint (struct amd_pmc_dev * dev )
331
+ {
332
+ switch (dev -> cpu_id ) {
333
+ case AMD_CPU_ID_PCO :
334
+ return MSG_OS_HINT_PCO ;
335
+ case AMD_CPU_ID_RN :
336
+ case AMD_CPU_ID_YC :
337
+ return MSG_OS_HINT_RN ;
338
+ }
339
+ return - EINVAL ;
160
340
}
161
341
162
342
static int __maybe_unused amd_pmc_suspend (struct device * dev )
163
343
{
164
344
struct amd_pmc_dev * pdev = dev_get_drvdata (dev );
165
345
int rc ;
346
+ u8 msg ;
347
+
348
+ /* Reset and Start SMU logging - to monitor the s0i3 stats */
349
+ amd_pmc_send_cmd (pdev , 0 , NULL , SMU_MSG_LOG_RESET , 0 );
350
+ amd_pmc_send_cmd (pdev , 0 , NULL , SMU_MSG_LOG_START , 0 );
166
351
167
- rc = amd_pmc_send_cmd (pdev , 1 );
352
+ msg = amd_pmc_get_os_hint (pdev );
353
+ rc = amd_pmc_send_cmd (pdev , 1 , NULL , msg , 0 );
168
354
if (rc )
169
355
dev_err (pdev -> dev , "suspend failed\n" );
170
356
171
- amd_pmc_dump_registers (pdev );
172
- return 0 ;
357
+ return rc ;
173
358
}
174
359
175
360
static int __maybe_unused amd_pmc_resume (struct device * dev )
176
361
{
177
362
struct amd_pmc_dev * pdev = dev_get_drvdata (dev );
178
363
int rc ;
364
+ u8 msg ;
365
+
366
+ /* Let SMU know that we are looking for stats */
367
+ amd_pmc_send_cmd (pdev , 0 , NULL , SMU_MSG_LOG_DUMP_DATA , 0 );
179
368
180
- rc = amd_pmc_send_cmd (pdev , 0 );
369
+ msg = amd_pmc_get_os_hint (pdev );
370
+ rc = amd_pmc_send_cmd (pdev , 0 , NULL , msg , 0 );
181
371
if (rc )
182
372
dev_err (pdev -> dev , "resume failed\n" );
183
373
184
- amd_pmc_dump_registers (pdev );
185
374
return 0 ;
186
375
}
187
376
@@ -190,6 +379,7 @@ static const struct dev_pm_ops amd_pmc_pm_ops = {
190
379
};
191
380
192
381
static const struct pci_device_id pmc_pci_ids [] = {
382
+ { PCI_DEVICE (PCI_VENDOR_ID_AMD , AMD_CPU_ID_YC ) },
193
383
{ PCI_DEVICE (PCI_VENDOR_ID_AMD , AMD_CPU_ID_CZN ) },
194
384
{ PCI_DEVICE (PCI_VENDOR_ID_AMD , AMD_CPU_ID_RN ) },
195
385
{ PCI_DEVICE (PCI_VENDOR_ID_AMD , AMD_CPU_ID_PCO ) },
@@ -201,9 +391,8 @@ static int amd_pmc_probe(struct platform_device *pdev)
201
391
{
202
392
struct amd_pmc_dev * dev = & pmc ;
203
393
struct pci_dev * rdev ;
204
- u32 base_addr_lo ;
205
- u32 base_addr_hi ;
206
- u64 base_addr ;
394
+ u32 base_addr_lo , base_addr_hi ;
395
+ u64 base_addr , fch_phys_addr ;
207
396
int err ;
208
397
u32 val ;
209
398
@@ -248,16 +437,25 @@ static int amd_pmc_probe(struct platform_device *pdev)
248
437
pci_dev_put (rdev );
249
438
base_addr = ((u64 )base_addr_hi << 32 | base_addr_lo );
250
439
251
- dev -> smu_base = devm_ioremap (dev -> dev , base_addr , AMD_PMC_MAPPING_SIZE );
252
- if (!dev -> smu_base )
253
- return - ENOMEM ;
254
-
255
440
dev -> regbase = devm_ioremap (dev -> dev , base_addr + AMD_PMC_BASE_ADDR_OFFSET ,
256
441
AMD_PMC_MAPPING_SIZE );
257
442
if (!dev -> regbase )
258
443
return - ENOMEM ;
259
444
260
- amd_pmc_dump_registers (dev );
445
+ mutex_init (& dev -> lock );
446
+
447
+ /* Use FCH registers to get the S0ix stats */
448
+ base_addr_lo = FCH_BASE_PHY_ADDR_LOW ;
449
+ base_addr_hi = FCH_BASE_PHY_ADDR_HIGH ;
450
+ fch_phys_addr = ((u64 )base_addr_hi << 32 | base_addr_lo );
451
+ dev -> fch_virt_addr = devm_ioremap (dev -> dev , fch_phys_addr , FCH_SSC_MAPPING_SIZE );
452
+ if (!dev -> fch_virt_addr )
453
+ return - ENOMEM ;
454
+
455
+ /* Use SMU to get the s0i3 debug stats */
456
+ err = amd_pmc_setup_smu_logging (dev );
457
+ if (err )
458
+ dev_err (dev -> dev , "SMU debugging info not supported on this platform\n" );
261
459
262
460
platform_set_drvdata (pdev , dev );
263
461
amd_pmc_dbgfs_register (dev );
@@ -269,11 +467,14 @@ static int amd_pmc_remove(struct platform_device *pdev)
269
467
struct amd_pmc_dev * dev = platform_get_drvdata (pdev );
270
468
271
469
amd_pmc_dbgfs_unregister (dev );
470
+ mutex_destroy (& dev -> lock );
272
471
return 0 ;
273
472
}
274
473
275
474
static const struct acpi_device_id amd_pmc_acpi_ids [] = {
276
475
{"AMDI0005" , 0 },
476
+ {"AMDI0006" , 0 },
477
+ {"AMDI0007" , 0 },
277
478
{"AMD0004" , 0 },
278
479
{ }
279
480
};
0 commit comments