1 /*
2  * Copyright 2016-17 IBM Corp.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version
7  * 2 of the License, or (at your option) any later version.
8  */
9 
10 #define pr_fmt(fmt) "vas: " fmt
11 
12 #include <linux/types.h>
13 #include <linux/slab.h>
14 #include <linux/debugfs.h>
15 #include <linux/seq_file.h>
16 #include "vas.h"
17 
18 static struct dentry *vas_debugfs;
19 
20 static char *cop_to_str(int cop)
21 {
22 	switch (cop) {
23 	case VAS_COP_TYPE_FAULT:	return "Fault";
24 	case VAS_COP_TYPE_842:		return "NX-842 Normal Priority";
25 	case VAS_COP_TYPE_842_HIPRI:	return "NX-842 High Priority";
26 	case VAS_COP_TYPE_GZIP:		return "NX-GZIP Normal Priority";
27 	case VAS_COP_TYPE_GZIP_HIPRI:	return "NX-GZIP High Priority";
28 	case VAS_COP_TYPE_FTW:		return "Fast Thread-wakeup";
29 	default:			return "Unknown";
30 	}
31 }
32 
33 static int info_show(struct seq_file *s, void *private)
34 {
35 	struct vas_window *window = s->private;
36 
37 	mutex_lock(&vas_mutex);
38 
39 	/* ensure window is not unmapped */
40 	if (!window->hvwc_map)
41 		goto unlock;
42 
43 	seq_printf(s, "Type: %s, %s\n", cop_to_str(window->cop),
44 					window->tx_win ? "Send" : "Receive");
45 	seq_printf(s, "Pid : %d\n", window->pid);
46 
47 unlock:
48 	mutex_unlock(&vas_mutex);
49 	return 0;
50 }
51 
52 DEFINE_SHOW_ATTRIBUTE(info);
53 
54 static inline void print_reg(struct seq_file *s, struct vas_window *win,
55 			char *name, u32 reg)
56 {
57 	seq_printf(s, "0x%016llx %s\n", read_hvwc_reg(win, name, reg), name);
58 }
59 
60 static int hvwc_show(struct seq_file *s, void *private)
61 {
62 	struct vas_window *window = s->private;
63 
64 	mutex_lock(&vas_mutex);
65 
66 	/* ensure window is not unmapped */
67 	if (!window->hvwc_map)
68 		goto unlock;
69 
70 	print_reg(s, window, VREG(LPID));
71 	print_reg(s, window, VREG(PID));
72 	print_reg(s, window, VREG(XLATE_MSR));
73 	print_reg(s, window, VREG(XLATE_LPCR));
74 	print_reg(s, window, VREG(XLATE_CTL));
75 	print_reg(s, window, VREG(AMR));
76 	print_reg(s, window, VREG(SEIDR));
77 	print_reg(s, window, VREG(FAULT_TX_WIN));
78 	print_reg(s, window, VREG(OSU_INTR_SRC_RA));
79 	print_reg(s, window, VREG(HV_INTR_SRC_RA));
80 	print_reg(s, window, VREG(PSWID));
81 	print_reg(s, window, VREG(LFIFO_BAR));
82 	print_reg(s, window, VREG(LDATA_STAMP_CTL));
83 	print_reg(s, window, VREG(LDMA_CACHE_CTL));
84 	print_reg(s, window, VREG(LRFIFO_PUSH));
85 	print_reg(s, window, VREG(CURR_MSG_COUNT));
86 	print_reg(s, window, VREG(LNOTIFY_AFTER_COUNT));
87 	print_reg(s, window, VREG(LRX_WCRED));
88 	print_reg(s, window, VREG(LRX_WCRED_ADDER));
89 	print_reg(s, window, VREG(TX_WCRED));
90 	print_reg(s, window, VREG(TX_WCRED_ADDER));
91 	print_reg(s, window, VREG(LFIFO_SIZE));
92 	print_reg(s, window, VREG(WINCTL));
93 	print_reg(s, window, VREG(WIN_STATUS));
94 	print_reg(s, window, VREG(WIN_CTX_CACHING_CTL));
95 	print_reg(s, window, VREG(TX_RSVD_BUF_COUNT));
96 	print_reg(s, window, VREG(LRFIFO_WIN_PTR));
97 	print_reg(s, window, VREG(LNOTIFY_CTL));
98 	print_reg(s, window, VREG(LNOTIFY_PID));
99 	print_reg(s, window, VREG(LNOTIFY_LPID));
100 	print_reg(s, window, VREG(LNOTIFY_TID));
101 	print_reg(s, window, VREG(LNOTIFY_SCOPE));
102 	print_reg(s, window, VREG(NX_UTIL_ADDER));
103 unlock:
104 	mutex_unlock(&vas_mutex);
105 	return 0;
106 }
107 
108 DEFINE_SHOW_ATTRIBUTE(hvwc);
109 
110 void vas_window_free_dbgdir(struct vas_window *window)
111 {
112 	if (window->dbgdir) {
113 		debugfs_remove_recursive(window->dbgdir);
114 		kfree(window->dbgname);
115 		window->dbgdir = NULL;
116 		window->dbgname = NULL;
117 	}
118 }
119 
120 void vas_window_init_dbgdir(struct vas_window *window)
121 {
122 	struct dentry *f, *d;
123 
124 	if (!window->vinst->dbgdir)
125 		return;
126 
127 	window->dbgname = kzalloc(16, GFP_KERNEL);
128 	if (!window->dbgname)
129 		return;
130 
131 	snprintf(window->dbgname, 16, "w%d", window->winid);
132 
133 	d = debugfs_create_dir(window->dbgname, window->vinst->dbgdir);
134 	if (IS_ERR(d))
135 		goto free_name;
136 
137 	window->dbgdir = d;
138 
139 	f = debugfs_create_file("info", 0444, d, window, &info_fops);
140 	if (IS_ERR(f))
141 		goto remove_dir;
142 
143 	f = debugfs_create_file("hvwc", 0444, d, window, &hvwc_fops);
144 	if (IS_ERR(f))
145 		goto remove_dir;
146 
147 	return;
148 
149 remove_dir:
150 	debugfs_remove_recursive(window->dbgdir);
151 	window->dbgdir = NULL;
152 
153 free_name:
154 	kfree(window->dbgname);
155 	window->dbgname = NULL;
156 }
157 
158 void vas_instance_init_dbgdir(struct vas_instance *vinst)
159 {
160 	struct dentry *d;
161 
162 	vas_init_dbgdir();
163 	if (!vas_debugfs)
164 		return;
165 
166 	vinst->dbgname = kzalloc(16, GFP_KERNEL);
167 	if (!vinst->dbgname)
168 		return;
169 
170 	snprintf(vinst->dbgname, 16, "v%d", vinst->vas_id);
171 
172 	d = debugfs_create_dir(vinst->dbgname, vas_debugfs);
173 	if (IS_ERR(d))
174 		goto free_name;
175 
176 	vinst->dbgdir = d;
177 	return;
178 
179 free_name:
180 	kfree(vinst->dbgname);
181 	vinst->dbgname = NULL;
182 	vinst->dbgdir = NULL;
183 }
184 
185 /*
186  * Set up the "root" VAS debugfs dir. Return if we already set it up
187  * (or failed to) in an earlier instance of VAS.
188  */
189 void vas_init_dbgdir(void)
190 {
191 	static bool first_time = true;
192 
193 	if (!first_time)
194 		return;
195 
196 	first_time = false;
197 	vas_debugfs = debugfs_create_dir("vas", NULL);
198 	if (IS_ERR(vas_debugfs))
199 		vas_debugfs = NULL;
200 }
201