diff options
Diffstat (limited to 'drivers/misc/mic/host/mic_sysfs.c')
| -rw-r--r-- | drivers/misc/mic/host/mic_sysfs.c | 459 | 
1 files changed, 459 insertions, 0 deletions
diff --git a/drivers/misc/mic/host/mic_sysfs.c b/drivers/misc/mic/host/mic_sysfs.c new file mode 100644 index 00000000000..6dd864e4a61 --- /dev/null +++ b/drivers/misc/mic/host/mic_sysfs.c @@ -0,0 +1,459 @@ +/* + * Intel MIC Platform Software Stack (MPSS) + * + * Copyright(c) 2013 Intel Corporation. + * + * 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". + * + * Intel MIC Host driver. + * + */ +#include <linux/pci.h> + +#include <linux/mic_common.h> +#include "../common/mic_dev.h" +#include "mic_device.h" + +/* + * A state-to-string lookup table, for exposing a human readable state + * via sysfs. Always keep in sync with enum mic_states + */ +static const char * const mic_state_string[] = { +	[MIC_OFFLINE] = "offline", +	[MIC_ONLINE] = "online", +	[MIC_SHUTTING_DOWN] = "shutting_down", +	[MIC_RESET_FAILED] = "reset_failed", +	[MIC_SUSPENDING] = "suspending", +	[MIC_SUSPENDED] = "suspended", +}; + +/* + * A shutdown-status-to-string lookup table, for exposing a human + * readable state via sysfs. Always keep in sync with enum mic_shutdown_status + */ +static const char * const mic_shutdown_status_string[] = { +	[MIC_NOP] = "nop", +	[MIC_CRASHED] = "crashed", +	[MIC_HALTED] = "halted", +	[MIC_POWER_OFF] = "poweroff", +	[MIC_RESTART] = "restart", +}; + +void mic_set_shutdown_status(struct mic_device *mdev, u8 shutdown_status) +{ +	dev_dbg(mdev->sdev->parent, "Shutdown Status %s -> %s\n", +		mic_shutdown_status_string[mdev->shutdown_status], +		mic_shutdown_status_string[shutdown_status]); +	mdev->shutdown_status = shutdown_status; +} + +void mic_set_state(struct mic_device *mdev, u8 state) +{ +	dev_dbg(mdev->sdev->parent, "State %s -> %s\n", +		mic_state_string[mdev->state], +		mic_state_string[state]); +	mdev->state = state; +	sysfs_notify_dirent(mdev->state_sysfs); +} + +static ssize_t +family_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	static const char x100[] = "x100"; +	static const char unknown[] = "Unknown"; +	const char *card = NULL; +	struct mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev) +		return -EINVAL; + +	switch (mdev->family) { +	case MIC_FAMILY_X100: +		card = x100; +		break; +	default: +		card = unknown; +		break; +	} +	return scnprintf(buf, PAGE_SIZE, "%s\n", card); +} +static DEVICE_ATTR_RO(family); + +static ssize_t +stepping_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	char *string = "??"; + +	if (!mdev) +		return -EINVAL; + +	switch (mdev->stepping) { +	case MIC_A0_STEP: +		string = "A0"; +		break; +	case MIC_B0_STEP: +		string = "B0"; +		break; +	case MIC_B1_STEP: +		string = "B1"; +		break; +	case MIC_C0_STEP: +		string = "C0"; +		break; +	default: +		break; +	} +	return scnprintf(buf, PAGE_SIZE, "%s\n", string); +} +static DEVICE_ATTR_RO(stepping); + +static ssize_t +state_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev || mdev->state >= MIC_LAST) +		return -EINVAL; + +	return scnprintf(buf, PAGE_SIZE, "%s\n", +		mic_state_string[mdev->state]); +} + +static ssize_t +state_store(struct device *dev, struct device_attribute *attr, +	    const char *buf, size_t count) +{ +	int rc = 0; +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	if (!mdev) +		return -EINVAL; +	if (sysfs_streq(buf, "boot")) { +		rc = mic_start(mdev, buf); +		if (rc) { +			dev_err(mdev->sdev->parent, +				"mic_boot failed rc %d\n", rc); +			count = rc; +		} +		goto done; +	} + +	if (sysfs_streq(buf, "reset")) { +		schedule_work(&mdev->reset_trigger_work); +		goto done; +	} + +	if (sysfs_streq(buf, "shutdown")) { +		mic_shutdown(mdev); +		goto done; +	} + +	if (sysfs_streq(buf, "suspend")) { +		mic_suspend(mdev); +		goto done; +	} + +	count = -EINVAL; +done: +	return count; +} +static DEVICE_ATTR_RW(state); + +static ssize_t shutdown_status_show(struct device *dev, +				    struct device_attribute *attr, char *buf) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev || mdev->shutdown_status >= MIC_STATUS_LAST) +		return -EINVAL; + +	return scnprintf(buf, PAGE_SIZE, "%s\n", +		mic_shutdown_status_string[mdev->shutdown_status]); +} +static DEVICE_ATTR_RO(shutdown_status); + +static ssize_t +cmdline_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	char *cmdline; + +	if (!mdev) +		return -EINVAL; + +	cmdline = mdev->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 mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev) +		return -EINVAL; + +	mutex_lock(&mdev->mic_mutex); +	kfree(mdev->cmdline); + +	mdev->cmdline = kmalloc(count + 1, GFP_KERNEL); +	if (!mdev->cmdline) { +		count = -ENOMEM; +		goto unlock; +	} + +	strncpy(mdev->cmdline, buf, count); + +	if (mdev->cmdline[count - 1] == '\n') +		mdev->cmdline[count - 1] = '\0'; +	else +		mdev->cmdline[count] = '\0'; +unlock: +	mutex_unlock(&mdev->mic_mutex); +	return count; +} +static DEVICE_ATTR_RW(cmdline); + +static ssize_t +firmware_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	char *firmware; + +	if (!mdev) +		return -EINVAL; + +	firmware = mdev->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 mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev) +		return -EINVAL; + +	mutex_lock(&mdev->mic_mutex); +	kfree(mdev->firmware); + +	mdev->firmware = kmalloc(count + 1, GFP_KERNEL); +	if (!mdev->firmware) { +		count = -ENOMEM; +		goto unlock; +	} +	strncpy(mdev->firmware, buf, count); + +	if (mdev->firmware[count - 1] == '\n') +		mdev->firmware[count - 1] = '\0'; +	else +		mdev->firmware[count] = '\0'; +unlock: +	mutex_unlock(&mdev->mic_mutex); +	return count; +} +static DEVICE_ATTR_RW(firmware); + +static ssize_t +ramdisk_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	char *ramdisk; + +	if (!mdev) +		return -EINVAL; + +	ramdisk = mdev->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 mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev) +		return -EINVAL; + +	mutex_lock(&mdev->mic_mutex); +	kfree(mdev->ramdisk); + +	mdev->ramdisk = kmalloc(count + 1, GFP_KERNEL); +	if (!mdev->ramdisk) { +		count = -ENOMEM; +		goto unlock; +	} + +	strncpy(mdev->ramdisk, buf, count); + +	if (mdev->ramdisk[count - 1] == '\n') +		mdev->ramdisk[count - 1] = '\0'; +	else +		mdev->ramdisk[count] = '\0'; +unlock: +	mutex_unlock(&mdev->mic_mutex); +	return count; +} +static DEVICE_ATTR_RW(ramdisk); + +static ssize_t +bootmode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	char *bootmode; + +	if (!mdev) +		return -EINVAL; + +	bootmode = mdev->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 mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev) +		return -EINVAL; + +	if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "elf")) +		return -EINVAL; + +	mutex_lock(&mdev->mic_mutex); +	kfree(mdev->bootmode); + +	mdev->bootmode = kmalloc(count + 1, GFP_KERNEL); +	if (!mdev->bootmode) { +		count = -ENOMEM; +		goto unlock; +	} + +	strncpy(mdev->bootmode, buf, count); + +	if (mdev->bootmode[count - 1] == '\n') +		mdev->bootmode[count - 1] = '\0'; +	else +		mdev->bootmode[count] = '\0'; +unlock: +	mutex_unlock(&mdev->mic_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 mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev) +		return -EINVAL; + +	return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_addr); +} + +static ssize_t +log_buf_addr_store(struct device *dev, struct device_attribute *attr, +		   const char *buf, size_t count) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	int ret; +	unsigned long addr; + +	if (!mdev) +		return -EINVAL; + +	ret = kstrtoul(buf, 16, &addr); +	if (ret) +		goto exit; + +	mdev->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 mic_device *mdev = dev_get_drvdata(dev->parent); + +	if (!mdev) +		return -EINVAL; + +	return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_len); +} + +static ssize_t +log_buf_len_store(struct device *dev, struct device_attribute *attr, +		  const char *buf, size_t count) +{ +	struct mic_device *mdev = dev_get_drvdata(dev->parent); +	int ret; +	unsigned long addr; + +	if (!mdev) +		return -EINVAL; + +	ret = kstrtoul(buf, 16, &addr); +	if (ret) +		goto exit; + +	mdev->log_buf_len = (int *)addr; +	ret = count; +exit: +	return ret; +} +static DEVICE_ATTR_RW(log_buf_len); + +static struct attribute *mic_default_attrs[] = { +	&dev_attr_family.attr, +	&dev_attr_stepping.attr, +	&dev_attr_state.attr, +	&dev_attr_shutdown_status.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(mic_default); + +void mic_sysfs_init(struct mic_device *mdev) +{ +	mdev->attr_group = mic_default_groups; +}  | 
