kernel: bump 4.14 to 4.14.93
[openwrt/staging/chunkeey.git] / target / linux / brcm2708 / patches-4.14 / 950-0125-AXI-performance-monitor-driver-2222.patch
1 From accf80ccafcb88ad0ffffc11bd4e090380af6654 Mon Sep 17 00:00:00 2001
2 From: James Hughes <JamesH65@users.noreply.github.com>
3 Date: Tue, 14 Nov 2017 15:13:15 +0000
4 Subject: [PATCH 125/454] AXI performance monitor driver (#2222)
5
6 Uses the debugfs I/F to provide access to the AXI
7 bus performance monitors.
8
9 Requires the new mailbox peripheral access for access
10 to the VPU performance registers, system bus access
11 is done using direct register reads.
12
13 Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
14 ---
15 drivers/perf/Kconfig | 7 +
16 drivers/perf/Makefile | 1 +
17 drivers/perf/raspberrypi_axi_monitor.c | 637 +++++++++++++++++++++++++
18 3 files changed, 645 insertions(+)
19 create mode 100644 drivers/perf/raspberrypi_axi_monitor.c
20
21 --- a/drivers/perf/Kconfig
22 +++ b/drivers/perf/Kconfig
23 @@ -43,4 +43,11 @@ config XGENE_PMU
24 help
25 Say y if you want to use APM X-Gene SoC performance monitors.
26
27 +config RPI_AXIPERF
28 + depends on ARCH_BCM2835
29 + tristate "RaspberryPi AXI Performance monitors"
30 + default n
31 + help
32 + Say y if you want to use Raspberry Pi AXI performance monitors, m if
33 + you want to build it as a module.
34 endmenu
35 --- a/drivers/perf/Makefile
36 +++ b/drivers/perf/Makefile
37 @@ -4,3 +4,4 @@ obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_ac
38 obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o
39 obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o
40 obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
41 +obj-$(CONFIG_RPI_AXIPERF) += raspberrypi_axi_monitor.o
42 --- /dev/null
43 +++ b/drivers/perf/raspberrypi_axi_monitor.c
44 @@ -0,0 +1,637 @@
45 +/*
46 + * raspberrypi_axi_monitor.c
47 + *
48 + * Author: james.hughes@raspberrypi.org
49 + *
50 + * Raspberry Pi AXI performance counters.
51 + *
52 + * Copyright (C) 2017 Raspberry Pi Trading Ltd.
53 + *
54 + * This program is free software; you can redistribute it and/or modify
55 + * it under the terms of the GNU General Public License version 2 as
56 + * published by the Free Software Foundation.
57 + */
58 +
59 +#include <linux/debugfs.h>
60 +#include <linux/devcoredump.h>
61 +#include <linux/device.h>
62 +#include <linux/kthread.h>
63 +#include <linux/module.h>
64 +#include <linux/netdevice.h>
65 +#include <linux/mutex.h>
66 +#include <linux/of.h>
67 +#include <linux/platform_device.h>
68 +
69 +#include <soc/bcm2835/raspberrypi-firmware.h>
70 +
71 +#define NUM_MONITORS 2
72 +#define NUM_BUS_WATCHERS_PER_MONITOR 3
73 +
74 +#define SYSTEM_MONITOR 0
75 +#define VPU_MONITOR 1
76 +
77 +#define MAX_BUSES 16
78 +#define DEFAULT_SAMPLE_TIME 100
79 +
80 +#define NUM_BUS_WATCHER_RESULTS 9
81 +
82 +struct bus_watcher_data {
83 + union {
84 + u32 results[NUM_BUS_WATCHER_RESULTS];
85 + struct {
86 + u32 atrans;
87 + u32 atwait;
88 + u32 amax;
89 + u32 wtrans;
90 + u32 wtwait;
91 + u32 wmax;
92 + u32 rtrans;
93 + u32 rtwait;
94 + u32 rmax;
95 + };
96 + };
97 +};
98 +
99 +
100 +struct rpi_axiperf {
101 + struct platform_device *dev;
102 + struct dentry *root_folder;
103 +
104 + struct task_struct *monitor_thread;
105 + struct mutex lock;
106 +
107 + struct rpi_firmware *firmware;
108 +
109 + /* Sample time spent on for each bus */
110 + int sample_time;
111 +
112 + /* Now storage for the per monitor settings and the resulting
113 + * performance figures
114 + */
115 + struct {
116 + /* Bit field of buses we want to monitor */
117 + int bus_enabled;
118 + /* Bit field of buses to filter by */
119 + int bus_filter;
120 + /* The current buses being monitored on this monitor */
121 + int current_bus[NUM_BUS_WATCHERS_PER_MONITOR];
122 + /* The last bus monitored on this monitor */
123 + int last_monitored;
124 +
125 + /* Set true if this mailbox must use the mailbox interface
126 + * rather than access registers directly.
127 + */
128 + int use_mailbox_interface;
129 +
130 + /* Current result values */
131 + struct bus_watcher_data results[MAX_BUSES];
132 +
133 + struct dentry *debugfs_entry;
134 + void __iomem *base_address;
135 +
136 + } monitor[NUM_MONITORS];
137 +
138 +};
139 +
140 +static struct rpi_axiperf *state;
141 +
142 +/* Two monitors, System and VPU, each with the following register sets.
143 + * Each monitor can only monitor one bus at a time, so we time share them,
144 + * giving each bus 100ms (default, settable via debugfs) of time on its
145 + * associated monitor
146 + * Record results from the three Bus watchers per monitor and push to the sysfs
147 + */
148 +
149 +/* general registers */
150 +const int GEN_CTRL;
151 +
152 +const int GEN_CTL_ENABLE_BIT = BIT(0);
153 +const int GEN_CTL_RESET_BIT = BIT(1);
154 +
155 +/* Bus watcher registers */
156 +const int BW_PITCH = 0x40;
157 +
158 +const int BW0_CTRL = 0x40;
159 +const int BW1_CTRL = 0x80;
160 +const int BW2_CTRL = 0xc0;
161 +
162 +const int BW_ATRANS_OFFSET = 0x04;
163 +const int BW_ATWAIT_OFFSET = 0x08;
164 +const int BW_AMAX_OFFSET = 0x0c;
165 +const int BW_WTRANS_OFFSET = 0x10;
166 +const int BW_WTWAIT_OFFSET = 0x14;
167 +const int BW_WMAX_OFFSET = 0x18;
168 +const int BW_RTRANS_OFFSET = 0x1c;
169 +const int BW_RTWAIT_OFFSET = 0x20;
170 +const int BW_RMAX_OFFSET = 0x24;
171 +
172 +const int BW_CTRL_RESET_BIT = BIT(31);
173 +const int BW_CTRL_ENABLE_BIT = BIT(30);
174 +const int BW_CTRL_ENABLE_ID_FILTER_BIT = BIT(29);
175 +const int BW_CTRL_LIMIT_HALT_BIT = BIT(28);
176 +
177 +const int BW_CTRL_SOURCE_SHIFT = 8;
178 +const int BW_CTRL_SOURCE_MASK = GENMASK(12, 8); // 5 bits
179 +const int BW_CTRL_BUS_WATCH_SHIFT;
180 +const int BW_CTRL_BUS_WATCH_MASK = GENMASK(5, 0); // 6 bits
181 +const int BW_CTRL_BUS_FILTER_SHIFT = 8;
182 +
183 +const static char *bus_filter_strings[] = {
184 + "",
185 + "CORE0_V",
186 + "ICACHE0",
187 + "DCACHE0",
188 + "CORE1_V",
189 + "ICACHE1",
190 + "DCACHE1",
191 + "L2_MAIN",
192 + "HOST_PORT",
193 + "HOST_PORT2",
194 + "HVS",
195 + "ISP",
196 + "VIDEO_DCT",
197 + "VIDEO_SD2AXI",
198 + "CAM0",
199 + "CAM1",
200 + "DMA0",
201 + "DMA1",
202 + "DMA2_VPU",
203 + "JPEG",
204 + "VIDEO_CME",
205 + "TRANSPOSER",
206 + "VIDEO_FME",
207 + "CCP2TX",
208 + "USB",
209 + "V3D0",
210 + "V3D1",
211 + "V3D2",
212 + "AVE",
213 + "DEBUG",
214 + "CPU",
215 + "M30"
216 +};
217 +
218 +const int num_bus_filters = ARRAY_SIZE(bus_filter_strings);
219 +
220 +const static char *system_bus_string[] = {
221 + "DMA_L2",
222 + "TRANS",
223 + "JPEG",
224 + "SYSTEM_UC",
225 + "DMA_UC",
226 + "SYSTEM_L2",
227 + "CCP2TX",
228 + "MPHI_RX",
229 + "MPHI_TX",
230 + "HVS",
231 + "H264",
232 + "ISP",
233 + "V3D",
234 + "PERIPHERAL",
235 + "CPU_UC",
236 + "CPU_L2"
237 +};
238 +
239 +const int num_system_buses = ARRAY_SIZE(system_bus_string);
240 +
241 +const static char *vpu_bus_string[] = {
242 + "VPU1_D_L2",
243 + "VPU0_D_L2",
244 + "VPU1_I_L2",
245 + "VPU0_I_L2",
246 + "SYSTEM_L2",
247 + "L2_FLUSH",
248 + "DMA_L2",
249 + "VPU1_D_UC",
250 + "VPU0_D_UC",
251 + "VPU1_I_UC",
252 + "VPU0_I_UC",
253 + "SYSTEM_UC",
254 + "L2_OUT",
255 + "DMA_UC",
256 + "SDRAM",
257 + "L2_IN"
258 +};
259 +
260 +const int num_vpu_buses = ARRAY_SIZE(vpu_bus_string);
261 +
262 +const static char *monitor_name[] = {
263 + "System",
264 + "VPU"
265 +};
266 +
267 +static inline void write_reg(int monitor, int reg, u32 value)
268 +{
269 + writel(value, state->monitor[monitor].base_address + reg);
270 +}
271 +
272 +static inline u32 read_reg(int monitor, u32 reg)
273 +{
274 + return readl(state->monitor[monitor].base_address + reg);
275 +}
276 +
277 +static void read_bus_watcher(int monitor, int watcher, u32 *results)
278 +{
279 + if (state->monitor[monitor].use_mailbox_interface) {
280 + /* We have 9 results, plus the overheads of start address and
281 + * length So 11 u32 to define
282 + */
283 + u32 tmp[11];
284 + int err;
285 +
286 + tmp[0] = (u32)(state->monitor[monitor].base_address + watcher
287 + + BW_ATRANS_OFFSET);
288 + tmp[1] = NUM_BUS_WATCHER_RESULTS;
289 +
290 + err = rpi_firmware_property(state->firmware,
291 + RPI_FIRMWARE_GET_PERIPH_REG,
292 + tmp, sizeof(tmp));
293 +
294 + if (err < 0 || tmp[1] != NUM_BUS_WATCHER_RESULTS)
295 + dev_err_once(&state->dev->dev,
296 + "Failed to read bus watcher");
297 + else
298 + memcpy(results, &tmp[2],
299 + NUM_BUS_WATCHER_RESULTS * sizeof(u32));
300 + } else {
301 + int i;
302 + void __iomem *addr = state->monitor[monitor].base_address
303 + + watcher + BW_ATRANS_OFFSET;
304 + for (i = 0; i < NUM_BUS_WATCHER_RESULTS; i++, addr += 4)
305 + *results++ = readl(addr);
306 + }
307 +}
308 +
309 +static void set_monitor_control(int monitor, u32 set)
310 +{
311 + if (state->monitor[monitor].use_mailbox_interface) {
312 + u32 tmp[3] = {(u32)(state->monitor[monitor].base_address +
313 + GEN_CTRL), 1, set};
314 + int err = rpi_firmware_property(state->firmware,
315 + RPI_FIRMWARE_SET_PERIPH_REG,
316 + tmp, sizeof(tmp));
317 +
318 + if (err < 0 || tmp[1] != 1)
319 + dev_err_once(&state->dev->dev,
320 + "Failed to set monitor control");
321 + } else
322 + write_reg(monitor, GEN_CTRL, set);
323 +}
324 +
325 +static void set_bus_watcher_control(int monitor, int watcher, u32 set)
326 +{
327 + if (state->monitor[monitor].use_mailbox_interface) {
328 + u32 tmp[3] = {(u32)(state->monitor[monitor].base_address +
329 + watcher), 1, set};
330 + int err = rpi_firmware_property(state->firmware,
331 + RPI_FIRMWARE_SET_PERIPH_REG,
332 + tmp, sizeof(tmp));
333 + if (err < 0 || tmp[1] != 1)
334 + dev_err_once(&state->dev->dev,
335 + "Failed to set bus watcher control");
336 + } else
337 + write_reg(monitor, watcher, set);
338 +}
339 +
340 +static void monitor(struct rpi_axiperf *state)
341 +{
342 + int monitor, num_buses[NUM_MONITORS];
343 +
344 + mutex_lock(&state->lock);
345 +
346 + for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
347 + typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
348 +
349 + /* Anything enabled? */
350 + if (mon->bus_enabled == 0) {
351 + /* No, disable all monitoring for this monitor */
352 + set_monitor_control(monitor, GEN_CTL_RESET_BIT);
353 + } else {
354 + int i;
355 +
356 + /* Find out how many busses we want to monitor, and
357 + * spread our 3 actual monitors over them
358 + */
359 + num_buses[monitor] = hweight32(mon->bus_enabled);
360 + num_buses[monitor] = min(num_buses[monitor],
361 + NUM_BUS_WATCHERS_PER_MONITOR);
362 +
363 + for (i = 0; i < num_buses[monitor]; i++) {
364 + int bus_control;
365 +
366 + do {
367 + mon->last_monitored++;
368 + mon->last_monitored &= 0xf;
369 + } while ((mon->bus_enabled &
370 + (1 << mon->last_monitored)) == 0);
371 +
372 + mon->current_bus[i] = mon->last_monitored;
373 +
374 + /* Reset the counters */
375 + set_bus_watcher_control(monitor,
376 + BW0_CTRL +
377 + i*BW_PITCH,
378 + BW_CTRL_RESET_BIT);
379 +
380 + bus_control = BW_CTRL_ENABLE_BIT |
381 + mon->current_bus[i];
382 +
383 + if (mon->bus_filter) {
384 + bus_control |=
385 + BW_CTRL_ENABLE_ID_FILTER_BIT;
386 + bus_control |=
387 + ((mon->bus_filter & 0x1f)
388 + << BW_CTRL_BUS_FILTER_SHIFT);
389 + }
390 +
391 + // Start capture
392 + set_bus_watcher_control(monitor,
393 + BW0_CTRL + i*BW_PITCH,
394 + bus_control);
395 + }
396 + }
397 +
398 + /* start monitoring */
399 + set_monitor_control(monitor, GEN_CTL_ENABLE_BIT);
400 + }
401 +
402 + mutex_unlock(&state->lock);
403 +
404 + msleep(state->sample_time);
405 +
406 + /* Now read the results */
407 +
408 + mutex_lock(&state->lock);
409 + for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
410 + typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
411 +
412 + /* Anything enabled? */
413 + if (mon->bus_enabled == 0) {
414 + /* No, disable all monitoring for this monitor */
415 + set_monitor_control(monitor, 0);
416 + } else {
417 + int i;
418 +
419 + for (i = 0; i < num_buses[monitor]; i++) {
420 + int bus = mon->current_bus[i];
421 +
422 + read_bus_watcher(monitor,
423 + BW0_CTRL + i*BW_PITCH,
424 + (u32 *)&mon->results[bus].results);
425 + }
426 + }
427 + }
428 + mutex_unlock(&state->lock);
429 +}
430 +
431 +static int monitor_thread(void *data)
432 +{
433 + struct rpi_axiperf *state = data;
434 +
435 + while (1) {
436 + monitor(state);
437 +
438 + if (kthread_should_stop())
439 + return 0;
440 + }
441 + return 0;
442 +}
443 +
444 +static ssize_t myreader(struct file *fp, char __user *user_buffer,
445 + size_t count, loff_t *position)
446 +{
447 +#define INIT_BUFF_SIZE 2048
448 +
449 + int i;
450 + int idx = (int)(fp->private_data);
451 + int num_buses, cnt;
452 + char *string_buffer;
453 + int buff_size = INIT_BUFF_SIZE;
454 + char *p;
455 + typeof(state->monitor[0]) *mon = &(state->monitor[idx]);
456 +
457 + if (idx < 0 || idx > NUM_MONITORS)
458 + idx = 0;
459 +
460 + num_buses = idx == SYSTEM_MONITOR ? num_system_buses : num_vpu_buses;
461 +
462 + string_buffer = kmalloc(buff_size, GFP_KERNEL);
463 +
464 + if (!string_buffer) {
465 + dev_err(&state->dev->dev,
466 + "Failed temporary string allocation\n");
467 + return 0;
468 + }
469 +
470 + p = string_buffer;
471 +
472 + mutex_lock(&state->lock);
473 +
474 + if (mon->bus_filter) {
475 + int filt = min(mon->bus_filter & 0x1f, num_bus_filters);
476 +
477 + cnt = snprintf(p, buff_size,
478 + "\nMonitoring transactions from %s only\n",
479 + bus_filter_strings[filt]);
480 + p += cnt;
481 + buff_size -= cnt;
482 + }
483 +
484 + cnt = snprintf(p, buff_size, " Bus | Atrans Atwait AMax Wtrans Wtwait WMax Rtrans Rtwait RMax\n"
485 + "======================================================================================================\n");
486 +
487 + if (cnt >= buff_size)
488 + goto done;
489 +
490 + p += cnt;
491 + buff_size -= cnt;
492 +
493 + for (i = 0; i < num_buses; i++) {
494 + if (mon->bus_enabled & (1 << i)) {
495 +#define DIVIDER (1024)
496 + typeof(mon->results[0]) *res = &(mon->results[i]);
497 +
498 + cnt = snprintf(p, buff_size,
499 + "%10s | %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK\n",
500 + idx == SYSTEM_MONITOR ?
501 + system_bus_string[i] :
502 + vpu_bus_string[i],
503 + res->atrans/DIVIDER,
504 + res->atwait/DIVIDER,
505 + res->amax/DIVIDER,
506 + res->wtrans/DIVIDER,
507 + res->wtwait/DIVIDER,
508 + res->wmax/DIVIDER,
509 + res->rtrans/DIVIDER,
510 + res->rtwait/DIVIDER,
511 + res->rmax/DIVIDER
512 + );
513 + if (cnt >= buff_size)
514 + goto done;
515 +
516 + p += cnt;
517 + buff_size -= cnt;
518 + }
519 + }
520 +
521 + mutex_unlock(&state->lock);
522 +
523 +done:
524 +
525 + /* did the last string entry exceeed our buffer size? ie out of string
526 + * buffer space. Null terminate, use what we have.
527 + */
528 + if (cnt >= buff_size) {
529 + buff_size = 0;
530 + string_buffer[INIT_BUFF_SIZE] = 0;
531 + }
532 +
533 + cnt = simple_read_from_buffer(user_buffer, count, position,
534 + string_buffer,
535 + INIT_BUFF_SIZE - buff_size);
536 +
537 + kfree(string_buffer);
538 +
539 + return cnt;
540 +}
541 +
542 +static ssize_t mywriter(struct file *fp, const char __user *user_buffer,
543 + size_t count, loff_t *position)
544 +{
545 + int idx = (int)(fp->private_data);
546 +
547 + if (idx < 0 || idx > NUM_MONITORS)
548 + idx = 0;
549 +
550 + /* At the moment, this does nothing, but in the future it could be
551 + * used to reset counters etc
552 + */
553 + return count;
554 +}
555 +
556 +static const struct file_operations fops_debug = {
557 + .read = myreader,
558 + .write = mywriter,
559 + .open = simple_open
560 +};
561 +
562 +static int rpi_axiperf_probe(struct platform_device *pdev)
563 +{
564 + int ret = 0, i;
565 + struct device *dev = &pdev->dev;
566 + struct device_node *np = dev->of_node;
567 + struct device_node *fw_node;
568 +
569 + state = kzalloc(sizeof(struct rpi_axiperf), GFP_KERNEL);
570 + if (!state)
571 + return -ENOMEM;
572 +
573 + /* Get the firmware handle for future rpi-firmware-xxx calls */
574 + fw_node = of_parse_phandle(np, "firmware", 0);
575 + if (!fw_node) {
576 + dev_err(dev, "Missing firmware node\n");
577 + return -ENOENT;
578 + }
579 +
580 + state->firmware = rpi_firmware_get(fw_node);
581 + if (!state->firmware)
582 + return -EPROBE_DEFER;
583 +
584 + /* Special case for the VPU monitor, we must use the mailbox interface
585 + * as it is not accessible from the ARM address space.
586 + */
587 + state->monitor[VPU_MONITOR].use_mailbox_interface = 1;
588 + state->monitor[SYSTEM_MONITOR].use_mailbox_interface = 0;
589 +
590 + for (i = 0; i < NUM_MONITORS; i++) {
591 + if (state->monitor[i].use_mailbox_interface) {
592 + of_property_read_u32_index(np, "reg", i*2,
593 + (u32 *)(&state->monitor[i].base_address));
594 + } else {
595 + struct resource *resource =
596 + platform_get_resource(pdev, IORESOURCE_MEM, i);
597 +
598 + state->monitor[i].base_address =
599 + devm_ioremap_resource(&pdev->dev, resource);
600 + }
601 +
602 + if (IS_ERR(state->monitor[i].base_address))
603 + return PTR_ERR(state->monitor[i].base_address);
604 +
605 + /* Enable all buses by default */
606 + state->monitor[i].bus_enabled = 0xffff;
607 + }
608 +
609 + state->dev = pdev;
610 + platform_set_drvdata(pdev, state);
611 +
612 + state->sample_time = DEFAULT_SAMPLE_TIME;
613 +
614 + /* Set up all the debugfs stuff */
615 + state->root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
616 +
617 + for (i = 0; i < NUM_MONITORS; i++) {
618 + state->monitor[i].debugfs_entry =
619 + debugfs_create_dir(monitor_name[i], state->root_folder);
620 + if (IS_ERR(state->monitor[i].debugfs_entry))
621 + state->monitor[i].debugfs_entry = NULL;
622 +
623 + debugfs_create_file("data", 0444,
624 + state->monitor[i].debugfs_entry,
625 + (void *)i, &fops_debug);
626 + debugfs_create_u32("enable", 0644,
627 + state->monitor[i].debugfs_entry,
628 + &state->monitor[i].bus_enabled);
629 + debugfs_create_u32("filter", 0644,
630 + state->monitor[i].debugfs_entry,
631 + &state->monitor[i].bus_filter);
632 + debugfs_create_u32("sample_time", 0644,
633 + state->monitor[i].debugfs_entry,
634 + &state->sample_time);
635 + }
636 +
637 + mutex_init(&state->lock);
638 +
639 + state->monitor_thread = kthread_run(monitor_thread, state,
640 + "rpi-axiperfmon");
641 +
642 + return ret;
643 +
644 +}
645 +
646 +static int rpi_axiperf_remove(struct platform_device *dev)
647 +{
648 + int ret = 0;
649 +
650 + kthread_stop(state->monitor_thread);
651 +
652 + debugfs_remove_recursive(state->root_folder);
653 + state->root_folder = NULL;
654 +
655 + return ret;
656 +}
657 +
658 +static const struct of_device_id rpi_axiperf_match[] = {
659 + {
660 + .compatible = "brcm,bcm2835-axiperf",
661 + },
662 + {},
663 +};
664 +MODULE_DEVICE_TABLE(of, rpi_axiperf_match);
665 +
666 +static struct platform_driver rpi_axiperf_driver = {
667 + .probe = rpi_axiperf_probe,
668 + .remove = rpi_axiperf_remove,
669 + .driver = {
670 + .name = "rpi-bcm2835-axiperf",
671 + .of_match_table = of_match_ptr(rpi_axiperf_match),
672 + },
673 +};
674 +
675 +module_platform_driver(rpi_axiperf_driver);
676 +
677 +/* Module information */
678 +MODULE_AUTHOR("James Hughes <james.hughes@raspberrypi.org>");
679 +MODULE_DESCRIPTION("RPI AXI Performance monitor driver");
680 +MODULE_LICENSE("GPL");
681 +