linux/drivers/misc/mic/cosm/cosm_sysfs.c
Thomas Gleixner 4e43d779e5 treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 290
Based on 1 normalized pattern(s):

  this program is free software you can redistribute it and or modify
  it under the terms of the gnu general public license version 2 as
  published by the free software foundation this program is
  distributed in the hope that it will be useful but without any
  warranty without even the implied warranty of merchantability or
  fitness for a particular purpose see the gnu general public license
  for more details the full gnu general public license is included in
  this distribution in the file called copying

extracted by the scancode license scanner the SPDX license identifier

  GPL-2.0-only

has been chosen to replace the boilerplate/reference in 39 file(s).

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Allison Randal <allison@lohutok.net>
Reviewed-by: Alexios Zavras <alexios.zavras@intel.com>
Cc: linux-spdx@vger.kernel.org
Link: https://lkml.kernel.org/r/20190529141901.397680977@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-06-05 17:36:38 +02:00

450 lines
9.3 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2015 Intel Corporation.
*
* Intel MIC Coprocessor State Management (COSM) Driver
*/
#include <linux/slab.h>
#include "cosm_main.h"
/*
* A state-to-string lookup table, for exposing a human readable state
* via sysfs. Always keep in sync with enum cosm_states
*/
const char * const cosm_state_string[] = {
[MIC_READY] = "ready",
[MIC_BOOTING] = "booting",
[MIC_ONLINE] = "online",
[MIC_SHUTTING_DOWN] = "shutting_down",
[MIC_RESETTING] = "resetting",
[MIC_RESET_FAILED] = "reset_failed",
};
/*
* A shutdown-status-to-string lookup table, for exposing a human
* readable state via sysfs. Always keep in sync with enum cosm_shutdown_status
*/
const char * const cosm_shutdown_status_string[] = {
[MIC_NOP] = "nop",
[MIC_CRASHED] = "crashed",
[MIC_HALTED] = "halted",
[MIC_POWER_OFF] = "poweroff",
[MIC_RESTART] = "restart",
};
void cosm_set_shutdown_status(struct cosm_device *cdev, u8 shutdown_status)
{
dev_dbg(&cdev->dev, "Shutdown Status %s -> %s\n",
cosm_shutdown_status_string[cdev->shutdown_status],
cosm_shutdown_status_string[shutdown_status]);
cdev->shutdown_status = shutdown_status;
}
void cosm_set_state(struct cosm_device *cdev, u8 state)
{
dev_dbg(&cdev->dev, "State %s -> %s\n",
cosm_state_string[cdev->state],
cosm_state_string[state]);
cdev->state = state;
sysfs_notify_dirent(cdev->state_sysfs);
}
static ssize_t
family_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
return cdev->hw_ops->family(cdev, buf);
}
static DEVICE_ATTR_RO(family);
static ssize_t
stepping_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
return cdev->hw_ops->stepping(cdev, buf);
}
static DEVICE_ATTR_RO(stepping);
static ssize_t
state_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev || cdev->state >= MIC_LAST)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%s\n",
cosm_state_string[cdev->state]);
}
static ssize_t
state_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
int rc;
if (!cdev)
return -EINVAL;
if (sysfs_streq(buf, "boot")) {
rc = cosm_start(cdev);
goto done;
}
if (sysfs_streq(buf, "reset")) {
rc = cosm_reset(cdev);
goto done;
}
if (sysfs_streq(buf, "shutdown")) {
rc = cosm_shutdown(cdev);
goto done;
}
rc = -EINVAL;
done:
if (rc)
count = rc;
return count;
}
static DEVICE_ATTR_RW(state);
static ssize_t shutdown_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev || cdev->shutdown_status >= MIC_STATUS_LAST)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%s\n",
cosm_shutdown_status_string[cdev->shutdown_status]);
}
static DEVICE_ATTR_RO(shutdown_status);
static ssize_t
heartbeat_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%d\n", cdev->sysfs_heartbeat_enable);
}
static ssize_t
heartbeat_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
int enable;
int ret;
if (!cdev)
return -EINVAL;
mutex_lock(&cdev->cosm_mutex);
ret = kstrtoint(buf, 10, &enable);
if (ret)
goto unlock;
cdev->sysfs_heartbeat_enable = enable;
/* if state is not online, cdev->heartbeat_watchdog_enable is 0 */
if (cdev->state == MIC_ONLINE)
cdev->heartbeat_watchdog_enable = enable;
ret = count;
unlock:
mutex_unlock(&cdev->cosm_mutex);
return ret;
}
static DEVICE_ATTR_RW(heartbeat_enable);
static ssize_t
cmdline_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
char *cmdline;
if (!cdev)
return -EINVAL;
cmdline = cdev->cmdline;
if (cmdline)
return scnprintf(buf, PAGE_SIZE, "%s\n", cmdline);
return 0;
}
static ssize_t
cmdline_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
mutex_lock(&cdev->cosm_mutex);
kfree(cdev->cmdline);
cdev->cmdline = kmalloc(count + 1, GFP_KERNEL);
if (!cdev->cmdline) {
count = -ENOMEM;
goto unlock;
}
strncpy(cdev->cmdline, buf, count);
if (cdev->cmdline[count - 1] == '\n')
cdev->cmdline[count - 1] = '\0';
else
cdev->cmdline[count] = '\0';
unlock:
mutex_unlock(&cdev->cosm_mutex);
return count;
}
static DEVICE_ATTR_RW(cmdline);
static ssize_t
firmware_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
char *firmware;
if (!cdev)
return -EINVAL;
firmware = cdev->firmware;
if (firmware)
return scnprintf(buf, PAGE_SIZE, "%s\n", firmware);
return 0;
}
static ssize_t
firmware_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
mutex_lock(&cdev->cosm_mutex);
kfree(cdev->firmware);
cdev->firmware = kmalloc(count + 1, GFP_KERNEL);
if (!cdev->firmware) {
count = -ENOMEM;
goto unlock;
}
strncpy(cdev->firmware, buf, count);
if (cdev->firmware[count - 1] == '\n')
cdev->firmware[count - 1] = '\0';
else
cdev->firmware[count] = '\0';
unlock:
mutex_unlock(&cdev->cosm_mutex);
return count;
}
static DEVICE_ATTR_RW(firmware);
static ssize_t
ramdisk_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
char *ramdisk;
if (!cdev)
return -EINVAL;
ramdisk = cdev->ramdisk;
if (ramdisk)
return scnprintf(buf, PAGE_SIZE, "%s\n", ramdisk);
return 0;
}
static ssize_t
ramdisk_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
mutex_lock(&cdev->cosm_mutex);
kfree(cdev->ramdisk);
cdev->ramdisk = kmalloc(count + 1, GFP_KERNEL);
if (!cdev->ramdisk) {
count = -ENOMEM;
goto unlock;
}
strncpy(cdev->ramdisk, buf, count);
if (cdev->ramdisk[count - 1] == '\n')
cdev->ramdisk[count - 1] = '\0';
else
cdev->ramdisk[count] = '\0';
unlock:
mutex_unlock(&cdev->cosm_mutex);
return count;
}
static DEVICE_ATTR_RW(ramdisk);
static ssize_t
bootmode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
char *bootmode;
if (!cdev)
return -EINVAL;
bootmode = cdev->bootmode;
if (bootmode)
return scnprintf(buf, PAGE_SIZE, "%s\n", bootmode);
return 0;
}
static ssize_t
bootmode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "flash"))
return -EINVAL;
mutex_lock(&cdev->cosm_mutex);
kfree(cdev->bootmode);
cdev->bootmode = kmalloc(count + 1, GFP_KERNEL);
if (!cdev->bootmode) {
count = -ENOMEM;
goto unlock;
}
strncpy(cdev->bootmode, buf, count);
if (cdev->bootmode[count - 1] == '\n')
cdev->bootmode[count - 1] = '\0';
else
cdev->bootmode[count] = '\0';
unlock:
mutex_unlock(&cdev->cosm_mutex);
return count;
}
static DEVICE_ATTR_RW(bootmode);
static ssize_t
log_buf_addr_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%p\n", cdev->log_buf_addr);
}
static ssize_t
log_buf_addr_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
int ret;
unsigned long addr;
if (!cdev)
return -EINVAL;
ret = kstrtoul(buf, 16, &addr);
if (ret)
goto exit;
cdev->log_buf_addr = (void *)addr;
ret = count;
exit:
return ret;
}
static DEVICE_ATTR_RW(log_buf_addr);
static ssize_t
log_buf_len_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
if (!cdev)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%p\n", cdev->log_buf_len);
}
static ssize_t
log_buf_len_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cosm_device *cdev = dev_get_drvdata(dev);
int ret;
unsigned long addr;
if (!cdev)
return -EINVAL;
ret = kstrtoul(buf, 16, &addr);
if (ret)
goto exit;
cdev->log_buf_len = (int *)addr;
ret = count;
exit:
return ret;
}
static DEVICE_ATTR_RW(log_buf_len);
static struct attribute *cosm_default_attrs[] = {
&dev_attr_family.attr,
&dev_attr_stepping.attr,
&dev_attr_state.attr,
&dev_attr_shutdown_status.attr,
&dev_attr_heartbeat_enable.attr,
&dev_attr_cmdline.attr,
&dev_attr_firmware.attr,
&dev_attr_ramdisk.attr,
&dev_attr_bootmode.attr,
&dev_attr_log_buf_addr.attr,
&dev_attr_log_buf_len.attr,
NULL
};
ATTRIBUTE_GROUPS(cosm_default);
void cosm_sysfs_init(struct cosm_device *cdev)
{
cdev->attr_group = cosm_default_groups;
}