]>
Commit | Line | Data |
---|---|---|
75758255 AD |
1 | /* |
2 | * Copyright 2008 Advanced Micro Devices, Inc. | |
3 | * Copyright 2008 Red Hat Inc. | |
4 | * Copyright 2009 Jerome Glisse. | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a | |
7 | * copy of this software and associated documentation files (the "Software"), | |
8 | * to deal in the Software without restriction, including without limitation | |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
10 | * and/or sell copies of the Software, and to permit persons to whom the | |
11 | * Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
22 | * OTHER DEALINGS IN THE SOFTWARE. | |
23 | * | |
24 | */ | |
25 | ||
26 | #include <linux/kthread.h> | |
27 | #include <drm/drmP.h> | |
28 | #include <linux/debugfs.h> | |
29 | #include "amdgpu.h" | |
30 | ||
7e4237db TSD |
31 | /** |
32 | * amdgpu_debugfs_add_files - Add simple debugfs entries | |
33 | * | |
34 | * @adev: Device to attach debugfs entries to | |
35 | * @files: Array of function callbacks that respond to reads | |
36 | * @nfiles: Number of callbacks to register | |
37 | * | |
75758255 AD |
38 | */ |
39 | int amdgpu_debugfs_add_files(struct amdgpu_device *adev, | |
40 | const struct drm_info_list *files, | |
41 | unsigned nfiles) | |
42 | { | |
43 | unsigned i; | |
44 | ||
45 | for (i = 0; i < adev->debugfs_count; i++) { | |
46 | if (adev->debugfs[i].files == files) { | |
47 | /* Already registered */ | |
48 | return 0; | |
49 | } | |
50 | } | |
51 | ||
52 | i = adev->debugfs_count + 1; | |
53 | if (i > AMDGPU_DEBUGFS_MAX_COMPONENTS) { | |
54 | DRM_ERROR("Reached maximum number of debugfs components.\n"); | |
55 | DRM_ERROR("Report so we increase " | |
56 | "AMDGPU_DEBUGFS_MAX_COMPONENTS.\n"); | |
57 | return -EINVAL; | |
58 | } | |
59 | adev->debugfs[adev->debugfs_count].files = files; | |
60 | adev->debugfs[adev->debugfs_count].num_files = nfiles; | |
61 | adev->debugfs_count = i; | |
62 | #if defined(CONFIG_DEBUG_FS) | |
63 | drm_debugfs_create_files(files, nfiles, | |
64 | adev->ddev->primary->debugfs_root, | |
65 | adev->ddev->primary); | |
66 | #endif | |
67 | return 0; | |
68 | } | |
69 | ||
70 | #if defined(CONFIG_DEBUG_FS) | |
71 | ||
7e4237db TSD |
72 | /** |
73 | * amdgpu_debugfs_process_reg_op - Handle MMIO register reads/writes | |
74 | * | |
75 | * @read: True if reading | |
76 | * @f: open file handle | |
77 | * @buf: User buffer to write/read to | |
78 | * @size: Number of bytes to write/read | |
79 | * @pos: Offset to seek to | |
80 | * | |
81 | * This debugfs entry has special meaning on the offset being sought. | |
82 | * Various bits have different meanings: | |
83 | * | |
84 | * Bit 62: Indicates a GRBM bank switch is needed | |
85 | * Bit 61: Indicates a SRBM bank switch is needed (implies bit 62 is | |
86 | * zero) | |
87 | * Bits 24..33: The SE or ME selector if needed | |
88 | * Bits 34..43: The SH (or SA) or PIPE selector if needed | |
89 | * Bits 44..53: The INSTANCE (or CU/WGP) or QUEUE selector if needed | |
90 | * | |
91 | * Bit 23: Indicates that the PM power gating lock should be held | |
92 | * This is necessary to read registers that might be | |
93 | * unreliable during a power gating transistion. | |
94 | * | |
95 | * The lower bits are the BYTE offset of the register to read. This | |
96 | * allows reading multiple registers in a single call and having | |
97 | * the returned size reflect that. | |
98 | */ | |
f7a9ee81 AG |
99 | static int amdgpu_debugfs_process_reg_op(bool read, struct file *f, |
100 | char __user *buf, size_t size, loff_t *pos) | |
75758255 AD |
101 | { |
102 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
103 | ssize_t result = 0; | |
104 | int r; | |
f7a9ee81 AG |
105 | bool pm_pg_lock, use_bank, use_ring; |
106 | unsigned instance_bank, sh_bank, se_bank, me, pipe, queue; | |
75758255 | 107 | |
f7a9ee81 AG |
108 | pm_pg_lock = use_bank = use_ring = false; |
109 | instance_bank = sh_bank = se_bank = me = pipe = queue = 0; | |
110 | ||
111 | if (size & 0x3 || *pos & 0x3 || | |
112 | ((*pos & (1ULL << 62)) && (*pos & (1ULL << 61)))) | |
75758255 AD |
113 | return -EINVAL; |
114 | ||
115 | /* are we reading registers for which a PG lock is necessary? */ | |
116 | pm_pg_lock = (*pos >> 23) & 1; | |
117 | ||
118 | if (*pos & (1ULL << 62)) { | |
119 | se_bank = (*pos & GENMASK_ULL(33, 24)) >> 24; | |
120 | sh_bank = (*pos & GENMASK_ULL(43, 34)) >> 34; | |
121 | instance_bank = (*pos & GENMASK_ULL(53, 44)) >> 44; | |
122 | ||
123 | if (se_bank == 0x3FF) | |
124 | se_bank = 0xFFFFFFFF; | |
125 | if (sh_bank == 0x3FF) | |
126 | sh_bank = 0xFFFFFFFF; | |
127 | if (instance_bank == 0x3FF) | |
128 | instance_bank = 0xFFFFFFFF; | |
129 | use_bank = 1; | |
f7a9ee81 AG |
130 | } else if (*pos & (1ULL << 61)) { |
131 | ||
132 | me = (*pos & GENMASK_ULL(33, 24)) >> 24; | |
133 | pipe = (*pos & GENMASK_ULL(43, 34)) >> 34; | |
134 | queue = (*pos & GENMASK_ULL(53, 44)) >> 44; | |
135 | ||
136 | use_ring = 1; | |
75758255 | 137 | } else { |
f7a9ee81 | 138 | use_bank = use_ring = 0; |
75758255 AD |
139 | } |
140 | ||
141 | *pos &= (1UL << 22) - 1; | |
142 | ||
143 | if (use_bank) { | |
144 | if ((sh_bank != 0xFFFFFFFF && sh_bank >= adev->gfx.config.max_sh_per_se) || | |
145 | (se_bank != 0xFFFFFFFF && se_bank >= adev->gfx.config.max_shader_engines)) | |
146 | return -EINVAL; | |
147 | mutex_lock(&adev->grbm_idx_mutex); | |
148 | amdgpu_gfx_select_se_sh(adev, se_bank, | |
149 | sh_bank, instance_bank); | |
f7a9ee81 AG |
150 | } else if (use_ring) { |
151 | mutex_lock(&adev->srbm_mutex); | |
152 | amdgpu_gfx_select_me_pipe_q(adev, me, pipe, queue); | |
75758255 AD |
153 | } |
154 | ||
155 | if (pm_pg_lock) | |
156 | mutex_lock(&adev->pm.mutex); | |
157 | ||
158 | while (size) { | |
159 | uint32_t value; | |
160 | ||
f7a9ee81 AG |
161 | if (read) { |
162 | value = RREG32(*pos >> 2); | |
163 | r = put_user(value, (uint32_t *)buf); | |
164 | } else { | |
165 | r = get_user(value, (uint32_t *)buf); | |
166 | if (!r) | |
167 | WREG32(*pos >> 2, value); | |
168 | } | |
75758255 AD |
169 | if (r) { |
170 | result = r; | |
171 | goto end; | |
172 | } | |
173 | ||
174 | result += 4; | |
175 | buf += 4; | |
176 | *pos += 4; | |
177 | size -= 4; | |
178 | } | |
179 | ||
180 | end: | |
181 | if (use_bank) { | |
182 | amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); | |
183 | mutex_unlock(&adev->grbm_idx_mutex); | |
f7a9ee81 AG |
184 | } else if (use_ring) { |
185 | amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0); | |
186 | mutex_unlock(&adev->srbm_mutex); | |
75758255 AD |
187 | } |
188 | ||
189 | if (pm_pg_lock) | |
190 | mutex_unlock(&adev->pm.mutex); | |
191 | ||
192 | return result; | |
193 | } | |
194 | ||
7e4237db TSD |
195 | /** |
196 | * amdgpu_debugfs_regs_read - Callback for reading MMIO registers | |
197 | */ | |
f7a9ee81 AG |
198 | static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf, |
199 | size_t size, loff_t *pos) | |
200 | { | |
201 | return amdgpu_debugfs_process_reg_op(true, f, buf, size, pos); | |
202 | } | |
203 | ||
7e4237db TSD |
204 | /** |
205 | * amdgpu_debugfs_regs_write - Callback for writing MMIO registers | |
206 | */ | |
75758255 AD |
207 | static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf, |
208 | size_t size, loff_t *pos) | |
209 | { | |
f7a9ee81 | 210 | return amdgpu_debugfs_process_reg_op(false, f, (char __user *)buf, size, pos); |
75758255 AD |
211 | } |
212 | ||
7e4237db TSD |
213 | |
214 | /** | |
215 | * amdgpu_debugfs_regs_pcie_read - Read from a PCIE register | |
216 | * | |
217 | * @f: open file handle | |
218 | * @buf: User buffer to store read data in | |
219 | * @size: Number of bytes to read | |
220 | * @pos: Offset to seek to | |
221 | * | |
222 | * The lower bits are the BYTE offset of the register to read. This | |
223 | * allows reading multiple registers in a single call and having | |
224 | * the returned size reflect that. | |
225 | */ | |
75758255 AD |
226 | static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, |
227 | size_t size, loff_t *pos) | |
228 | { | |
229 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
230 | ssize_t result = 0; | |
231 | int r; | |
232 | ||
233 | if (size & 0x3 || *pos & 0x3) | |
234 | return -EINVAL; | |
235 | ||
236 | while (size) { | |
237 | uint32_t value; | |
238 | ||
239 | value = RREG32_PCIE(*pos >> 2); | |
240 | r = put_user(value, (uint32_t *)buf); | |
241 | if (r) | |
242 | return r; | |
243 | ||
244 | result += 4; | |
245 | buf += 4; | |
246 | *pos += 4; | |
247 | size -= 4; | |
248 | } | |
249 | ||
250 | return result; | |
251 | } | |
252 | ||
7e4237db TSD |
253 | /** |
254 | * amdgpu_debugfs_regs_pcie_write - Write to a PCIE register | |
255 | * | |
256 | * @f: open file handle | |
257 | * @buf: User buffer to write data from | |
258 | * @size: Number of bytes to write | |
259 | * @pos: Offset to seek to | |
260 | * | |
261 | * The lower bits are the BYTE offset of the register to write. This | |
262 | * allows writing multiple registers in a single call and having | |
263 | * the returned size reflect that. | |
264 | */ | |
75758255 AD |
265 | static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user *buf, |
266 | size_t size, loff_t *pos) | |
267 | { | |
268 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
269 | ssize_t result = 0; | |
270 | int r; | |
271 | ||
272 | if (size & 0x3 || *pos & 0x3) | |
273 | return -EINVAL; | |
274 | ||
275 | while (size) { | |
276 | uint32_t value; | |
277 | ||
278 | r = get_user(value, (uint32_t *)buf); | |
279 | if (r) | |
280 | return r; | |
281 | ||
282 | WREG32_PCIE(*pos >> 2, value); | |
283 | ||
284 | result += 4; | |
285 | buf += 4; | |
286 | *pos += 4; | |
287 | size -= 4; | |
288 | } | |
289 | ||
290 | return result; | |
291 | } | |
292 | ||
7e4237db TSD |
293 | /** |
294 | * amdgpu_debugfs_regs_didt_read - Read from a DIDT register | |
295 | * | |
296 | * @f: open file handle | |
297 | * @buf: User buffer to store read data in | |
298 | * @size: Number of bytes to read | |
299 | * @pos: Offset to seek to | |
300 | * | |
301 | * The lower bits are the BYTE offset of the register to read. This | |
302 | * allows reading multiple registers in a single call and having | |
303 | * the returned size reflect that. | |
304 | */ | |
75758255 AD |
305 | static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, |
306 | size_t size, loff_t *pos) | |
307 | { | |
308 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
309 | ssize_t result = 0; | |
310 | int r; | |
311 | ||
312 | if (size & 0x3 || *pos & 0x3) | |
313 | return -EINVAL; | |
314 | ||
315 | while (size) { | |
316 | uint32_t value; | |
317 | ||
318 | value = RREG32_DIDT(*pos >> 2); | |
319 | r = put_user(value, (uint32_t *)buf); | |
320 | if (r) | |
321 | return r; | |
322 | ||
323 | result += 4; | |
324 | buf += 4; | |
325 | *pos += 4; | |
326 | size -= 4; | |
327 | } | |
328 | ||
329 | return result; | |
330 | } | |
331 | ||
7e4237db TSD |
332 | /** |
333 | * amdgpu_debugfs_regs_didt_write - Write to a DIDT register | |
334 | * | |
335 | * @f: open file handle | |
336 | * @buf: User buffer to write data from | |
337 | * @size: Number of bytes to write | |
338 | * @pos: Offset to seek to | |
339 | * | |
340 | * The lower bits are the BYTE offset of the register to write. This | |
341 | * allows writing multiple registers in a single call and having | |
342 | * the returned size reflect that. | |
343 | */ | |
75758255 AD |
344 | static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user *buf, |
345 | size_t size, loff_t *pos) | |
346 | { | |
347 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
348 | ssize_t result = 0; | |
349 | int r; | |
350 | ||
351 | if (size & 0x3 || *pos & 0x3) | |
352 | return -EINVAL; | |
353 | ||
354 | while (size) { | |
355 | uint32_t value; | |
356 | ||
357 | r = get_user(value, (uint32_t *)buf); | |
358 | if (r) | |
359 | return r; | |
360 | ||
361 | WREG32_DIDT(*pos >> 2, value); | |
362 | ||
363 | result += 4; | |
364 | buf += 4; | |
365 | *pos += 4; | |
366 | size -= 4; | |
367 | } | |
368 | ||
369 | return result; | |
370 | } | |
371 | ||
7e4237db TSD |
372 | /** |
373 | * amdgpu_debugfs_regs_smc_read - Read from a SMC register | |
374 | * | |
375 | * @f: open file handle | |
376 | * @buf: User buffer to store read data in | |
377 | * @size: Number of bytes to read | |
378 | * @pos: Offset to seek to | |
379 | * | |
380 | * The lower bits are the BYTE offset of the register to read. This | |
381 | * allows reading multiple registers in a single call and having | |
382 | * the returned size reflect that. | |
383 | */ | |
75758255 AD |
384 | static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, |
385 | size_t size, loff_t *pos) | |
386 | { | |
387 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
388 | ssize_t result = 0; | |
389 | int r; | |
390 | ||
391 | if (size & 0x3 || *pos & 0x3) | |
392 | return -EINVAL; | |
393 | ||
394 | while (size) { | |
395 | uint32_t value; | |
396 | ||
397 | value = RREG32_SMC(*pos); | |
398 | r = put_user(value, (uint32_t *)buf); | |
399 | if (r) | |
400 | return r; | |
401 | ||
402 | result += 4; | |
403 | buf += 4; | |
404 | *pos += 4; | |
405 | size -= 4; | |
406 | } | |
407 | ||
408 | return result; | |
409 | } | |
410 | ||
7e4237db TSD |
411 | /** |
412 | * amdgpu_debugfs_regs_smc_write - Write to a SMC register | |
413 | * | |
414 | * @f: open file handle | |
415 | * @buf: User buffer to write data from | |
416 | * @size: Number of bytes to write | |
417 | * @pos: Offset to seek to | |
418 | * | |
419 | * The lower bits are the BYTE offset of the register to write. This | |
420 | * allows writing multiple registers in a single call and having | |
421 | * the returned size reflect that. | |
422 | */ | |
75758255 AD |
423 | static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *buf, |
424 | size_t size, loff_t *pos) | |
425 | { | |
426 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
427 | ssize_t result = 0; | |
428 | int r; | |
429 | ||
430 | if (size & 0x3 || *pos & 0x3) | |
431 | return -EINVAL; | |
432 | ||
433 | while (size) { | |
434 | uint32_t value; | |
435 | ||
436 | r = get_user(value, (uint32_t *)buf); | |
437 | if (r) | |
438 | return r; | |
439 | ||
440 | WREG32_SMC(*pos, value); | |
441 | ||
442 | result += 4; | |
443 | buf += 4; | |
444 | *pos += 4; | |
445 | size -= 4; | |
446 | } | |
447 | ||
448 | return result; | |
449 | } | |
450 | ||
7e4237db TSD |
451 | /** |
452 | * amdgpu_debugfs_gca_config_read - Read from gfx config data | |
453 | * | |
454 | * @f: open file handle | |
455 | * @buf: User buffer to store read data in | |
456 | * @size: Number of bytes to read | |
457 | * @pos: Offset to seek to | |
458 | * | |
459 | * This file is used to access configuration data in a somewhat | |
460 | * stable fashion. The format is a series of DWORDs with the first | |
461 | * indicating which revision it is. New content is appended to the | |
462 | * end so that older software can still read the data. | |
463 | */ | |
464 | ||
75758255 AD |
465 | static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf, |
466 | size_t size, loff_t *pos) | |
467 | { | |
468 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
469 | ssize_t result = 0; | |
470 | int r; | |
471 | uint32_t *config, no_regs = 0; | |
472 | ||
473 | if (size & 0x3 || *pos & 0x3) | |
474 | return -EINVAL; | |
475 | ||
476 | config = kmalloc_array(256, sizeof(*config), GFP_KERNEL); | |
477 | if (!config) | |
478 | return -ENOMEM; | |
479 | ||
480 | /* version, increment each time something is added */ | |
481 | config[no_regs++] = 3; | |
482 | config[no_regs++] = adev->gfx.config.max_shader_engines; | |
483 | config[no_regs++] = adev->gfx.config.max_tile_pipes; | |
484 | config[no_regs++] = adev->gfx.config.max_cu_per_sh; | |
485 | config[no_regs++] = adev->gfx.config.max_sh_per_se; | |
486 | config[no_regs++] = adev->gfx.config.max_backends_per_se; | |
487 | config[no_regs++] = adev->gfx.config.max_texture_channel_caches; | |
488 | config[no_regs++] = adev->gfx.config.max_gprs; | |
489 | config[no_regs++] = adev->gfx.config.max_gs_threads; | |
490 | config[no_regs++] = adev->gfx.config.max_hw_contexts; | |
491 | config[no_regs++] = adev->gfx.config.sc_prim_fifo_size_frontend; | |
492 | config[no_regs++] = adev->gfx.config.sc_prim_fifo_size_backend; | |
493 | config[no_regs++] = adev->gfx.config.sc_hiz_tile_fifo_size; | |
494 | config[no_regs++] = adev->gfx.config.sc_earlyz_tile_fifo_size; | |
495 | config[no_regs++] = adev->gfx.config.num_tile_pipes; | |
496 | config[no_regs++] = adev->gfx.config.backend_enable_mask; | |
497 | config[no_regs++] = adev->gfx.config.mem_max_burst_length_bytes; | |
498 | config[no_regs++] = adev->gfx.config.mem_row_size_in_kb; | |
499 | config[no_regs++] = adev->gfx.config.shader_engine_tile_size; | |
500 | config[no_regs++] = adev->gfx.config.num_gpus; | |
501 | config[no_regs++] = adev->gfx.config.multi_gpu_tile_size; | |
502 | config[no_regs++] = adev->gfx.config.mc_arb_ramcfg; | |
503 | config[no_regs++] = adev->gfx.config.gb_addr_config; | |
504 | config[no_regs++] = adev->gfx.config.num_rbs; | |
505 | ||
506 | /* rev==1 */ | |
507 | config[no_regs++] = adev->rev_id; | |
508 | config[no_regs++] = adev->pg_flags; | |
509 | config[no_regs++] = adev->cg_flags; | |
510 | ||
511 | /* rev==2 */ | |
512 | config[no_regs++] = adev->family; | |
513 | config[no_regs++] = adev->external_rev_id; | |
514 | ||
515 | /* rev==3 */ | |
516 | config[no_regs++] = adev->pdev->device; | |
517 | config[no_regs++] = adev->pdev->revision; | |
518 | config[no_regs++] = adev->pdev->subsystem_device; | |
519 | config[no_regs++] = adev->pdev->subsystem_vendor; | |
520 | ||
521 | while (size && (*pos < no_regs * 4)) { | |
522 | uint32_t value; | |
523 | ||
524 | value = config[*pos >> 2]; | |
525 | r = put_user(value, (uint32_t *)buf); | |
526 | if (r) { | |
527 | kfree(config); | |
528 | return r; | |
529 | } | |
530 | ||
531 | result += 4; | |
532 | buf += 4; | |
533 | *pos += 4; | |
534 | size -= 4; | |
535 | } | |
536 | ||
537 | kfree(config); | |
538 | return result; | |
539 | } | |
540 | ||
7e4237db TSD |
541 | /** |
542 | * amdgpu_debugfs_sensor_read - Read from the powerplay sensors | |
543 | * | |
544 | * @f: open file handle | |
545 | * @buf: User buffer to store read data in | |
546 | * @size: Number of bytes to read | |
547 | * @pos: Offset to seek to | |
548 | * | |
549 | * The offset is treated as the BYTE address of one of the sensors | |
550 | * enumerated in amd/include/kgd_pp_interface.h under the | |
551 | * 'amd_pp_sensors' enumeration. For instance to read the UVD VCLK | |
552 | * you would use the offset 3 * 4 = 12. | |
553 | */ | |
75758255 AD |
554 | static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf, |
555 | size_t size, loff_t *pos) | |
556 | { | |
557 | struct amdgpu_device *adev = file_inode(f)->i_private; | |
558 | int idx, x, outsize, r, valuesize; | |
559 | uint32_t values[16]; | |
560 | ||
561 | if (size & 3 || *pos & 0x3) | |
562 | return -EINVAL; | |
563 | ||
b13aa109 | 564 | if (!adev->pm.dpm_enabled) |
75758255 AD |
565 | return -EINVAL; |
566 | ||
567 | /* convert offset to sensor number */ | |
568 | idx = *pos >> 2; | |
569 | ||
570 | valuesize = sizeof(values); | |
4a5a2de6 KW |
571 | r = amdgpu_dpm_read_sensor(adev, idx, &values[0], &valuesize); |
572 | if (r) | |
573 | return r; | |
75758255 AD |
574 | |
575 | if (size > valuesize) | |
576 | return -EINVAL; | |
577 | ||
578 | outsize = 0; | |
579 | x = 0; | |
580 | if (!r) { | |
581 | while (size) { | |
582 | r = put_user(values[x++], (int32_t *)buf); | |
583 | buf += 4; | |
584 | size -= 4; | |
585 | outsize += 4; | |
586 | } | |
587 | } | |
588 | ||
589 | return !r ? outsize : r; | |
590 | } | |
591 | ||
7e4237db TSD |
592 | /** amdgpu_debugfs_wave_read - Read WAVE STATUS data |
593 | * | |
594 | * @f: open file handle | |
595 | * @buf: User buffer to store read data in | |
596 | * @size: Number of bytes to read | |
597 | * @pos: Offset to seek to | |
598 | * | |
599 | * The offset being sought changes which wave that the status data | |
600 | * will be returned for. The bits are used as follows: | |
601 | * | |
602 | * Bits 0..6: Byte offset into data | |
603 | * Bits 7..14: SE selector | |
604 | * Bits 15..22: SH/SA selector | |
605 | * Bits 23..30: CU/{WGP+SIMD} selector | |
606 | * Bits 31..36: WAVE ID selector | |
607 | * Bits 37..44: SIMD ID selector | |
608 | * | |
609 | * The returned data begins with one DWORD of version information | |
610 | * Followed by WAVE STATUS registers relevant to the GFX IP version | |
611 | * being used. See gfx_v8_0_read_wave_data() for an example output. | |
612 | */ | |
75758255 AD |
613 | static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf, |
614 | size_t size, loff_t *pos) | |
615 | { | |
616 | struct amdgpu_device *adev = f->f_inode->i_private; | |
617 | int r, x; | |
618 | ssize_t result=0; | |
619 | uint32_t offset, se, sh, cu, wave, simd, data[32]; | |
620 | ||
621 | if (size & 3 || *pos & 3) | |
622 | return -EINVAL; | |
623 | ||
624 | /* decode offset */ | |
625 | offset = (*pos & GENMASK_ULL(6, 0)); | |
626 | se = (*pos & GENMASK_ULL(14, 7)) >> 7; | |
627 | sh = (*pos & GENMASK_ULL(22, 15)) >> 15; | |
628 | cu = (*pos & GENMASK_ULL(30, 23)) >> 23; | |
629 | wave = (*pos & GENMASK_ULL(36, 31)) >> 31; | |
630 | simd = (*pos & GENMASK_ULL(44, 37)) >> 37; | |
631 | ||
632 | /* switch to the specific se/sh/cu */ | |
633 | mutex_lock(&adev->grbm_idx_mutex); | |
634 | amdgpu_gfx_select_se_sh(adev, se, sh, cu); | |
635 | ||
636 | x = 0; | |
637 | if (adev->gfx.funcs->read_wave_data) | |
638 | adev->gfx.funcs->read_wave_data(adev, simd, wave, data, &x); | |
639 | ||
640 | amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); | |
641 | mutex_unlock(&adev->grbm_idx_mutex); | |
642 | ||
643 | if (!x) | |
644 | return -EINVAL; | |
645 | ||
646 | while (size && (offset < x * 4)) { | |
647 | uint32_t value; | |
648 | ||
649 | value = data[offset >> 2]; | |
650 | r = put_user(value, (uint32_t *)buf); | |
651 | if (r) | |
652 | return r; | |
653 | ||
654 | result += 4; | |
655 | buf += 4; | |
656 | offset += 4; | |
657 | size -= 4; | |
658 | } | |
659 | ||
660 | return result; | |
661 | } | |
662 | ||
7e4237db TSD |
663 | /** amdgpu_debugfs_gpr_read - Read wave gprs |
664 | * | |
665 | * @f: open file handle | |
666 | * @buf: User buffer to store read data in | |
667 | * @size: Number of bytes to read | |
668 | * @pos: Offset to seek to | |
669 | * | |
670 | * The offset being sought changes which wave that the status data | |
671 | * will be returned for. The bits are used as follows: | |
672 | * | |
673 | * Bits 0..11: Byte offset into data | |
674 | * Bits 12..19: SE selector | |
675 | * Bits 20..27: SH/SA selector | |
676 | * Bits 28..35: CU/{WGP+SIMD} selector | |
677 | * Bits 36..43: WAVE ID selector | |
678 | * Bits 37..44: SIMD ID selector | |
679 | * Bits 52..59: Thread selector | |
680 | * Bits 60..61: Bank selector (VGPR=0,SGPR=1) | |
681 | * | |
682 | * The return data comes from the SGPR or VGPR register bank for | |
683 | * the selected operational unit. | |
684 | */ | |
75758255 AD |
685 | static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf, |
686 | size_t size, loff_t *pos) | |
687 | { | |
688 | struct amdgpu_device *adev = f->f_inode->i_private; | |
689 | int r; | |
690 | ssize_t result = 0; | |
691 | uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data; | |
692 | ||
693 | if (size & 3 || *pos & 3) | |
694 | return -EINVAL; | |
695 | ||
696 | /* decode offset */ | |
697 | offset = *pos & GENMASK_ULL(11, 0); | |
698 | se = (*pos & GENMASK_ULL(19, 12)) >> 12; | |
699 | sh = (*pos & GENMASK_ULL(27, 20)) >> 20; | |
700 | cu = (*pos & GENMASK_ULL(35, 28)) >> 28; | |
701 | wave = (*pos & GENMASK_ULL(43, 36)) >> 36; | |
702 | simd = (*pos & GENMASK_ULL(51, 44)) >> 44; | |
703 | thread = (*pos & GENMASK_ULL(59, 52)) >> 52; | |
704 | bank = (*pos & GENMASK_ULL(61, 60)) >> 60; | |
705 | ||
706 | data = kmalloc_array(1024, sizeof(*data), GFP_KERNEL); | |
707 | if (!data) | |
708 | return -ENOMEM; | |
709 | ||
710 | /* switch to the specific se/sh/cu */ | |
711 | mutex_lock(&adev->grbm_idx_mutex); | |
712 | amdgpu_gfx_select_se_sh(adev, se, sh, cu); | |
713 | ||
714 | if (bank == 0) { | |
715 | if (adev->gfx.funcs->read_wave_vgprs) | |
716 | adev->gfx.funcs->read_wave_vgprs(adev, simd, wave, thread, offset, size>>2, data); | |
717 | } else { | |
718 | if (adev->gfx.funcs->read_wave_sgprs) | |
719 | adev->gfx.funcs->read_wave_sgprs(adev, simd, wave, offset, size>>2, data); | |
720 | } | |
721 | ||
722 | amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); | |
723 | mutex_unlock(&adev->grbm_idx_mutex); | |
724 | ||
725 | while (size) { | |
726 | uint32_t value; | |
727 | ||
728 | value = data[offset++]; | |
729 | r = put_user(value, (uint32_t *)buf); | |
730 | if (r) { | |
731 | result = r; | |
732 | goto err; | |
733 | } | |
734 | ||
735 | result += 4; | |
736 | buf += 4; | |
737 | size -= 4; | |
738 | } | |
739 | ||
740 | err: | |
741 | kfree(data); | |
742 | return result; | |
743 | } | |
744 | ||
745 | static const struct file_operations amdgpu_debugfs_regs_fops = { | |
746 | .owner = THIS_MODULE, | |
747 | .read = amdgpu_debugfs_regs_read, | |
748 | .write = amdgpu_debugfs_regs_write, | |
749 | .llseek = default_llseek | |
750 | }; | |
751 | static const struct file_operations amdgpu_debugfs_regs_didt_fops = { | |
752 | .owner = THIS_MODULE, | |
753 | .read = amdgpu_debugfs_regs_didt_read, | |
754 | .write = amdgpu_debugfs_regs_didt_write, | |
755 | .llseek = default_llseek | |
756 | }; | |
757 | static const struct file_operations amdgpu_debugfs_regs_pcie_fops = { | |
758 | .owner = THIS_MODULE, | |
759 | .read = amdgpu_debugfs_regs_pcie_read, | |
760 | .write = amdgpu_debugfs_regs_pcie_write, | |
761 | .llseek = default_llseek | |
762 | }; | |
763 | static const struct file_operations amdgpu_debugfs_regs_smc_fops = { | |
764 | .owner = THIS_MODULE, | |
765 | .read = amdgpu_debugfs_regs_smc_read, | |
766 | .write = amdgpu_debugfs_regs_smc_write, | |
767 | .llseek = default_llseek | |
768 | }; | |
769 | ||
770 | static const struct file_operations amdgpu_debugfs_gca_config_fops = { | |
771 | .owner = THIS_MODULE, | |
772 | .read = amdgpu_debugfs_gca_config_read, | |
773 | .llseek = default_llseek | |
774 | }; | |
775 | ||
776 | static const struct file_operations amdgpu_debugfs_sensors_fops = { | |
777 | .owner = THIS_MODULE, | |
778 | .read = amdgpu_debugfs_sensor_read, | |
779 | .llseek = default_llseek | |
780 | }; | |
781 | ||
782 | static const struct file_operations amdgpu_debugfs_wave_fops = { | |
783 | .owner = THIS_MODULE, | |
784 | .read = amdgpu_debugfs_wave_read, | |
785 | .llseek = default_llseek | |
786 | }; | |
787 | static const struct file_operations amdgpu_debugfs_gpr_fops = { | |
788 | .owner = THIS_MODULE, | |
789 | .read = amdgpu_debugfs_gpr_read, | |
790 | .llseek = default_llseek | |
791 | }; | |
792 | ||
793 | static const struct file_operations *debugfs_regs[] = { | |
794 | &amdgpu_debugfs_regs_fops, | |
795 | &amdgpu_debugfs_regs_didt_fops, | |
796 | &amdgpu_debugfs_regs_pcie_fops, | |
797 | &amdgpu_debugfs_regs_smc_fops, | |
798 | &amdgpu_debugfs_gca_config_fops, | |
799 | &amdgpu_debugfs_sensors_fops, | |
800 | &amdgpu_debugfs_wave_fops, | |
801 | &amdgpu_debugfs_gpr_fops, | |
802 | }; | |
803 | ||
804 | static const char *debugfs_regs_names[] = { | |
805 | "amdgpu_regs", | |
806 | "amdgpu_regs_didt", | |
807 | "amdgpu_regs_pcie", | |
808 | "amdgpu_regs_smc", | |
809 | "amdgpu_gca_config", | |
810 | "amdgpu_sensors", | |
811 | "amdgpu_wave", | |
812 | "amdgpu_gpr", | |
813 | }; | |
814 | ||
7e4237db TSD |
815 | /** |
816 | * amdgpu_debugfs_regs_init - Initialize debugfs entries that provide | |
817 | * register access. | |
818 | * | |
819 | * @adev: The device to attach the debugfs entries to | |
820 | */ | |
75758255 AD |
821 | int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) |
822 | { | |
823 | struct drm_minor *minor = adev->ddev->primary; | |
824 | struct dentry *ent, *root = minor->debugfs_root; | |
d344b21b | 825 | unsigned int i; |
75758255 AD |
826 | |
827 | for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { | |
828 | ent = debugfs_create_file(debugfs_regs_names[i], | |
829 | S_IFREG | S_IRUGO, root, | |
830 | adev, debugfs_regs[i]); | |
d344b21b | 831 | if (!i && !IS_ERR_OR_NULL(ent)) |
75758255 AD |
832 | i_size_write(ent->d_inode, adev->rmmio_size); |
833 | adev->debugfs_regs[i] = ent; | |
834 | } | |
835 | ||
836 | return 0; | |
837 | } | |
838 | ||
839 | void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev) | |
840 | { | |
841 | unsigned i; | |
842 | ||
843 | for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { | |
844 | if (adev->debugfs_regs[i]) { | |
845 | debugfs_remove(adev->debugfs_regs[i]); | |
846 | adev->debugfs_regs[i] = NULL; | |
847 | } | |
848 | } | |
849 | } | |
850 | ||
851 | static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data) | |
852 | { | |
853 | struct drm_info_node *node = (struct drm_info_node *) m->private; | |
854 | struct drm_device *dev = node->minor->dev; | |
855 | struct amdgpu_device *adev = dev->dev_private; | |
856 | int r = 0, i; | |
857 | ||
858 | /* hold on the scheduler */ | |
859 | for (i = 0; i < AMDGPU_MAX_RINGS; i++) { | |
860 | struct amdgpu_ring *ring = adev->rings[i]; | |
861 | ||
862 | if (!ring || !ring->sched.thread) | |
863 | continue; | |
864 | kthread_park(ring->sched.thread); | |
865 | } | |
866 | ||
867 | seq_printf(m, "run ib test:\n"); | |
868 | r = amdgpu_ib_ring_tests(adev); | |
869 | if (r) | |
870 | seq_printf(m, "ib ring tests failed (%d).\n", r); | |
871 | else | |
872 | seq_printf(m, "ib ring tests passed.\n"); | |
873 | ||
874 | /* go on the scheduler */ | |
875 | for (i = 0; i < AMDGPU_MAX_RINGS; i++) { | |
876 | struct amdgpu_ring *ring = adev->rings[i]; | |
877 | ||
878 | if (!ring || !ring->sched.thread) | |
879 | continue; | |
880 | kthread_unpark(ring->sched.thread); | |
881 | } | |
882 | ||
883 | return 0; | |
884 | } | |
885 | ||
886 | static int amdgpu_debugfs_get_vbios_dump(struct seq_file *m, void *data) | |
887 | { | |
888 | struct drm_info_node *node = (struct drm_info_node *) m->private; | |
889 | struct drm_device *dev = node->minor->dev; | |
890 | struct amdgpu_device *adev = dev->dev_private; | |
891 | ||
892 | seq_write(m, adev->bios, adev->bios_size); | |
893 | return 0; | |
894 | } | |
895 | ||
896 | static int amdgpu_debugfs_evict_vram(struct seq_file *m, void *data) | |
897 | { | |
898 | struct drm_info_node *node = (struct drm_info_node *)m->private; | |
899 | struct drm_device *dev = node->minor->dev; | |
900 | struct amdgpu_device *adev = dev->dev_private; | |
901 | ||
902 | seq_printf(m, "(%d)\n", amdgpu_bo_evict_vram(adev)); | |
903 | return 0; | |
904 | } | |
905 | ||
87e90c76 CK |
906 | static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data) |
907 | { | |
908 | struct drm_info_node *node = (struct drm_info_node *)m->private; | |
909 | struct drm_device *dev = node->minor->dev; | |
910 | struct amdgpu_device *adev = dev->dev_private; | |
911 | ||
912 | seq_printf(m, "(%d)\n", ttm_bo_evict_mm(&adev->mman.bdev, TTM_PL_TT)); | |
913 | return 0; | |
914 | } | |
915 | ||
75758255 AD |
916 | static const struct drm_info_list amdgpu_debugfs_list[] = { |
917 | {"amdgpu_vbios", amdgpu_debugfs_get_vbios_dump}, | |
918 | {"amdgpu_test_ib", &amdgpu_debugfs_test_ib}, | |
87e90c76 CK |
919 | {"amdgpu_evict_vram", &amdgpu_debugfs_evict_vram}, |
920 | {"amdgpu_evict_gtt", &amdgpu_debugfs_evict_gtt}, | |
75758255 AD |
921 | }; |
922 | ||
923 | int amdgpu_debugfs_init(struct amdgpu_device *adev) | |
924 | { | |
925 | return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list, | |
926 | ARRAY_SIZE(amdgpu_debugfs_list)); | |
927 | } | |
928 | ||
929 | #else | |
930 | int amdgpu_debugfs_init(struct amdgpu_device *adev) | |
931 | { | |
932 | return 0; | |
933 | } | |
934 | int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) | |
935 | { | |
936 | return 0; | |
937 | } | |
938 | void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev) { } | |
939 | #endif |