1 /*
2  * Memory mapped I/O tracing
3  *
4  * Copyright (C) 2008 Pekka Paalanen <pq@iki.fi>
5  */
6 
7 #define DEBUG 1
8 
9 #include <linux/kernel.h>
10 #include <linux/mmiotrace.h>
11 #include <linux/pci.h>
12 
13 #include "trace.h"
14 
15 struct header_iter {
16 	struct pci_dev *dev;
17 };
18 
19 static struct trace_array *mmio_trace_array;
20 static bool overrun_detected;
21 
22 static void mmio_reset_data(struct trace_array *tr)
23 {
24 	int cpu;
25 
26 	overrun_detected = false;
27 	tr->time_start = ftrace_now(tr->cpu);
28 
29 	for_each_online_cpu(cpu)
30 		tracing_reset(tr->data[cpu]);
31 }
32 
33 static void mmio_trace_init(struct trace_array *tr)
34 {
35 	pr_debug("in %s\n", __func__);
36 	mmio_trace_array = tr;
37 	if (tr->ctrl) {
38 		mmio_reset_data(tr);
39 		enable_mmiotrace();
40 	}
41 }
42 
43 static void mmio_trace_reset(struct trace_array *tr)
44 {
45 	pr_debug("in %s\n", __func__);
46 	if (tr->ctrl)
47 		disable_mmiotrace();
48 	mmio_reset_data(tr);
49 	mmio_trace_array = NULL;
50 }
51 
52 static void mmio_trace_ctrl_update(struct trace_array *tr)
53 {
54 	pr_debug("in %s\n", __func__);
55 	if (tr->ctrl) {
56 		mmio_reset_data(tr);
57 		enable_mmiotrace();
58 	} else {
59 		disable_mmiotrace();
60 	}
61 }
62 
63 static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
64 {
65 	int ret = 0;
66 	int i;
67 	resource_size_t start, end;
68 	const struct pci_driver *drv = pci_dev_driver(dev);
69 
70 	/* XXX: incomplete checks for trace_seq_printf() return value */
71 	ret += trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x",
72 				dev->bus->number, dev->devfn,
73 				dev->vendor, dev->device, dev->irq);
74 	/*
75 	 * XXX: is pci_resource_to_user() appropriate, since we are
76 	 * supposed to interpret the __ioremap() phys_addr argument based on
77 	 * these printed values?
78 	 */
79 	for (i = 0; i < 7; i++) {
80 		pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
81 		ret += trace_seq_printf(s, " %llx",
82 			(unsigned long long)(start |
83 			(dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
84 	}
85 	for (i = 0; i < 7; i++) {
86 		pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
87 		ret += trace_seq_printf(s, " %llx",
88 			dev->resource[i].start < dev->resource[i].end ?
89 			(unsigned long long)(end - start) + 1 : 0);
90 	}
91 	if (drv)
92 		ret += trace_seq_printf(s, " %s\n", drv->name);
93 	else
94 		ret += trace_seq_printf(s, " \n");
95 	return ret;
96 }
97 
98 static void destroy_header_iter(struct header_iter *hiter)
99 {
100 	if (!hiter)
101 		return;
102 	pci_dev_put(hiter->dev);
103 	kfree(hiter);
104 }
105 
106 static void mmio_pipe_open(struct trace_iterator *iter)
107 {
108 	struct header_iter *hiter;
109 	struct trace_seq *s = &iter->seq;
110 
111 	trace_seq_printf(s, "VERSION 20070824\n");
112 
113 	hiter = kzalloc(sizeof(*hiter), GFP_KERNEL);
114 	if (!hiter)
115 		return;
116 
117 	hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
118 	iter->private = hiter;
119 }
120 
121 /* XXX: This is not called when the pipe is closed! */
122 static void mmio_close(struct trace_iterator *iter)
123 {
124 	struct header_iter *hiter = iter->private;
125 	destroy_header_iter(hiter);
126 	iter->private = NULL;
127 }
128 
129 static unsigned long count_overruns(struct trace_iterator *iter)
130 {
131 	int cpu;
132 	unsigned long cnt = 0;
133 	for_each_online_cpu(cpu) {
134 		cnt += iter->overrun[cpu];
135 		iter->overrun[cpu] = 0;
136 	}
137 	return cnt;
138 }
139 
140 static ssize_t mmio_read(struct trace_iterator *iter, struct file *filp,
141 				char __user *ubuf, size_t cnt, loff_t *ppos)
142 {
143 	ssize_t ret;
144 	struct header_iter *hiter = iter->private;
145 	struct trace_seq *s = &iter->seq;
146 	unsigned long n;
147 
148 	n = count_overruns(iter);
149 	if (n) {
150 		/* XXX: This is later than where events were lost. */
151 		trace_seq_printf(s, "MARK 0.000000 Lost %lu events.\n", n);
152 		if (!overrun_detected)
153 			pr_warning("mmiotrace has lost events.\n");
154 		overrun_detected = true;
155 		goto print_out;
156 	}
157 
158 	if (!hiter)
159 		return 0;
160 
161 	mmio_print_pcidev(s, hiter->dev);
162 	hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, hiter->dev);
163 
164 	if (!hiter->dev) {
165 		destroy_header_iter(hiter);
166 		iter->private = NULL;
167 	}
168 
169 print_out:
170 	ret = trace_seq_to_user(s, ubuf, cnt);
171 	return (ret == -EBUSY) ? 0 : ret;
172 }
173 
174 static int mmio_print_rw(struct trace_iterator *iter)
175 {
176 	struct trace_entry *entry = iter->ent;
177 	struct mmiotrace_rw *rw	= &entry->mmiorw;
178 	struct trace_seq *s	= &iter->seq;
179 	unsigned long long t	= ns2usecs(entry->t);
180 	unsigned long usec_rem	= do_div(t, 1000000ULL);
181 	unsigned secs		= (unsigned long)t;
182 	int ret = 1;
183 
184 	switch (entry->mmiorw.opcode) {
185 	case MMIO_READ:
186 		ret = trace_seq_printf(s,
187 			"R %d %lu.%06lu %d 0x%llx 0x%lx 0x%lx %d\n",
188 			rw->width, secs, usec_rem, rw->map_id,
189 			(unsigned long long)rw->phys,
190 			rw->value, rw->pc, 0);
191 		break;
192 	case MMIO_WRITE:
193 		ret = trace_seq_printf(s,
194 			"W %d %lu.%06lu %d 0x%llx 0x%lx 0x%lx %d\n",
195 			rw->width, secs, usec_rem, rw->map_id,
196 			(unsigned long long)rw->phys,
197 			rw->value, rw->pc, 0);
198 		break;
199 	case MMIO_UNKNOWN_OP:
200 		ret = trace_seq_printf(s,
201 			"UNKNOWN %lu.%06lu %d 0x%llx %02x,%02x,%02x 0x%lx %d\n",
202 			secs, usec_rem, rw->map_id,
203 			(unsigned long long)rw->phys,
204 			(rw->value >> 16) & 0xff, (rw->value >> 8) & 0xff,
205 			(rw->value >> 0) & 0xff, rw->pc, 0);
206 		break;
207 	default:
208 		ret = trace_seq_printf(s, "rw what?\n");
209 		break;
210 	}
211 	if (ret)
212 		return 1;
213 	return 0;
214 }
215 
216 static int mmio_print_map(struct trace_iterator *iter)
217 {
218 	struct trace_entry *entry = iter->ent;
219 	struct mmiotrace_map *m	= &entry->mmiomap;
220 	struct trace_seq *s	= &iter->seq;
221 	unsigned long long t	= ns2usecs(entry->t);
222 	unsigned long usec_rem	= do_div(t, 1000000ULL);
223 	unsigned secs		= (unsigned long)t;
224 	int ret = 1;
225 
226 	switch (entry->mmiorw.opcode) {
227 	case MMIO_PROBE:
228 		ret = trace_seq_printf(s,
229 			"MAP %lu.%06lu %d 0x%llx 0x%lx 0x%lx 0x%lx %d\n",
230 			secs, usec_rem, m->map_id,
231 			(unsigned long long)m->phys, m->virt, m->len,
232 			0UL, 0);
233 		break;
234 	case MMIO_UNPROBE:
235 		ret = trace_seq_printf(s,
236 			"UNMAP %lu.%06lu %d 0x%lx %d\n",
237 			secs, usec_rem, m->map_id, 0UL, 0);
238 		break;
239 	default:
240 		ret = trace_seq_printf(s, "map what?\n");
241 		break;
242 	}
243 	if (ret)
244 		return 1;
245 	return 0;
246 }
247 
248 /* return 0 to abort printing without consuming current entry in pipe mode */
249 static int mmio_print_line(struct trace_iterator *iter)
250 {
251 	switch (iter->ent->type) {
252 	case TRACE_MMIO_RW:
253 		return mmio_print_rw(iter);
254 	case TRACE_MMIO_MAP:
255 		return mmio_print_map(iter);
256 	default:
257 		return 1; /* ignore unknown entries */
258 	}
259 }
260 
261 static struct tracer mmio_tracer __read_mostly =
262 {
263 	.name		= "mmiotrace",
264 	.init		= mmio_trace_init,
265 	.reset		= mmio_trace_reset,
266 	.pipe_open	= mmio_pipe_open,
267 	.close		= mmio_close,
268 	.read		= mmio_read,
269 	.ctrl_update	= mmio_trace_ctrl_update,
270 	.print_line	= mmio_print_line,
271 };
272 
273 __init static int init_mmio_trace(void)
274 {
275 	return register_tracer(&mmio_tracer);
276 }
277 device_initcall(init_mmio_trace);
278 
279 void mmio_trace_rw(struct mmiotrace_rw *rw)
280 {
281 	struct trace_array *tr = mmio_trace_array;
282 	struct trace_array_cpu *data = tr->data[smp_processor_id()];
283 	__trace_mmiotrace_rw(tr, data, rw);
284 }
285 
286 void mmio_trace_mapping(struct mmiotrace_map *map)
287 {
288 	struct trace_array *tr = mmio_trace_array;
289 	struct trace_array_cpu *data;
290 
291 	preempt_disable();
292 	data = tr->data[smp_processor_id()];
293 	__trace_mmiotrace_map(tr, data, map);
294 	preempt_enable();
295 }
296