diff options
Diffstat (limited to 'drivers/misc/mic/cosm/cosm_sysfs.c')
-rw-r--r-- | drivers/misc/mic/cosm/cosm_sysfs.c | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/drivers/misc/mic/cosm/cosm_sysfs.c b/drivers/misc/mic/cosm/cosm_sysfs.c new file mode 100644 index 000000000000..29d6863b6e59 --- /dev/null +++ b/drivers/misc/mic/cosm/cosm_sysfs.c | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2015 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Coprocessor State Management (COSM) Driver | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/slab.h> | ||
22 | #include "cosm_main.h" | ||
23 | |||
24 | /* | ||
25 | * A state-to-string lookup table, for exposing a human readable state | ||
26 | * via sysfs. Always keep in sync with enum cosm_states | ||
27 | */ | ||
28 | const char * const cosm_state_string[] = { | ||
29 | [MIC_READY] = "ready", | ||
30 | [MIC_BOOTING] = "booting", | ||
31 | [MIC_ONLINE] = "online", | ||
32 | [MIC_SHUTTING_DOWN] = "shutting_down", | ||
33 | [MIC_RESETTING] = "resetting", | ||
34 | [MIC_RESET_FAILED] = "reset_failed", | ||
35 | }; | ||
36 | |||
37 | /* | ||
38 | * A shutdown-status-to-string lookup table, for exposing a human | ||
39 | * readable state via sysfs. Always keep in sync with enum cosm_shutdown_status | ||
40 | */ | ||
41 | const char * const cosm_shutdown_status_string[] = { | ||
42 | [MIC_NOP] = "nop", | ||
43 | [MIC_CRASHED] = "crashed", | ||
44 | [MIC_HALTED] = "halted", | ||
45 | [MIC_POWER_OFF] = "poweroff", | ||
46 | [MIC_RESTART] = "restart", | ||
47 | }; | ||
48 | |||
49 | void cosm_set_shutdown_status(struct cosm_device *cdev, u8 shutdown_status) | ||
50 | { | ||
51 | dev_dbg(&cdev->dev, "Shutdown Status %s -> %s\n", | ||
52 | cosm_shutdown_status_string[cdev->shutdown_status], | ||
53 | cosm_shutdown_status_string[shutdown_status]); | ||
54 | cdev->shutdown_status = shutdown_status; | ||
55 | } | ||
56 | |||
57 | void cosm_set_state(struct cosm_device *cdev, u8 state) | ||
58 | { | ||
59 | dev_dbg(&cdev->dev, "State %s -> %s\n", | ||
60 | cosm_state_string[cdev->state], | ||
61 | cosm_state_string[state]); | ||
62 | cdev->state = state; | ||
63 | sysfs_notify_dirent(cdev->state_sysfs); | ||
64 | } | ||
65 | |||
66 | static ssize_t | ||
67 | family_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
68 | { | ||
69 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
70 | |||
71 | if (!cdev) | ||
72 | return -EINVAL; | ||
73 | |||
74 | return cdev->hw_ops->family(cdev, buf); | ||
75 | } | ||
76 | static DEVICE_ATTR_RO(family); | ||
77 | |||
78 | static ssize_t | ||
79 | stepping_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
80 | { | ||
81 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
82 | |||
83 | if (!cdev) | ||
84 | return -EINVAL; | ||
85 | |||
86 | return cdev->hw_ops->stepping(cdev, buf); | ||
87 | } | ||
88 | static DEVICE_ATTR_RO(stepping); | ||
89 | |||
90 | static ssize_t | ||
91 | state_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
92 | { | ||
93 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
94 | |||
95 | if (!cdev || cdev->state >= MIC_LAST) | ||
96 | return -EINVAL; | ||
97 | |||
98 | return scnprintf(buf, PAGE_SIZE, "%s\n", | ||
99 | cosm_state_string[cdev->state]); | ||
100 | } | ||
101 | |||
102 | static ssize_t | ||
103 | state_store(struct device *dev, struct device_attribute *attr, | ||
104 | const char *buf, size_t count) | ||
105 | { | ||
106 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
107 | int rc; | ||
108 | |||
109 | if (!cdev) | ||
110 | return -EINVAL; | ||
111 | |||
112 | if (sysfs_streq(buf, "boot")) { | ||
113 | rc = cosm_start(cdev); | ||
114 | goto done; | ||
115 | } | ||
116 | if (sysfs_streq(buf, "reset")) { | ||
117 | rc = cosm_reset(cdev); | ||
118 | goto done; | ||
119 | } | ||
120 | |||
121 | if (sysfs_streq(buf, "shutdown")) { | ||
122 | rc = cosm_shutdown(cdev); | ||
123 | goto done; | ||
124 | } | ||
125 | rc = -EINVAL; | ||
126 | done: | ||
127 | if (rc) | ||
128 | count = rc; | ||
129 | return count; | ||
130 | } | ||
131 | static DEVICE_ATTR_RW(state); | ||
132 | |||
133 | static ssize_t shutdown_status_show(struct device *dev, | ||
134 | struct device_attribute *attr, char *buf) | ||
135 | { | ||
136 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
137 | |||
138 | if (!cdev || cdev->shutdown_status >= MIC_STATUS_LAST) | ||
139 | return -EINVAL; | ||
140 | |||
141 | return scnprintf(buf, PAGE_SIZE, "%s\n", | ||
142 | cosm_shutdown_status_string[cdev->shutdown_status]); | ||
143 | } | ||
144 | static DEVICE_ATTR_RO(shutdown_status); | ||
145 | |||
146 | static ssize_t | ||
147 | heartbeat_enable_show(struct device *dev, | ||
148 | struct device_attribute *attr, char *buf) | ||
149 | { | ||
150 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
151 | |||
152 | if (!cdev) | ||
153 | return -EINVAL; | ||
154 | |||
155 | return scnprintf(buf, PAGE_SIZE, "%d\n", cdev->sysfs_heartbeat_enable); | ||
156 | } | ||
157 | |||
158 | static ssize_t | ||
159 | heartbeat_enable_store(struct device *dev, | ||
160 | struct device_attribute *attr, | ||
161 | const char *buf, size_t count) | ||
162 | { | ||
163 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
164 | int enable; | ||
165 | int ret; | ||
166 | |||
167 | if (!cdev) | ||
168 | return -EINVAL; | ||
169 | |||
170 | mutex_lock(&cdev->cosm_mutex); | ||
171 | ret = kstrtoint(buf, 10, &enable); | ||
172 | if (ret) | ||
173 | goto unlock; | ||
174 | |||
175 | cdev->sysfs_heartbeat_enable = enable; | ||
176 | /* if state is not online, cdev->heartbeat_watchdog_enable is 0 */ | ||
177 | if (cdev->state == MIC_ONLINE) | ||
178 | cdev->heartbeat_watchdog_enable = enable; | ||
179 | ret = count; | ||
180 | unlock: | ||
181 | mutex_unlock(&cdev->cosm_mutex); | ||
182 | return ret; | ||
183 | } | ||
184 | static DEVICE_ATTR_RW(heartbeat_enable); | ||
185 | |||
186 | static ssize_t | ||
187 | cmdline_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
188 | { | ||
189 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
190 | char *cmdline; | ||
191 | |||
192 | if (!cdev) | ||
193 | return -EINVAL; | ||
194 | |||
195 | cmdline = cdev->cmdline; | ||
196 | |||
197 | if (cmdline) | ||
198 | return scnprintf(buf, PAGE_SIZE, "%s\n", cmdline); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static ssize_t | ||
203 | cmdline_store(struct device *dev, struct device_attribute *attr, | ||
204 | const char *buf, size_t count) | ||
205 | { | ||
206 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
207 | |||
208 | if (!cdev) | ||
209 | return -EINVAL; | ||
210 | |||
211 | mutex_lock(&cdev->cosm_mutex); | ||
212 | kfree(cdev->cmdline); | ||
213 | |||
214 | cdev->cmdline = kmalloc(count + 1, GFP_KERNEL); | ||
215 | if (!cdev->cmdline) { | ||
216 | count = -ENOMEM; | ||
217 | goto unlock; | ||
218 | } | ||
219 | |||
220 | strncpy(cdev->cmdline, buf, count); | ||
221 | |||
222 | if (cdev->cmdline[count - 1] == '\n') | ||
223 | cdev->cmdline[count - 1] = '\0'; | ||
224 | else | ||
225 | cdev->cmdline[count] = '\0'; | ||
226 | unlock: | ||
227 | mutex_unlock(&cdev->cosm_mutex); | ||
228 | return count; | ||
229 | } | ||
230 | static DEVICE_ATTR_RW(cmdline); | ||
231 | |||
232 | static ssize_t | ||
233 | firmware_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
234 | { | ||
235 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
236 | char *firmware; | ||
237 | |||
238 | if (!cdev) | ||
239 | return -EINVAL; | ||
240 | |||
241 | firmware = cdev->firmware; | ||
242 | |||
243 | if (firmware) | ||
244 | return scnprintf(buf, PAGE_SIZE, "%s\n", firmware); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static ssize_t | ||
249 | firmware_store(struct device *dev, struct device_attribute *attr, | ||
250 | const char *buf, size_t count) | ||
251 | { | ||
252 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
253 | |||
254 | if (!cdev) | ||
255 | return -EINVAL; | ||
256 | |||
257 | mutex_lock(&cdev->cosm_mutex); | ||
258 | kfree(cdev->firmware); | ||
259 | |||
260 | cdev->firmware = kmalloc(count + 1, GFP_KERNEL); | ||
261 | if (!cdev->firmware) { | ||
262 | count = -ENOMEM; | ||
263 | goto unlock; | ||
264 | } | ||
265 | strncpy(cdev->firmware, buf, count); | ||
266 | |||
267 | if (cdev->firmware[count - 1] == '\n') | ||
268 | cdev->firmware[count - 1] = '\0'; | ||
269 | else | ||
270 | cdev->firmware[count] = '\0'; | ||
271 | unlock: | ||
272 | mutex_unlock(&cdev->cosm_mutex); | ||
273 | return count; | ||
274 | } | ||
275 | static DEVICE_ATTR_RW(firmware); | ||
276 | |||
277 | static ssize_t | ||
278 | ramdisk_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
279 | { | ||
280 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
281 | char *ramdisk; | ||
282 | |||
283 | if (!cdev) | ||
284 | return -EINVAL; | ||
285 | |||
286 | ramdisk = cdev->ramdisk; | ||
287 | |||
288 | if (ramdisk) | ||
289 | return scnprintf(buf, PAGE_SIZE, "%s\n", ramdisk); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static ssize_t | ||
294 | ramdisk_store(struct device *dev, struct device_attribute *attr, | ||
295 | const char *buf, size_t count) | ||
296 | { | ||
297 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
298 | |||
299 | if (!cdev) | ||
300 | return -EINVAL; | ||
301 | |||
302 | mutex_lock(&cdev->cosm_mutex); | ||
303 | kfree(cdev->ramdisk); | ||
304 | |||
305 | cdev->ramdisk = kmalloc(count + 1, GFP_KERNEL); | ||
306 | if (!cdev->ramdisk) { | ||
307 | count = -ENOMEM; | ||
308 | goto unlock; | ||
309 | } | ||
310 | |||
311 | strncpy(cdev->ramdisk, buf, count); | ||
312 | |||
313 | if (cdev->ramdisk[count - 1] == '\n') | ||
314 | cdev->ramdisk[count - 1] = '\0'; | ||
315 | else | ||
316 | cdev->ramdisk[count] = '\0'; | ||
317 | unlock: | ||
318 | mutex_unlock(&cdev->cosm_mutex); | ||
319 | return count; | ||
320 | } | ||
321 | static DEVICE_ATTR_RW(ramdisk); | ||
322 | |||
323 | static ssize_t | ||
324 | bootmode_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
325 | { | ||
326 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
327 | char *bootmode; | ||
328 | |||
329 | if (!cdev) | ||
330 | return -EINVAL; | ||
331 | |||
332 | bootmode = cdev->bootmode; | ||
333 | |||
334 | if (bootmode) | ||
335 | return scnprintf(buf, PAGE_SIZE, "%s\n", bootmode); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static ssize_t | ||
340 | bootmode_store(struct device *dev, struct device_attribute *attr, | ||
341 | const char *buf, size_t count) | ||
342 | { | ||
343 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
344 | |||
345 | if (!cdev) | ||
346 | return -EINVAL; | ||
347 | |||
348 | if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "flash")) | ||
349 | return -EINVAL; | ||
350 | |||
351 | mutex_lock(&cdev->cosm_mutex); | ||
352 | kfree(cdev->bootmode); | ||
353 | |||
354 | cdev->bootmode = kmalloc(count + 1, GFP_KERNEL); | ||
355 | if (!cdev->bootmode) { | ||
356 | count = -ENOMEM; | ||
357 | goto unlock; | ||
358 | } | ||
359 | |||
360 | strncpy(cdev->bootmode, buf, count); | ||
361 | |||
362 | if (cdev->bootmode[count - 1] == '\n') | ||
363 | cdev->bootmode[count - 1] = '\0'; | ||
364 | else | ||
365 | cdev->bootmode[count] = '\0'; | ||
366 | unlock: | ||
367 | mutex_unlock(&cdev->cosm_mutex); | ||
368 | return count; | ||
369 | } | ||
370 | static DEVICE_ATTR_RW(bootmode); | ||
371 | |||
372 | static ssize_t | ||
373 | log_buf_addr_show(struct device *dev, struct device_attribute *attr, | ||
374 | char *buf) | ||
375 | { | ||
376 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
377 | |||
378 | if (!cdev) | ||
379 | return -EINVAL; | ||
380 | |||
381 | return scnprintf(buf, PAGE_SIZE, "%p\n", cdev->log_buf_addr); | ||
382 | } | ||
383 | |||
384 | static ssize_t | ||
385 | log_buf_addr_store(struct device *dev, struct device_attribute *attr, | ||
386 | const char *buf, size_t count) | ||
387 | { | ||
388 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
389 | int ret; | ||
390 | unsigned long addr; | ||
391 | |||
392 | if (!cdev) | ||
393 | return -EINVAL; | ||
394 | |||
395 | ret = kstrtoul(buf, 16, &addr); | ||
396 | if (ret) | ||
397 | goto exit; | ||
398 | |||
399 | cdev->log_buf_addr = (void *)addr; | ||
400 | ret = count; | ||
401 | exit: | ||
402 | return ret; | ||
403 | } | ||
404 | static DEVICE_ATTR_RW(log_buf_addr); | ||
405 | |||
406 | static ssize_t | ||
407 | log_buf_len_show(struct device *dev, struct device_attribute *attr, | ||
408 | char *buf) | ||
409 | { | ||
410 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
411 | |||
412 | if (!cdev) | ||
413 | return -EINVAL; | ||
414 | |||
415 | return scnprintf(buf, PAGE_SIZE, "%p\n", cdev->log_buf_len); | ||
416 | } | ||
417 | |||
418 | static ssize_t | ||
419 | log_buf_len_store(struct device *dev, struct device_attribute *attr, | ||
420 | const char *buf, size_t count) | ||
421 | { | ||
422 | struct cosm_device *cdev = dev_get_drvdata(dev); | ||
423 | int ret; | ||
424 | unsigned long addr; | ||
425 | |||
426 | if (!cdev) | ||
427 | return -EINVAL; | ||
428 | |||
429 | ret = kstrtoul(buf, 16, &addr); | ||
430 | if (ret) | ||
431 | goto exit; | ||
432 | |||
433 | cdev->log_buf_len = (int *)addr; | ||
434 | ret = count; | ||
435 | exit: | ||
436 | return ret; | ||
437 | } | ||
438 | static DEVICE_ATTR_RW(log_buf_len); | ||
439 | |||
440 | static struct attribute *cosm_default_attrs[] = { | ||
441 | &dev_attr_family.attr, | ||
442 | &dev_attr_stepping.attr, | ||
443 | &dev_attr_state.attr, | ||
444 | &dev_attr_shutdown_status.attr, | ||
445 | &dev_attr_heartbeat_enable.attr, | ||
446 | &dev_attr_cmdline.attr, | ||
447 | &dev_attr_firmware.attr, | ||
448 | &dev_attr_ramdisk.attr, | ||
449 | &dev_attr_bootmode.attr, | ||
450 | &dev_attr_log_buf_addr.attr, | ||
451 | &dev_attr_log_buf_len.attr, | ||
452 | |||
453 | NULL | ||
454 | }; | ||
455 | |||
456 | ATTRIBUTE_GROUPS(cosm_default); | ||
457 | |||
458 | void cosm_sysfs_init(struct cosm_device *cdev) | ||
459 | { | ||
460 | cdev->attr_group = cosm_default_groups; | ||
461 | } | ||