Commit | Line | Data |
---|---|---|
30e53bb8 TW |
1 | /* |
2 | * | |
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | |
4 | * Copyright (c) 2012-2013, Intel Corporation. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms and conditions of the GNU General Public License, | |
8 | * version 2, as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | */ | |
16 | #include <linux/slab.h> | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/device.h> | |
19 | #include <linux/debugfs.h> | |
30e53bb8 TW |
20 | |
21 | #include <linux/mei.h> | |
22 | ||
23 | #include "mei_dev.h" | |
79563db9 | 24 | #include "client.h" |
30e53bb8 TW |
25 | #include "hw.h" |
26 | ||
30e53bb8 TW |
27 | static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, |
28 | size_t cnt, loff_t *ppos) | |
29 | { | |
30 | struct mei_device *dev = fp->private_data; | |
b7d88514 | 31 | struct mei_me_client *me_cl; |
c4495200 AU |
32 | size_t bufsz = 1; |
33 | char *buf; | |
5ca2d388 | 34 | int i = 0; |
30e53bb8 TW |
35 | int pos = 0; |
36 | int ret; | |
37 | ||
79563db9 TW |
38 | #define HDR \ |
39 | " |id|fix| UUID |con|msg len|sb|refc|\n" | |
30e53bb8 | 40 | |
b7d88514 | 41 | down_read(&dev->me_clients_rwsem); |
c4495200 AU |
42 | list_for_each_entry(me_cl, &dev->me_clients, list) |
43 | bufsz++; | |
44 | ||
45 | bufsz *= sizeof(HDR) + 1; | |
46 | buf = kzalloc(bufsz, GFP_KERNEL); | |
47 | if (!buf) { | |
b7d88514 | 48 | up_read(&dev->me_clients_rwsem); |
c4495200 AU |
49 | return -ENOMEM; |
50 | } | |
51 | ||
52 | pos += scnprintf(buf + pos, bufsz - pos, HDR); | |
26900254 | 53 | #undef HDR |
c4495200 | 54 | |
83ce0741 | 55 | /* if the driver is not enabled the list won't be consistent */ |
30e53bb8 TW |
56 | if (dev->dev_state != MEI_DEV_ENABLED) |
57 | goto out; | |
58 | ||
b7d88514 | 59 | list_for_each_entry(me_cl, &dev->me_clients, list) { |
30e53bb8 | 60 | |
b7d88514 | 61 | if (mei_me_cl_get(me_cl)) { |
79563db9 TW |
62 | pos += scnprintf(buf + pos, bufsz - pos, |
63 | "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n", | |
64 | i++, me_cl->client_id, | |
65 | me_cl->props.fixed_address, | |
66 | &me_cl->props.protocol_name, | |
67 | me_cl->props.max_number_of_connections, | |
68 | me_cl->props.max_msg_length, | |
69 | me_cl->props.single_recv_buf, | |
2c935bc5 | 70 | kref_read(&me_cl->refcnt)); |
79563db9 | 71 | |
b7d88514 TW |
72 | mei_me_cl_put(me_cl); |
73 | } | |
30e53bb8 | 74 | } |
b7d88514 | 75 | |
30e53bb8 | 76 | out: |
b7d88514 | 77 | up_read(&dev->me_clients_rwsem); |
30e53bb8 TW |
78 | ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); |
79 | kfree(buf); | |
80 | return ret; | |
81 | } | |
82 | ||
83 | static const struct file_operations mei_dbgfs_fops_meclients = { | |
a42f82f5 | 84 | .open = simple_open, |
30e53bb8 TW |
85 | .read = mei_dbgfs_read_meclients, |
86 | .llseek = generic_file_llseek, | |
87 | }; | |
88 | ||
5baaf71f TW |
89 | static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf, |
90 | size_t cnt, loff_t *ppos) | |
91 | { | |
92 | struct mei_device *dev = fp->private_data; | |
93 | struct mei_cl *cl; | |
26900254 | 94 | size_t bufsz = 1; |
5baaf71f TW |
95 | char *buf; |
96 | int i = 0; | |
97 | int pos = 0; | |
98 | int ret; | |
99 | ||
26900254 AU |
100 | #define HDR " |me|host|state|rd|wr|\n" |
101 | ||
5baaf71f TW |
102 | if (!dev) |
103 | return -ENODEV; | |
104 | ||
26900254 AU |
105 | mutex_lock(&dev->device_lock); |
106 | ||
107 | /* | |
108 | * if the driver is not enabled the list won't be consistent, | |
109 | * we output empty table | |
110 | */ | |
111 | if (dev->dev_state == MEI_DEV_ENABLED) | |
112 | list_for_each_entry(cl, &dev->file_list, link) | |
113 | bufsz++; | |
114 | ||
115 | bufsz *= sizeof(HDR) + 1; | |
116 | ||
5baaf71f | 117 | buf = kzalloc(bufsz, GFP_KERNEL); |
26900254 AU |
118 | if (!buf) { |
119 | mutex_unlock(&dev->device_lock); | |
5baaf71f | 120 | return -ENOMEM; |
26900254 | 121 | } |
5baaf71f | 122 | |
26900254 AU |
123 | pos += scnprintf(buf + pos, bufsz - pos, HDR); |
124 | #undef HDR | |
5baaf71f | 125 | |
0a01e974 | 126 | /* if the driver is not enabled the list won't be consistent */ |
5baaf71f TW |
127 | if (dev->dev_state != MEI_DEV_ENABLED) |
128 | goto out; | |
129 | ||
130 | list_for_each_entry(cl, &dev->file_list, link) { | |
131 | ||
132 | pos += scnprintf(buf + pos, bufsz - pos, | |
26900254 | 133 | "%3d|%2d|%4d|%5d|%2d|%2d|\n", |
d49ed64a | 134 | i, mei_cl_me_id(cl), cl->host_client_id, cl->state, |
a9bed610 | 135 | !list_empty(&cl->rd_completed), cl->writing_state); |
5baaf71f TW |
136 | i++; |
137 | } | |
138 | out: | |
139 | mutex_unlock(&dev->device_lock); | |
140 | ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); | |
141 | kfree(buf); | |
142 | return ret; | |
143 | } | |
144 | ||
145 | static const struct file_operations mei_dbgfs_fops_active = { | |
146 | .open = simple_open, | |
147 | .read = mei_dbgfs_read_active, | |
148 | .llseek = generic_file_llseek, | |
149 | }; | |
150 | ||
30e53bb8 TW |
151 | static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, |
152 | size_t cnt, loff_t *ppos) | |
153 | { | |
154 | struct mei_device *dev = fp->private_data; | |
155 | const size_t bufsz = 1024; | |
156 | char *buf = kzalloc(bufsz, GFP_KERNEL); | |
157 | int pos = 0; | |
158 | int ret; | |
159 | ||
160 | if (!buf) | |
161 | return -ENOMEM; | |
162 | ||
1beeb4b9 | 163 | pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n", |
30e53bb8 | 164 | mei_dev_state_str(dev->dev_state)); |
1beeb4b9 AU |
165 | pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n", |
166 | mei_hbm_state_str(dev->hbm_state)); | |
5b20a028 | 167 | |
439a74b3 AU |
168 | if (dev->hbm_state >= MEI_HBM_ENUM_CLIENTS && |
169 | dev->hbm_state <= MEI_HBM_STARTED) { | |
5b20a028 TW |
170 | pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n"); |
171 | pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n", | |
172 | dev->hbm_f_pg_supported); | |
70ef835c TW |
173 | pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n", |
174 | dev->hbm_f_dc_supported); | |
27f476ea AU |
175 | pos += scnprintf(buf + pos, bufsz - pos, "\tIE: %01d\n", |
176 | dev->hbm_f_ie_supported); | |
18901357 AU |
177 | pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n", |
178 | dev->hbm_f_dot_supported); | |
4d99877d TW |
179 | pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n", |
180 | dev->hbm_f_ev_supported); | |
f4e06246 AU |
181 | pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n", |
182 | dev->hbm_f_fa_supported); | |
7ee7f45a AU |
183 | pos += scnprintf(buf + pos, bufsz - pos, "\tOS: %01d\n", |
184 | dev->hbm_f_os_supported); | |
5b20a028 TW |
185 | } |
186 | ||
1beeb4b9 AU |
187 | pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", |
188 | mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED", | |
189 | mei_pg_state_str(mei_pg_state(dev))); | |
30e53bb8 TW |
190 | ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); |
191 | kfree(buf); | |
192 | return ret; | |
193 | } | |
194 | static const struct file_operations mei_dbgfs_fops_devstate = { | |
a42f82f5 | 195 | .open = simple_open, |
30e53bb8 TW |
196 | .read = mei_dbgfs_read_devstate, |
197 | .llseek = generic_file_llseek, | |
198 | }; | |
199 | ||
f4e06246 AU |
200 | static ssize_t mei_dbgfs_write_allow_fa(struct file *file, |
201 | const char __user *user_buf, | |
202 | size_t count, loff_t *ppos) | |
203 | { | |
204 | struct mei_device *dev; | |
205 | int ret; | |
206 | ||
207 | dev = container_of(file->private_data, | |
208 | struct mei_device, allow_fixed_address); | |
209 | ||
210 | ret = debugfs_write_file_bool(file, user_buf, count, ppos); | |
211 | if (ret < 0) | |
212 | return ret; | |
213 | dev->override_fixed_address = true; | |
214 | return ret; | |
215 | } | |
216 | ||
217 | static const struct file_operations mei_dbgfs_fops_allow_fa = { | |
218 | .open = simple_open, | |
219 | .read = debugfs_read_file_bool, | |
220 | .write = mei_dbgfs_write_allow_fa, | |
221 | .llseek = generic_file_llseek, | |
222 | }; | |
223 | ||
30e53bb8 TW |
224 | /** |
225 | * mei_dbgfs_deregister - Remove the debugfs files and directories | |
a8605ea2 AU |
226 | * |
227 | * @dev: the mei device structure | |
30e53bb8 TW |
228 | */ |
229 | void mei_dbgfs_deregister(struct mei_device *dev) | |
230 | { | |
231 | if (!dev->dbgfs_dir) | |
232 | return; | |
233 | debugfs_remove_recursive(dev->dbgfs_dir); | |
234 | dev->dbgfs_dir = NULL; | |
235 | } | |
236 | ||
237 | /** | |
a8605ea2 | 238 | * mei_dbgfs_register - Add the debugfs files |
30e53bb8 | 239 | * |
a8605ea2 AU |
240 | * @dev: the mei device structure |
241 | * @name: the mei device name | |
ce23139c AU |
242 | * |
243 | * Return: 0 on success, <0 on failure. | |
30e53bb8 TW |
244 | */ |
245 | int mei_dbgfs_register(struct mei_device *dev, const char *name) | |
246 | { | |
247 | struct dentry *dir, *f; | |
92db1555 | 248 | |
30e53bb8 TW |
249 | dir = debugfs_create_dir(name, NULL); |
250 | if (!dir) | |
251 | return -ENOMEM; | |
252 | ||
5964db08 TW |
253 | dev->dbgfs_dir = dir; |
254 | ||
30e53bb8 TW |
255 | f = debugfs_create_file("meclients", S_IRUSR, dir, |
256 | dev, &mei_dbgfs_fops_meclients); | |
257 | if (!f) { | |
2bf94cab | 258 | dev_err(dev->dev, "meclients: registration failed\n"); |
30e53bb8 TW |
259 | goto err; |
260 | } | |
5baaf71f TW |
261 | f = debugfs_create_file("active", S_IRUSR, dir, |
262 | dev, &mei_dbgfs_fops_active); | |
263 | if (!f) { | |
2be7010c | 264 | dev_err(dev->dev, "active: registration failed\n"); |
5baaf71f TW |
265 | goto err; |
266 | } | |
30e53bb8 TW |
267 | f = debugfs_create_file("devstate", S_IRUSR, dir, |
268 | dev, &mei_dbgfs_fops_devstate); | |
269 | if (!f) { | |
2bf94cab | 270 | dev_err(dev->dev, "devstate: registration failed\n"); |
30e53bb8 TW |
271 | goto err; |
272 | } | |
f4e06246 AU |
273 | f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir, |
274 | &dev->allow_fixed_address, | |
275 | &mei_dbgfs_fops_allow_fa); | |
eeabfcf5 AU |
276 | if (!f) { |
277 | dev_err(dev->dev, "allow_fixed_address: registration failed\n"); | |
278 | goto err; | |
279 | } | |
30e53bb8 TW |
280 | return 0; |
281 | err: | |
282 | mei_dbgfs_deregister(dev); | |
283 | return -ENODEV; | |
284 | } | |
285 |