Commit | Line | Data |
---|---|---|
b170d8ce SD |
1 | /* |
2 | * Intel MIC Platform Software Stack (MPSS) | |
3 | * | |
4 | * Copyright(c) 2013 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 Host driver. | |
19 | * | |
20 | */ | |
21 | #include <linux/pci.h> | |
22 | ||
3a6a9201 | 23 | #include <linux/mic_common.h> |
4aa79961 | 24 | #include "../common/mic_dev.h" |
b170d8ce SD |
25 | #include "mic_device.h" |
26 | ||
3a6a9201 SD |
27 | /* |
28 | * A state-to-string lookup table, for exposing a human readable state | |
29 | * via sysfs. Always keep in sync with enum mic_states | |
30 | */ | |
31 | static const char * const mic_state_string[] = { | |
32 | [MIC_OFFLINE] = "offline", | |
33 | [MIC_ONLINE] = "online", | |
34 | [MIC_SHUTTING_DOWN] = "shutting_down", | |
35 | [MIC_RESET_FAILED] = "reset_failed", | |
36 | }; | |
37 | ||
38 | /* | |
39 | * A shutdown-status-to-string lookup table, for exposing a human | |
40 | * readable state via sysfs. Always keep in sync with enum mic_shutdown_status | |
41 | */ | |
42 | static const char * const mic_shutdown_status_string[] = { | |
43 | [MIC_NOP] = "nop", | |
44 | [MIC_CRASHED] = "crashed", | |
45 | [MIC_HALTED] = "halted", | |
46 | [MIC_POWER_OFF] = "poweroff", | |
47 | [MIC_RESTART] = "restart", | |
48 | }; | |
49 | ||
50 | void mic_set_shutdown_status(struct mic_device *mdev, u8 shutdown_status) | |
51 | { | |
52 | dev_dbg(mdev->sdev->parent, "Shutdown Status %s -> %s\n", | |
53 | mic_shutdown_status_string[mdev->shutdown_status], | |
54 | mic_shutdown_status_string[shutdown_status]); | |
55 | mdev->shutdown_status = shutdown_status; | |
56 | } | |
57 | ||
58 | void mic_set_state(struct mic_device *mdev, u8 state) | |
59 | { | |
60 | dev_dbg(mdev->sdev->parent, "State %s -> %s\n", | |
61 | mic_state_string[mdev->state], | |
62 | mic_state_string[state]); | |
63 | mdev->state = state; | |
64 | sysfs_notify_dirent(mdev->state_sysfs); | |
65 | } | |
66 | ||
b170d8ce | 67 | static ssize_t |
2ce58528 | 68 | family_show(struct device *dev, struct device_attribute *attr, char *buf) |
b170d8ce SD |
69 | { |
70 | static const char x100[] = "x100"; | |
71 | static const char unknown[] = "Unknown"; | |
72 | const char *card = NULL; | |
73 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
74 | ||
75 | if (!mdev) | |
76 | return -EINVAL; | |
77 | ||
78 | switch (mdev->family) { | |
79 | case MIC_FAMILY_X100: | |
80 | card = x100; | |
81 | break; | |
82 | default: | |
83 | card = unknown; | |
84 | break; | |
85 | } | |
86 | return scnprintf(buf, PAGE_SIZE, "%s\n", card); | |
87 | } | |
2ce58528 | 88 | static DEVICE_ATTR_RO(family); |
b170d8ce SD |
89 | |
90 | static ssize_t | |
2ce58528 | 91 | stepping_show(struct device *dev, struct device_attribute *attr, char *buf) |
b170d8ce SD |
92 | { |
93 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
94 | char *string = "??"; | |
95 | ||
96 | if (!mdev) | |
97 | return -EINVAL; | |
98 | ||
99 | switch (mdev->stepping) { | |
100 | case MIC_A0_STEP: | |
101 | string = "A0"; | |
102 | break; | |
103 | case MIC_B0_STEP: | |
104 | string = "B0"; | |
105 | break; | |
106 | case MIC_B1_STEP: | |
107 | string = "B1"; | |
108 | break; | |
109 | case MIC_C0_STEP: | |
110 | string = "C0"; | |
111 | break; | |
112 | default: | |
113 | break; | |
114 | } | |
115 | return scnprintf(buf, PAGE_SIZE, "%s\n", string); | |
116 | } | |
2ce58528 | 117 | static DEVICE_ATTR_RO(stepping); |
b170d8ce | 118 | |
3a6a9201 | 119 | static ssize_t |
2ce58528 | 120 | state_show(struct device *dev, struct device_attribute *attr, char *buf) |
3a6a9201 SD |
121 | { |
122 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
123 | ||
124 | if (!mdev || mdev->state >= MIC_LAST) | |
125 | return -EINVAL; | |
126 | ||
127 | return scnprintf(buf, PAGE_SIZE, "%s\n", | |
128 | mic_state_string[mdev->state]); | |
129 | } | |
130 | ||
131 | static ssize_t | |
2ce58528 | 132 | state_store(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
133 | const char *buf, size_t count) |
134 | { | |
135 | int rc = 0; | |
136 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
137 | if (!mdev) | |
138 | return -EINVAL; | |
139 | if (sysfs_streq(buf, "boot")) { | |
140 | rc = mic_start(mdev, buf); | |
141 | if (rc) { | |
142 | dev_err(mdev->sdev->parent, | |
143 | "mic_boot failed rc %d\n", rc); | |
144 | count = rc; | |
145 | } | |
146 | goto done; | |
147 | } | |
148 | ||
149 | if (sysfs_streq(buf, "reset")) { | |
150 | schedule_work(&mdev->reset_trigger_work); | |
151 | goto done; | |
152 | } | |
153 | ||
154 | if (sysfs_streq(buf, "shutdown")) { | |
155 | mic_shutdown(mdev); | |
156 | goto done; | |
157 | } | |
158 | ||
159 | count = -EINVAL; | |
160 | done: | |
161 | return count; | |
162 | } | |
2ce58528 | 163 | static DEVICE_ATTR_RW(state); |
3a6a9201 | 164 | |
2ce58528 | 165 | static ssize_t shutdown_status_show(struct device *dev, |
3a6a9201 SD |
166 | struct device_attribute *attr, char *buf) |
167 | { | |
168 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
169 | ||
170 | if (!mdev || mdev->shutdown_status >= MIC_STATUS_LAST) | |
171 | return -EINVAL; | |
172 | ||
173 | return scnprintf(buf, PAGE_SIZE, "%s\n", | |
174 | mic_shutdown_status_string[mdev->shutdown_status]); | |
175 | } | |
2ce58528 | 176 | static DEVICE_ATTR_RO(shutdown_status); |
3a6a9201 SD |
177 | |
178 | static ssize_t | |
2ce58528 | 179 | cmdline_show(struct device *dev, struct device_attribute *attr, char *buf) |
3a6a9201 SD |
180 | { |
181 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
182 | char *cmdline; | |
183 | ||
184 | if (!mdev) | |
185 | return -EINVAL; | |
186 | ||
187 | cmdline = mdev->cmdline; | |
188 | ||
189 | if (cmdline) | |
190 | return scnprintf(buf, PAGE_SIZE, "%s\n", cmdline); | |
191 | return 0; | |
192 | } | |
193 | ||
194 | static ssize_t | |
2ce58528 | 195 | cmdline_store(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
196 | const char *buf, size_t count) |
197 | { | |
198 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
199 | ||
200 | if (!mdev) | |
201 | return -EINVAL; | |
202 | ||
203 | mutex_lock(&mdev->mic_mutex); | |
204 | kfree(mdev->cmdline); | |
205 | ||
206 | mdev->cmdline = kmalloc(count + 1, GFP_KERNEL); | |
207 | if (!mdev->cmdline) { | |
208 | count = -ENOMEM; | |
209 | goto unlock; | |
210 | } | |
211 | ||
212 | strncpy(mdev->cmdline, buf, count); | |
213 | ||
214 | if (mdev->cmdline[count - 1] == '\n') | |
215 | mdev->cmdline[count - 1] = '\0'; | |
216 | else | |
217 | mdev->cmdline[count] = '\0'; | |
218 | unlock: | |
219 | mutex_unlock(&mdev->mic_mutex); | |
220 | return count; | |
221 | } | |
2ce58528 | 222 | static DEVICE_ATTR_RW(cmdline); |
3a6a9201 SD |
223 | |
224 | static ssize_t | |
2ce58528 | 225 | firmware_show(struct device *dev, struct device_attribute *attr, char *buf) |
3a6a9201 SD |
226 | { |
227 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
228 | char *firmware; | |
229 | ||
230 | if (!mdev) | |
231 | return -EINVAL; | |
232 | ||
233 | firmware = mdev->firmware; | |
234 | ||
235 | if (firmware) | |
236 | return scnprintf(buf, PAGE_SIZE, "%s\n", firmware); | |
237 | return 0; | |
238 | } | |
239 | ||
240 | static ssize_t | |
2ce58528 | 241 | firmware_store(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
242 | const char *buf, size_t count) |
243 | { | |
244 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
245 | ||
246 | if (!mdev) | |
247 | return -EINVAL; | |
248 | ||
249 | mutex_lock(&mdev->mic_mutex); | |
250 | kfree(mdev->firmware); | |
251 | ||
252 | mdev->firmware = kmalloc(count + 1, GFP_KERNEL); | |
253 | if (!mdev->firmware) { | |
254 | count = -ENOMEM; | |
255 | goto unlock; | |
256 | } | |
257 | strncpy(mdev->firmware, buf, count); | |
258 | ||
259 | if (mdev->firmware[count - 1] == '\n') | |
260 | mdev->firmware[count - 1] = '\0'; | |
261 | else | |
262 | mdev->firmware[count] = '\0'; | |
263 | unlock: | |
264 | mutex_unlock(&mdev->mic_mutex); | |
265 | return count; | |
266 | } | |
2ce58528 | 267 | static DEVICE_ATTR_RW(firmware); |
3a6a9201 SD |
268 | |
269 | static ssize_t | |
2ce58528 | 270 | ramdisk_show(struct device *dev, struct device_attribute *attr, char *buf) |
3a6a9201 SD |
271 | { |
272 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
273 | char *ramdisk; | |
274 | ||
275 | if (!mdev) | |
276 | return -EINVAL; | |
277 | ||
278 | ramdisk = mdev->ramdisk; | |
279 | ||
280 | if (ramdisk) | |
281 | return scnprintf(buf, PAGE_SIZE, "%s\n", ramdisk); | |
282 | return 0; | |
283 | } | |
284 | ||
285 | static ssize_t | |
2ce58528 | 286 | ramdisk_store(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
287 | const char *buf, size_t count) |
288 | { | |
289 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
290 | ||
291 | if (!mdev) | |
292 | return -EINVAL; | |
293 | ||
294 | mutex_lock(&mdev->mic_mutex); | |
295 | kfree(mdev->ramdisk); | |
296 | ||
297 | mdev->ramdisk = kmalloc(count + 1, GFP_KERNEL); | |
298 | if (!mdev->ramdisk) { | |
299 | count = -ENOMEM; | |
300 | goto unlock; | |
301 | } | |
302 | ||
303 | strncpy(mdev->ramdisk, buf, count); | |
304 | ||
305 | if (mdev->ramdisk[count - 1] == '\n') | |
306 | mdev->ramdisk[count - 1] = '\0'; | |
307 | else | |
308 | mdev->ramdisk[count] = '\0'; | |
309 | unlock: | |
310 | mutex_unlock(&mdev->mic_mutex); | |
311 | return count; | |
312 | } | |
2ce58528 | 313 | static DEVICE_ATTR_RW(ramdisk); |
3a6a9201 SD |
314 | |
315 | static ssize_t | |
2ce58528 | 316 | bootmode_show(struct device *dev, struct device_attribute *attr, char *buf) |
3a6a9201 SD |
317 | { |
318 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
319 | char *bootmode; | |
320 | ||
321 | if (!mdev) | |
322 | return -EINVAL; | |
323 | ||
324 | bootmode = mdev->bootmode; | |
325 | ||
326 | if (bootmode) | |
327 | return scnprintf(buf, PAGE_SIZE, "%s\n", bootmode); | |
328 | return 0; | |
329 | } | |
330 | ||
331 | static ssize_t | |
2ce58528 | 332 | bootmode_store(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
333 | const char *buf, size_t count) |
334 | { | |
335 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
336 | ||
337 | if (!mdev) | |
338 | return -EINVAL; | |
339 | ||
340 | if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "elf")) | |
341 | return -EINVAL; | |
342 | ||
343 | mutex_lock(&mdev->mic_mutex); | |
344 | kfree(mdev->bootmode); | |
345 | ||
346 | mdev->bootmode = kmalloc(count + 1, GFP_KERNEL); | |
347 | if (!mdev->bootmode) { | |
348 | count = -ENOMEM; | |
349 | goto unlock; | |
350 | } | |
351 | ||
352 | strncpy(mdev->bootmode, buf, count); | |
353 | ||
354 | if (mdev->bootmode[count - 1] == '\n') | |
355 | mdev->bootmode[count - 1] = '\0'; | |
356 | else | |
357 | mdev->bootmode[count] = '\0'; | |
358 | unlock: | |
359 | mutex_unlock(&mdev->mic_mutex); | |
360 | return count; | |
361 | } | |
2ce58528 | 362 | static DEVICE_ATTR_RW(bootmode); |
3a6a9201 SD |
363 | |
364 | static ssize_t | |
2ce58528 | 365 | log_buf_addr_show(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
366 | char *buf) |
367 | { | |
368 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
369 | ||
370 | if (!mdev) | |
371 | return -EINVAL; | |
372 | ||
373 | return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_addr); | |
374 | } | |
375 | ||
376 | static ssize_t | |
2ce58528 | 377 | log_buf_addr_store(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
378 | const char *buf, size_t count) |
379 | { | |
380 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
381 | int ret; | |
382 | unsigned long addr; | |
383 | ||
384 | if (!mdev) | |
385 | return -EINVAL; | |
386 | ||
387 | ret = kstrtoul(buf, 16, &addr); | |
388 | if (ret) | |
389 | goto exit; | |
390 | ||
391 | mdev->log_buf_addr = (void *)addr; | |
392 | ret = count; | |
393 | exit: | |
394 | return ret; | |
395 | } | |
2ce58528 | 396 | static DEVICE_ATTR_RW(log_buf_addr); |
3a6a9201 SD |
397 | |
398 | static ssize_t | |
2ce58528 | 399 | log_buf_len_show(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
400 | char *buf) |
401 | { | |
402 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
403 | ||
404 | if (!mdev) | |
405 | return -EINVAL; | |
406 | ||
407 | return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_len); | |
408 | } | |
409 | ||
410 | static ssize_t | |
2ce58528 | 411 | log_buf_len_store(struct device *dev, struct device_attribute *attr, |
3a6a9201 SD |
412 | const char *buf, size_t count) |
413 | { | |
414 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
415 | int ret; | |
416 | unsigned long addr; | |
417 | ||
418 | if (!mdev) | |
419 | return -EINVAL; | |
420 | ||
421 | ret = kstrtoul(buf, 16, &addr); | |
422 | if (ret) | |
423 | goto exit; | |
424 | ||
425 | mdev->log_buf_len = (int *)addr; | |
426 | ret = count; | |
427 | exit: | |
428 | return ret; | |
429 | } | |
2ce58528 | 430 | static DEVICE_ATTR_RW(log_buf_len); |
3a6a9201 | 431 | |
b170d8ce SD |
432 | static struct attribute *mic_default_attrs[] = { |
433 | &dev_attr_family.attr, | |
434 | &dev_attr_stepping.attr, | |
3a6a9201 SD |
435 | &dev_attr_state.attr, |
436 | &dev_attr_shutdown_status.attr, | |
437 | &dev_attr_cmdline.attr, | |
438 | &dev_attr_firmware.attr, | |
439 | &dev_attr_ramdisk.attr, | |
440 | &dev_attr_bootmode.attr, | |
441 | &dev_attr_log_buf_addr.attr, | |
442 | &dev_attr_log_buf_len.attr, | |
b170d8ce SD |
443 | |
444 | NULL | |
445 | }; | |
446 | ||
2ce58528 | 447 | ATTRIBUTE_GROUPS(mic_default); |
b170d8ce SD |
448 | |
449 | void mic_sysfs_init(struct mic_device *mdev) | |
450 | { | |
2ce58528 | 451 | mdev->attr_group = mic_default_groups; |
b170d8ce | 452 | } |