1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ |
3 | #include <linux/init.h> |
4 | #include <linux/kernel.h> |
5 | #include <linux/module.h> |
6 | #include <linux/pci.h> |
7 | #include <linux/debugfs.h> |
8 | #include <linux/io-64-nonatomic-lo-hi.h> |
9 | #include <uapi/linux/idxd.h> |
10 | #include "idxd.h" |
11 | #include "registers.h" |
12 | |
13 | static struct dentry *idxd_debugfs_dir; |
14 | |
15 | static void dump_event_entry(struct idxd_device *idxd, struct seq_file *s, |
16 | u16 index, int *count, bool processed) |
17 | { |
18 | struct idxd_evl *evl = idxd->evl; |
19 | struct dsa_evl_entry *entry; |
20 | struct dsa_completion_record *cr; |
21 | u64 *raw; |
22 | int i; |
23 | int evl_strides = evl_ent_size(idxd) / sizeof(u64); |
24 | |
25 | entry = (struct dsa_evl_entry *)evl->log + index; |
26 | |
27 | if (!entry->e.desc_valid) |
28 | return; |
29 | |
30 | seq_printf(m: s, fmt: "Event Log entry %d (real index %u) processed: %u\n" , |
31 | *count, index, processed); |
32 | |
33 | seq_printf(m: s, fmt: "desc valid %u wq idx valid %u\n" |
34 | "batch %u fault rw %u priv %u error 0x%x\n" |
35 | "wq idx %u op %#x pasid %u batch idx %u\n" |
36 | "fault addr %#llx\n" , |
37 | entry->e.desc_valid, entry->e.wq_idx_valid, |
38 | entry->e.batch, entry->e.fault_rw, entry->e.priv, |
39 | entry->e.error, entry->e.wq_idx, entry->e.operation, |
40 | entry->e.pasid, entry->e.batch_idx, entry->e.fault_addr); |
41 | |
42 | cr = &entry->cr; |
43 | seq_printf(m: s, fmt: "status %#x result %#x fault_info %#x bytes_completed %u\n" |
44 | "fault addr %#llx inv flags %#x\n\n" , |
45 | cr->status, cr->result, cr->fault_info, cr->bytes_completed, |
46 | cr->fault_addr, cr->invalid_flags); |
47 | |
48 | raw = (u64 *)entry; |
49 | |
50 | for (i = 0; i < evl_strides; i++) |
51 | seq_printf(m: s, fmt: "entry[%d] = %#llx\n" , i, raw[i]); |
52 | |
53 | seq_puts(m: s, s: "\n" ); |
54 | *count += 1; |
55 | } |
56 | |
57 | static int debugfs_evl_show(struct seq_file *s, void *d) |
58 | { |
59 | struct idxd_device *idxd = s->private; |
60 | struct idxd_evl *evl = idxd->evl; |
61 | union evl_status_reg evl_status; |
62 | u16 h, t, evl_size, i; |
63 | int count = 0; |
64 | bool processed = true; |
65 | |
66 | if (!evl || !evl->log) |
67 | return 0; |
68 | |
69 | spin_lock(lock: &evl->lock); |
70 | |
71 | evl_status.bits = ioread64(addr: idxd->reg_base + IDXD_EVLSTATUS_OFFSET); |
72 | t = evl_status.tail; |
73 | h = evl_status.head; |
74 | evl_size = evl->size; |
75 | |
76 | seq_printf(m: s, fmt: "Event Log head %u tail %u interrupt pending %u\n\n" , |
77 | evl_status.head, evl_status.tail, evl_status.int_pending); |
78 | |
79 | i = t; |
80 | while (1) { |
81 | i = (i + 1) % evl_size; |
82 | if (i == t) |
83 | break; |
84 | |
85 | if (processed && i == h) |
86 | processed = false; |
87 | dump_event_entry(idxd, s, index: i, count: &count, processed); |
88 | } |
89 | |
90 | spin_unlock(lock: &evl->lock); |
91 | return 0; |
92 | } |
93 | |
94 | DEFINE_SHOW_ATTRIBUTE(debugfs_evl); |
95 | |
96 | int idxd_device_init_debugfs(struct idxd_device *idxd) |
97 | { |
98 | if (IS_ERR_OR_NULL(ptr: idxd_debugfs_dir)) |
99 | return 0; |
100 | |
101 | idxd->dbgfs_dir = debugfs_create_dir(name: dev_name(idxd_confdev(idxd)), parent: idxd_debugfs_dir); |
102 | if (IS_ERR(ptr: idxd->dbgfs_dir)) |
103 | return PTR_ERR(ptr: idxd->dbgfs_dir); |
104 | |
105 | if (idxd->evl) { |
106 | idxd->dbgfs_evl_file = debugfs_create_file(name: "event_log" , mode: 0400, |
107 | parent: idxd->dbgfs_dir, data: idxd, |
108 | fops: &debugfs_evl_fops); |
109 | if (IS_ERR(ptr: idxd->dbgfs_evl_file)) { |
110 | debugfs_remove_recursive(dentry: idxd->dbgfs_dir); |
111 | idxd->dbgfs_dir = NULL; |
112 | return PTR_ERR(ptr: idxd->dbgfs_evl_file); |
113 | } |
114 | } |
115 | |
116 | return 0; |
117 | } |
118 | |
119 | void idxd_device_remove_debugfs(struct idxd_device *idxd) |
120 | { |
121 | debugfs_remove_recursive(dentry: idxd->dbgfs_dir); |
122 | } |
123 | |
124 | int idxd_init_debugfs(void) |
125 | { |
126 | if (!debugfs_initialized()) |
127 | return 0; |
128 | |
129 | idxd_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); |
130 | if (IS_ERR(ptr: idxd_debugfs_dir)) |
131 | return PTR_ERR(ptr: idxd_debugfs_dir); |
132 | return 0; |
133 | } |
134 | |
135 | void idxd_remove_debugfs(void) |
136 | { |
137 | debugfs_remove_recursive(dentry: idxd_debugfs_dir); |
138 | } |
139 | |