linux/drivers/misc/mic/cosm/cosm_sysfs.c
<<
>>
Prefs
   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}
 450