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