aboutsummaryrefslogtreecommitdiffstats
path: root/runlist_procfs.c
blob: 2107bd4dcabf3f3aec511668f0d7a8741d487ed6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <linux/seq_file.h> // For seq_* functions and types

#include "nvdebug.h"

#define RUNLIST_PROCFS_NAME "runlist"

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;
	}
	// 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;
	// 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);
		return rl_iter;
	}
	return NULL;
}

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;
	if (tsg->entry_type != ENTRY_TYPE_TSG) {
                printk(KERN_WARNING "[nvdebug] Attempted to print non-TSG in nvdebug_print_tsg()!\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) {
		char* loc_txt;
		u64 instance_ptr;
		if (chan->entry_type != ENTRY_TYPE_CHAN) {
			printk(KERN_WARNING "[nvdebug] Attempted to print non-channel in nvdebug_print_channel()!\n");
			return -EIO;
		}
		switch (chan->inst_target) {
			case TARGET_VID_MEM:
				loc_txt = "VID_MEM";
				break;
			case TARGET_SYS_MEM_COHERENT:
				loc_txt = "SYS_MEM_COHERENT";
				break;
			case TARGET_SYS_MEM_NONCOHERENT:
				loc_txt = "SYS_MEM_NONCOHERENT";
				break;
			default:
				printk(KERN_WARNING "[nvdebug] Invalid aperture in runlist channel!\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");
	}
	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,
};