#include // For seq_* functions and types #include // Macros to detect kernel version #include "nvdebug.h" #define RUNLIST_PROCFS_NAME "runlist" #define DETAILED_CHANNEL_INFO static int runlist_detail_seq_show_chan(struct seq_file *s, struct gk20a *g, uint32_t chid) { channel_ctrl_t chan; char *loc_txt; u64 instance_ptr; chan.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(chid)); loc_txt = target_to_text(chan.inst_target); if (!loc_txt) return -EIO; instance_ptr = chan.inst_ptr; instance_ptr <<= 12; seq_printf(s, " +- Channel Info %-4d -+\n", chid); seq_printf(s, " | Enabled: %d|\n", chan.enable); seq_printf(s, " | Next: %d|\n", chan.next); seq_printf(s, " | Force CTX Reload: %d|\n", chan.force_ctx_reload); seq_printf(s, " | Enable set: %d|\n", chan.enable_set); seq_printf(s, " | Enable clear: %d|\n", chan.enable_clear); seq_printf(s, " | PBDMA Faulted: %d|\n", chan.pbdma_faulted); seq_printf(s, " | ENG Faulted: %d|\n", chan.eng_faulted); seq_printf(s, " | Status: %2d|\n", chan.status); seq_printf(s, " | Busy: %d|\n", chan.busy); seq_printf(s, " | Instance PTR: |\n"); seq_printf(s, " | %#018llx |\n", instance_ptr); seq_printf(s, " | %-20s|\n", loc_txt); seq_printf(s, " | Instance bound: %d|\n", chan.inst_bind); seq_printf(s, " +---------------------+\n"); return 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) // Bug workaround. See comment in runlist_file_seq_start() static loff_t pos_fixup; #endif static void *runlist_file_seq_start(struct seq_file *s, loff_t *pos) { static struct runlist_iter rl_iter; // *pos == 0 for first call after read of file if (*pos == 0) { int err = get_runlist_iter(&rl_iter); if (err) return NULL; return &rl_iter; } // If we're resuming an earlier print if (*pos < rl_iter.rl_info.len) { #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) // There's a nasty bug prior to 4.19-rc1 that if the buffer overflows, the // last update to `pos` is not saved. Work around that here by reloading a // saved copy of `pos`. if (!pos_fixup) return NULL; *pos = pos_fixup; #endif return &rl_iter; } // When called with *pos != 0, we already traversed the runlist return NULL; } static void* runlist_file_seq_next(struct seq_file *s, void *raw_rl_iter, loff_t *pos) { struct runlist_iter* rl_iter = raw_rl_iter; void *ret = NULL; // Advance by one TSG + channels under last TSG *pos += 1 + rl_iter->curr_tsg->tsg_length; // Verify we haven't reached the end of the runlist // rl_info.len is the num of tsg entries + total num of channel entries if (*pos < rl_iter->rl_info.len) { rl_iter->curr_tsg = next_tsg(rl_iter->curr_tsg); ret = rl_iter; } #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) // Bug workaround. See comment in runlist_file_seq_start() pos_fixup = ret ? *pos : 0; #endif return ret; } static void runlist_file_seq_stop(struct seq_file *s, void *raw_rl_iter) { // No cleanup needed } static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) { struct entry_tsg* tsg = ((struct runlist_iter*)raw_rl_iter)->curr_tsg; struct runlist_chan* chan; struct gk20a *g = get_live_gk20a(); if (!g) return -EIO; if (tsg->entry_type != ENTRY_TYPE_TSG) { printk(KERN_WARNING "[nvdebug] Attempted to print non-TSG in tsg print logic!\n"); return -EIO; } seq_printf(s, "+---- TSG Entry %-2d----+\n", tsg->tsgid); seq_printf(s, "| Scale: %-13d|\n", tsg->timeslice_scale); seq_printf(s, "| Timeout: %-11d|\n", tsg->timeslice_timeout); seq_printf(s, "+---------------------+\n"); for_chan_in_tsg(chan, tsg) { #ifndef DETAILED_CHANNEL_INFO char* loc_txt; u64 instance_ptr; #endif if (chan->entry_type != ENTRY_TYPE_CHAN) { printk(KERN_WARNING "[nvdebug] Attempted to print non-channel in channel print logic!\n"); return -EIO; } #ifdef DETAILED_CHANNEL_INFO runlist_detail_seq_show_chan(s, g, chan->chid); #else loc_txt = target_to_text(chan->inst_target); if (!loc_txt) { printk(KERN_WARNING "[nvdebug] Invalid apature in channel print logic!\n"); return -EIO; } // Reconstruct pointer to channel instance block instance_ptr = chan->inst_ptr_hi; instance_ptr <<= 32; instance_ptr |= chan->inst_ptr_lo << 12; seq_printf(s, " +- Channel Entry %-4d-+\n", chan->chid); seq_printf(s, " | Runqueue Selector: %d|\n", chan->runqueue_selector); seq_printf(s, " | Instance PTR: |\n"); seq_printf(s, " | %#018llx |\n", instance_ptr); seq_printf(s, " | %-20s|\n", loc_txt); seq_printf(s, " +---------------------+\n"); #endif } return 0; } static const struct seq_operations runlist_file_seq_ops = { .start = runlist_file_seq_start, .next = runlist_file_seq_next, .stop = runlist_file_seq_stop, .show = runlist_file_seq_show, }; static int runlist_file_open(struct inode *inode, struct file *f) { return seq_open(f, &runlist_file_seq_ops); } const struct file_operations runlist_file_ops = { .open = runlist_file_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, };