2 * Copyright (c) 2010-2011 Imre Deak <imre.deak@nokia.com>
3 * Copyright (c) 2010-2011 Luc Verhaegen <libv@codethink.co.uk>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Debugfs interface living in pvr/ subdirectory.
25 #include <linux/kernel.h>
26 #include <linux/debugfs.h>
27 #include <linux/vmalloc.h>
28 #include <linux/mutex.h>
29 #include <linux/uaccess.h>
32 #include "img_types.h"
33 #include "servicesext.h"
35 #include "sgxinfokm.h"
36 #include "syscommon.h"
37 #include "pvr_bridge_km.h"
39 #include "pvr_debugfs.h"
42 static struct dentry *debugfs_dir;
48 static struct PVRSRV_DEVICE_NODE *get_sgx_node(void)
50 struct SYS_DATA *sysdata;
51 struct PVRSRV_DEVICE_NODE *node;
53 if (SysAcquireData(&sysdata) != PVRSRV_OK)
56 for (node = sysdata->psDeviceNodeList; node; node = node->psNext)
57 if (node->sDevId.eDeviceType == PVRSRV_DEVICE_TYPE_SGX)
63 static int pvr_debugfs_reset(void *data, u64 val)
65 struct PVRSRV_DEVICE_NODE *node;
66 enum PVRSRV_ERROR err;
74 if (pvr_is_disabled()) {
79 node = get_sgx_node();
85 err = PVRSRVSetDevicePowerStateKM(node->sDevId.ui32DeviceIndex,
86 PVRSRV_POWER_STATE_D0);
87 if (err != PVRSRV_OK) {
92 HWRecoveryResetSGX(node);
94 SGXTestActivePowerEvent(node);
101 static int pvr_debugfs_set(void *data, u64 val)
105 if (var == &pvr_reset)
106 return pvr_debugfs_reset(data, val);
111 DEFINE_SIMPLE_ATTRIBUTE(pvr_debugfs_fops, NULL, pvr_debugfs_set, "%llu\n");
116 struct edm_buf_info {
121 static int pvr_debugfs_edm_open(struct inode *inode, struct file *file)
123 struct PVRSRV_DEVICE_NODE *node;
124 struct PVRSRV_SGXDEV_INFO *sgx_info;
125 struct edm_buf_info *bi;
128 /* Take a snapshot of the EDM trace buffer */
129 size = SGXMK_TRACE_BUFFER_SIZE * SGXMK_TRACE_BUF_STR_LEN;
130 bi = vmalloc(sizeof(*bi) + size);
134 node = get_sgx_node();
135 sgx_info = node->pvDevice;
136 bi->len = snprint_edm_trace(sgx_info, bi->data, size);
137 file->private_data = bi;
142 static int pvr_debugfs_edm_release(struct inode *inode, struct file *file)
144 vfree(file->private_data);
149 static ssize_t pvr_debugfs_edm_read(struct file *file, char __user *buffer,
150 size_t count, loff_t *ppos)
152 struct edm_buf_info *bi = file->private_data;
154 return simple_read_from_buffer(buffer, count, ppos, bi->data, bi->len);
157 static const struct file_operations pvr_debugfs_edm_fops = {
158 .owner = THIS_MODULE,
159 .open = pvr_debugfs_edm_open,
160 .read = pvr_debugfs_edm_read,
161 .release = pvr_debugfs_edm_release,
167 * HW Recovery dumping support.
170 static struct mutex hwrec_mutex[1];
171 static struct timeval hwrec_time;
172 static int hwrec_open_count;
173 static DECLARE_WAIT_QUEUE_HEAD(hwrec_wait_queue);
174 static int hwrec_event;
176 /* add extra locking to keep us from overwriting things during dumping. */
177 static int hwrec_event_open_count;
178 static int hwrec_event_file_lock;
180 /* While these could get moved into PVRSRV_SGXDEV_INFO, the more future-proof
181 * way of handling hw recovery events is by providing 1 single hwrecovery dump
182 * at a time, and adding a hwrec_info debugfs file with: process information,
183 * general driver information, and the instance of the (then multicore) pvr
184 * where the hwrec event happened.
186 static u32 *hwrec_registers;
188 #ifdef CONFIG_PVR_DEBUG
189 static size_t hwrec_mem_size;
190 #define HWREC_MEM_PAGES (4 * PAGE_SIZE)
191 static unsigned long hwrec_mem_pages[HWREC_MEM_PAGES];
192 #endif /* CONFIG_PVR_DEBUG */
195 hwrec_registers_dump(struct PVRSRV_SGXDEV_INFO *psDevInfo)
199 if (!hwrec_registers) {
200 hwrec_registers = (u32 *) __get_free_page(GFP_KERNEL);
201 if (!hwrec_registers) {
202 pr_err("%s: failed to get free page.\n", __func__);
207 for (i = 0; i < 1024; i++)
208 hwrec_registers[i] = readl(psDevInfo->pvRegsBaseKM + 4 * i);
212 hwrec_pages_free(size_t *size, u32 *pages)
219 for (i = 0; (i * PAGE_SIZE) < *size; i++) {
228 hwrec_pages_write(u8 *buffer, size_t size, size_t *current_size, u32 *pages,
235 size_t offset = *current_size & ~PAGE_MASK;
236 int page = *current_size / PAGE_SIZE;
239 if (((*current_size) / PAGE_SIZE) >= array_size) {
240 pr_err("%s: Size overrun!\n", __func__);
244 pages[page] = __get_free_page(GFP_KERNEL);
246 pr_err("%s: failed to get free page.\n",
252 if (count > (PAGE_SIZE - offset))
253 count = PAGE_SIZE - offset;
255 memcpy(((u8 *) pages[page]) + offset, buffer, count);
260 *current_size += count;
266 #ifdef CONFIG_PVR_DEBUG
270 hwrec_pages_free(&hwrec_mem_size, hwrec_mem_pages);
274 hwrec_mem_write(u8 *buffer, size_t size)
276 return hwrec_pages_write(buffer, size, &hwrec_mem_size,
277 hwrec_mem_pages, ARRAY_SIZE(hwrec_mem_pages));
281 hwrec_mem_print(char *format, ...)
287 va_start(ap, format);
288 size = vscnprintf(tmp, sizeof(tmp), format, ap);
291 return hwrec_mem_write(tmp, size);
293 #endif /* CONFIG_PVR_DEBUG */
296 pvr_hwrec_dump(struct PVRSRV_SGXDEV_INFO *psDevInfo)
298 mutex_lock(hwrec_mutex);
300 if (hwrec_open_count || hwrec_event_file_lock) {
301 pr_err("%s: previous hwrec dump is still locked!\n", __func__);
302 mutex_unlock(hwrec_mutex);
306 do_gettimeofday(&hwrec_time);
307 pr_info("HW Recovery dump generated at %010ld%06ld\n",
308 hwrec_time.tv_sec, hwrec_time.tv_usec);
310 hwrec_registers_dump(psDevInfo);
312 #ifdef CONFIG_PVR_DEBUG
314 mmu_hwrec_mem_dump(psDevInfo);
315 #endif /* CONFIG_PVR_DEBUG */
319 mutex_unlock(hwrec_mutex);
321 wake_up_interruptible(&hwrec_wait_queue);
328 hwrec_file_open(struct inode *inode, struct file *filp)
330 mutex_lock(hwrec_mutex);
334 mutex_unlock(hwrec_mutex);
339 hwrec_file_release(struct inode *inode, struct file *filp)
341 mutex_lock(hwrec_mutex);
345 mutex_unlock(hwrec_mutex);
350 hwrec_llseek_helper(struct file *filp, loff_t offset, int whence, loff_t max)
356 if ((offset > max) || (offset < 0))
362 if (((filp->f_pos + offset) > max) ||
363 ((filp->f_pos + offset) < 0))
366 f_pos = filp->f_pos + offset;
373 f_pos = max + offset;
387 * Provides a hwrec timestamp for unique dumping.
390 hwrec_time_read(struct file *filp, char __user *buf, size_t size,
395 mutex_lock(hwrec_mutex);
396 snprintf(tmp, sizeof(tmp), "%010ld%06ld",
397 hwrec_time.tv_sec, hwrec_time.tv_usec);
398 mutex_unlock(hwrec_mutex);
400 return simple_read_from_buffer(buf, size, f_pos, tmp, strlen(tmp));
403 static const struct file_operations hwrec_time_fops = {
404 .owner = THIS_MODULE,
406 .read = hwrec_time_read,
407 .open = hwrec_file_open,
408 .release = hwrec_file_release,
412 * Blocks the reader until a HWRec happens.
415 hwrec_event_open(struct inode *inode, struct file *filp)
419 mutex_lock(hwrec_mutex);
421 if (hwrec_event_open_count)
424 hwrec_event_open_count++;
428 mutex_unlock(hwrec_mutex);
434 hwrec_event_release(struct inode *inode, struct file *filp)
436 mutex_lock(hwrec_mutex);
438 hwrec_event_open_count--;
440 mutex_unlock(hwrec_mutex);
447 hwrec_event_read(struct file *filp, char __user *buf, size_t size,
452 mutex_lock(hwrec_mutex);
454 hwrec_event_file_lock = 0;
456 mutex_unlock(hwrec_mutex);
458 ret = wait_event_interruptible(hwrec_wait_queue, hwrec_event);
460 mutex_lock(hwrec_mutex);
463 hwrec_event_file_lock = 1;
465 mutex_unlock(hwrec_mutex);
471 static const struct file_operations hwrec_event_fops = {
472 .owner = THIS_MODULE,
474 .read = hwrec_event_read,
475 .open = hwrec_event_open,
476 .release = hwrec_event_release,
480 * Reads out all readable registers.
482 #define HWREC_REGS_LINE_SIZE 17
485 hwrec_regs_llseek(struct file *filp, loff_t offset, int whence)
489 mutex_lock(hwrec_mutex);
492 f_pos = hwrec_llseek_helper(filp, offset, whence,
493 1024 * HWREC_REGS_LINE_SIZE);
497 mutex_unlock(hwrec_mutex);
503 hwrec_regs_read(struct file *filp, char __user *buf, size_t size,
506 char tmp[HWREC_REGS_LINE_SIZE + 1];
509 if ((*f_pos < 0) || (size < (sizeof(tmp) - 1)))
512 i = ((int) *f_pos) / (sizeof(tmp) - 1);
516 mutex_lock(hwrec_mutex);
518 if (!hwrec_registers)
521 size = snprintf(tmp, sizeof(tmp), "0x%03X 0x%08X\n", i * 4,
524 mutex_unlock(hwrec_mutex);
527 if (copy_to_user(buf, tmp + *f_pos - (i * (sizeof(tmp) - 1)),
537 static const struct file_operations hwrec_regs_fops = {
538 .owner = THIS_MODULE,
539 .llseek = hwrec_regs_llseek,
540 .read = hwrec_regs_read,
541 .open = hwrec_file_open,
542 .release = hwrec_file_release,
545 #ifdef CONFIG_PVR_DEBUG
547 * Provides a full context dump: page directory, page tables, and all mapped
551 hwrec_mem_llseek(struct file *filp, loff_t offset, int whence)
555 mutex_lock(hwrec_mutex);
558 f_pos = hwrec_llseek_helper(filp, offset, whence,
563 mutex_unlock(hwrec_mutex);
569 hwrec_mem_read(struct file *filp, char __user *buf, size_t size,
572 mutex_lock(hwrec_mutex);
574 if ((*f_pos >= 0) && (*f_pos < hwrec_mem_size)) {
577 size = min(size, (size_t) hwrec_mem_size - (size_t) *f_pos);
579 page = (*f_pos) / PAGE_SIZE;
580 offset = (*f_pos) & ~PAGE_MASK;
582 size = min(size, (size_t) PAGE_SIZE - offset);
584 if (copy_to_user(buf,
585 ((u8 *) hwrec_mem_pages[page]) + offset,
587 mutex_unlock(hwrec_mutex);
593 mutex_unlock(hwrec_mutex);
599 static const struct file_operations hwrec_mem_fops = {
600 .owner = THIS_MODULE,
601 .llseek = hwrec_mem_llseek,
602 .read = hwrec_mem_read,
603 .open = hwrec_file_open,
604 .release = hwrec_file_release,
606 #endif /* CONFIG_PVR_DEBUG */
611 int pvr_debugfs_init(void)
613 mutex_init(hwrec_mutex);
615 debugfs_dir = debugfs_create_dir("pvr", NULL);
619 if (!debugfs_create_file("reset_sgx", S_IWUSR, debugfs_dir, &pvr_reset,
620 &pvr_debugfs_fops)) {
621 debugfs_remove(debugfs_dir);
625 if (!debugfs_create_file("edm_trace", S_IRUGO, debugfs_dir, NULL,
626 &pvr_debugfs_edm_fops)) {
627 debugfs_remove_recursive(debugfs_dir);
631 if (!debugfs_create_file("hwrec_event", S_IRUSR, debugfs_dir, NULL,
632 &hwrec_event_fops)) {
633 debugfs_remove_recursive(debugfs_dir);
637 if (!debugfs_create_file("hwrec_time", S_IRUSR, debugfs_dir, NULL,
639 debugfs_remove_recursive(debugfs_dir);
643 if (!debugfs_create_file("hwrec_regs", S_IRUSR, debugfs_dir, NULL,
645 debugfs_remove_recursive(debugfs_dir);
649 #ifdef CONFIG_PVR_DEBUG
650 if (!debugfs_create_file("hwrec_mem", S_IRUSR, debugfs_dir, NULL,
652 debugfs_remove_recursive(debugfs_dir);
655 #endif /* CONFIG_PVR_DEBUG */
660 void pvr_debugfs_cleanup(void)
662 debugfs_remove_recursive(debugfs_dir);
665 free_page((u32) hwrec_registers);
667 #ifdef CONFIG_PVR_DEBUG
669 #endif /* CONFIG_PVR_DEBUG */