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