1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2012-2022, Intel Corporation. All rights reserved |
4 | * Intel Management Engine Interface (Intel MEI) Linux driver |
5 | */ |
6 | |
7 | #include <linux/slab.h> |
8 | #include <linux/kernel.h> |
9 | #include <linux/device.h> |
10 | #include <linux/debugfs.h> |
11 | #include <linux/seq_file.h> |
12 | |
13 | #include <linux/mei.h> |
14 | |
15 | #include "mei_dev.h" |
16 | #include "client.h" |
17 | #include "hw.h" |
18 | |
19 | static int mei_dbgfs_meclients_show(struct seq_file *m, void *unused) |
20 | { |
21 | struct mei_device *dev = m->private; |
22 | struct mei_me_client *me_cl; |
23 | int i = 0; |
24 | |
25 | if (!dev) |
26 | return -ENODEV; |
27 | |
28 | down_read(sem: &dev->me_clients_rwsem); |
29 | |
30 | seq_puts(m, s: " |id|fix| UUID |con|msg len|sb|refc|vt|\n" ); |
31 | |
32 | /* if the driver is not enabled the list won't be consistent */ |
33 | if (dev->dev_state != MEI_DEV_ENABLED) |
34 | goto out; |
35 | |
36 | list_for_each_entry(me_cl, &dev->me_clients, list) { |
37 | if (!mei_me_cl_get(me_cl)) |
38 | continue; |
39 | |
40 | seq_printf(m, fmt: "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|%2d|\n" , |
41 | i++, me_cl->client_id, |
42 | me_cl->props.fixed_address, |
43 | &me_cl->props.protocol_name, |
44 | me_cl->props.max_number_of_connections, |
45 | me_cl->props.max_msg_length, |
46 | me_cl->props.single_recv_buf, |
47 | kref_read(kref: &me_cl->refcnt), |
48 | me_cl->props.vt_supported); |
49 | mei_me_cl_put(me_cl); |
50 | } |
51 | |
52 | out: |
53 | up_read(sem: &dev->me_clients_rwsem); |
54 | return 0; |
55 | } |
56 | DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_meclients); |
57 | |
58 | static int mei_dbgfs_active_show(struct seq_file *m, void *unused) |
59 | { |
60 | struct mei_device *dev = m->private; |
61 | struct mei_cl *cl; |
62 | int i = 0; |
63 | |
64 | if (!dev) |
65 | return -ENODEV; |
66 | |
67 | mutex_lock(&dev->device_lock); |
68 | |
69 | seq_puts(m, s: " |me|host|state|rd|wr|wrq\n" ); |
70 | |
71 | /* if the driver is not enabled the list won't be consistent */ |
72 | if (dev->dev_state != MEI_DEV_ENABLED) |
73 | goto out; |
74 | |
75 | list_for_each_entry(cl, &dev->file_list, link) { |
76 | |
77 | seq_printf(m, fmt: "%3d|%2d|%4d|%5d|%2d|%2d|%3u\n" , |
78 | i, mei_cl_me_id(cl), cl->host_client_id, cl->state, |
79 | !list_empty(head: &cl->rd_completed), cl->writing_state, |
80 | cl->tx_cb_queued); |
81 | i++; |
82 | } |
83 | out: |
84 | mutex_unlock(lock: &dev->device_lock); |
85 | return 0; |
86 | } |
87 | DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_active); |
88 | |
89 | static const char *mei_dev_pxp_mode_str(enum mei_dev_pxp_mode state) |
90 | { |
91 | #define MEI_PXP_MODE(state) case MEI_DEV_PXP_##state: return #state |
92 | switch (state) { |
93 | MEI_PXP_MODE(DEFAULT); |
94 | MEI_PXP_MODE(INIT); |
95 | MEI_PXP_MODE(SETUP); |
96 | MEI_PXP_MODE(READY); |
97 | default: |
98 | return "unknown" ; |
99 | } |
100 | #undef MEI_PXP_MODE |
101 | } |
102 | |
103 | static int mei_dbgfs_devstate_show(struct seq_file *m, void *unused) |
104 | { |
105 | struct mei_device *dev = m->private; |
106 | |
107 | seq_printf(m, fmt: "dev: %s\n" , mei_dev_state_str(state: dev->dev_state)); |
108 | seq_printf(m, fmt: "hbm: %s\n" , mei_hbm_state_str(state: dev->hbm_state)); |
109 | |
110 | if (dev->hbm_state >= MEI_HBM_ENUM_CLIENTS && |
111 | dev->hbm_state <= MEI_HBM_STARTED) { |
112 | seq_puts(m, s: "hbm features:\n" ); |
113 | seq_printf(m, fmt: "\tPG: %01d\n" , dev->hbm_f_pg_supported); |
114 | seq_printf(m, fmt: "\tDC: %01d\n" , dev->hbm_f_dc_supported); |
115 | seq_printf(m, fmt: "\tIE: %01d\n" , dev->hbm_f_ie_supported); |
116 | seq_printf(m, fmt: "\tDOT: %01d\n" , dev->hbm_f_dot_supported); |
117 | seq_printf(m, fmt: "\tEV: %01d\n" , dev->hbm_f_ev_supported); |
118 | seq_printf(m, fmt: "\tFA: %01d\n" , dev->hbm_f_fa_supported); |
119 | seq_printf(m, fmt: "\tOS: %01d\n" , dev->hbm_f_os_supported); |
120 | seq_printf(m, fmt: "\tDR: %01d\n" , dev->hbm_f_dr_supported); |
121 | seq_printf(m, fmt: "\tVT: %01d\n" , dev->hbm_f_vt_supported); |
122 | seq_printf(m, fmt: "\tCAP: %01d\n" , dev->hbm_f_cap_supported); |
123 | seq_printf(m, fmt: "\tCD: %01d\n" , dev->hbm_f_cd_supported); |
124 | } |
125 | |
126 | seq_printf(m, fmt: "pg: %s, %s\n" , |
127 | mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED" , |
128 | mei_pg_state_str(state: mei_pg_state(dev))); |
129 | |
130 | seq_printf(m, fmt: "pxp: %s\n" , mei_dev_pxp_mode_str(state: dev->pxp_mode)); |
131 | |
132 | return 0; |
133 | } |
134 | DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_devstate); |
135 | |
136 | static ssize_t mei_dbgfs_write_allow_fa(struct file *file, |
137 | const char __user *user_buf, |
138 | size_t count, loff_t *ppos) |
139 | { |
140 | struct mei_device *dev; |
141 | int ret; |
142 | |
143 | dev = container_of(file->private_data, |
144 | struct mei_device, allow_fixed_address); |
145 | |
146 | ret = debugfs_write_file_bool(file, user_buf, count, ppos); |
147 | if (ret < 0) |
148 | return ret; |
149 | dev->override_fixed_address = true; |
150 | return ret; |
151 | } |
152 | |
153 | static const struct file_operations mei_dbgfs_allow_fa_fops = { |
154 | .open = simple_open, |
155 | .read = debugfs_read_file_bool, |
156 | .write = mei_dbgfs_write_allow_fa, |
157 | .llseek = generic_file_llseek, |
158 | }; |
159 | |
160 | /** |
161 | * mei_dbgfs_deregister - Remove the debugfs files and directories |
162 | * |
163 | * @dev: the mei device structure |
164 | */ |
165 | void mei_dbgfs_deregister(struct mei_device *dev) |
166 | { |
167 | if (!dev->dbgfs_dir) |
168 | return; |
169 | debugfs_remove_recursive(dentry: dev->dbgfs_dir); |
170 | dev->dbgfs_dir = NULL; |
171 | } |
172 | |
173 | /** |
174 | * mei_dbgfs_register - Add the debugfs files |
175 | * |
176 | * @dev: the mei device structure |
177 | * @name: the mei device name |
178 | */ |
179 | void mei_dbgfs_register(struct mei_device *dev, const char *name) |
180 | { |
181 | struct dentry *dir; |
182 | |
183 | dir = debugfs_create_dir(name, NULL); |
184 | dev->dbgfs_dir = dir; |
185 | |
186 | debugfs_create_file(name: "meclients" , S_IRUSR, parent: dir, data: dev, |
187 | fops: &mei_dbgfs_meclients_fops); |
188 | debugfs_create_file(name: "active" , S_IRUSR, parent: dir, data: dev, |
189 | fops: &mei_dbgfs_active_fops); |
190 | debugfs_create_file(name: "devstate" , S_IRUSR, parent: dir, data: dev, |
191 | fops: &mei_dbgfs_devstate_fops); |
192 | debugfs_create_file(name: "allow_fixed_address" , S_IRUSR | S_IWUSR, parent: dir, |
193 | data: &dev->allow_fixed_address, |
194 | fops: &mei_dbgfs_allow_fa_fops); |
195 | } |
196 | |