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