/* * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "os_linux.h" /* * The sequence iterator functions. We simply use the count of the * next line as our internal position. */ static void *gk20a_fecs_trace_debugfs_ring_seq_start( struct seq_file *s, loff_t *pos) { if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS) return NULL; return pos; } static void *gk20a_fecs_trace_debugfs_ring_seq_next( struct seq_file *s, void *v, loff_t *pos) { ++(*pos); if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS) return NULL; return pos; } static void gk20a_fecs_trace_debugfs_ring_seq_stop( struct seq_file *s, void *v) { } static int gk20a_fecs_trace_debugfs_ring_seq_show( struct seq_file *s, void *v) { loff_t *pos = (loff_t *) v; struct gk20a *g = *(struct gk20a **)s->private; struct gk20a_fecs_trace_record *r = gk20a_fecs_trace_get_record(g, *pos); int i; const u32 invalid_tag = gk20a_fecs_trace_record_ts_tag_invalid_ts_v(); u32 tag; u64 timestamp; seq_printf(s, "record #%lld (%p)\n", *pos, r); seq_printf(s, "\tmagic_lo=%08x\n", r->magic_lo); seq_printf(s, "\tmagic_hi=%08x\n", r->magic_hi); if (gk20a_fecs_trace_is_valid_record(r)) { seq_printf(s, "\tcontext_ptr=%08x\n", r->context_ptr); seq_printf(s, "\tcontext_id=%08x\n", r->context_id); seq_printf(s, "\tnew_context_ptr=%08x\n", r->new_context_ptr); seq_printf(s, "\tnew_context_id=%08x\n", r->new_context_id); for (i = 0; i < gk20a_fecs_trace_num_ts(); i++) { tag = gk20a_fecs_trace_record_ts_tag_v(r->ts[i]); if (tag == invalid_tag) continue; timestamp = gk20a_fecs_trace_record_ts_timestamp_v(r->ts[i]); timestamp <<= GK20A_FECS_TRACE_PTIMER_SHIFT; seq_printf(s, "\ttag=%02x timestamp=%012llx\n", tag, timestamp); } } return 0; } /* * Tie them all together into a set of seq_operations. */ static const struct seq_operations gk20a_fecs_trace_debugfs_ring_seq_ops = { .start = gk20a_fecs_trace_debugfs_ring_seq_start, .next = gk20a_fecs_trace_debugfs_ring_seq_next, .stop = gk20a_fecs_trace_debugfs_ring_seq_stop, .show = gk20a_fecs_trace_debugfs_ring_seq_show }; /* * Time to set up the file operations for our /proc file. In this case, * all we need is an open function which sets up the sequence ops. */ static int gk20a_ctxsw_debugfs_ring_open(struct inode *inode, struct file *file) { struct gk20a **p; p = __seq_open_private(file, &gk20a_fecs_trace_debugfs_ring_seq_ops, sizeof(struct gk20a *)); if (!p) return -ENOMEM; *p = (struct gk20a *)inode->i_private; return 0; }; /* * The file operations structure contains our open function along with * set of the canned seq_ ops. */ static const struct file_operations gk20a_fecs_trace_debugfs_ring_fops = { .owner = THIS_MODULE, .open = gk20a_ctxsw_debugfs_ring_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private }; static int gk20a_fecs_trace_debugfs_read(void *arg, u64 *val) { *val = gk20a_fecs_trace_get_read_index((struct gk20a *)arg); return 0; } DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_read_fops, gk20a_fecs_trace_debugfs_read, NULL, "%llu\n"); static int gk20a_fecs_trace_debugfs_write(void *arg, u64 *val) { *val = gk20a_fecs_trace_get_write_index((struct gk20a *)arg); return 0; } DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_write_fops, gk20a_fecs_trace_debugfs_write, NULL, "%llu\n"); int nvgpu_fecs_trace_init_debugfs(struct gk20a *g) { struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); debugfs_create_file("ctxsw_trace_read", 0600, l->debugfs, g, &gk20a_fecs_trace_debugfs_read_fops); debugfs_create_file("ctxsw_trace_write", 0600, l->debugfs, g, &gk20a_fecs_trace_debugfs_write_fops); debugfs_create_file("ctxsw_trace_ring", 0600, l->debugfs, g, &gk20a_fecs_trace_debugfs_ring_fops); return 0; }