Commit 43b8a7ed authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman
Browse files

mei: expose device state in sysfs



Expose mei device state to user-space through sysfs.
This gives indication to applications that driver is in transition,
usefully mostly to detect link reset state.

Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d65bf042
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -65,3 +65,18 @@ Description: Display the ME firmware version.
		<platform>:<major>.<minor>.<milestone>.<build_no>.
		There can be up to three such blocks for different
		FW components.

What:		/sys/class/mei/meiN/dev_state
Date:		Mar 2019
KernelVersion:	5.1
Contact:	Tomas Winkler <tomas.winkler@intel.com>
Description:	Display the ME device state.

		The device state can have following values:
		INITIALIZING
		INIT_CLIENTS
		ENABLED
		RESETTING
		DISABLED
		POWER_DOWN
		POWER_UP
+1 −1
Original line number Diff line number Diff line
@@ -669,7 +669,7 @@ int mei_cl_unlink(struct mei_cl *cl)

void mei_host_client_init(struct mei_device *dev)
{
	dev->dev_state = MEI_DEV_ENABLED;
	mei_set_devstate(dev, MEI_DEV_ENABLED);
	dev->reset_count = 0;

	schedule_work(&dev->bus_rescan_work);
+10 −10
Original line number Diff line number Diff line
@@ -123,12 +123,12 @@ int mei_reset(struct mei_device *dev)

	/* enter reset flow */
	interrupts_enabled = state != MEI_DEV_POWER_DOWN;
	dev->dev_state = MEI_DEV_RESETTING;
	mei_set_devstate(dev, MEI_DEV_RESETTING);

	dev->reset_count++;
	if (dev->reset_count > MEI_MAX_CONSEC_RESET) {
		dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
		dev->dev_state = MEI_DEV_DISABLED;
		mei_set_devstate(dev, MEI_DEV_DISABLED);
		return -ENODEV;
	}

@@ -150,7 +150,7 @@ int mei_reset(struct mei_device *dev)

	if (state == MEI_DEV_POWER_DOWN) {
		dev_dbg(dev->dev, "powering down: end of reset\n");
		dev->dev_state = MEI_DEV_DISABLED;
		mei_set_devstate(dev, MEI_DEV_DISABLED);
		return 0;
	}

@@ -162,11 +162,11 @@ int mei_reset(struct mei_device *dev)

	dev_dbg(dev->dev, "link is established start sending messages.\n");

	dev->dev_state = MEI_DEV_INIT_CLIENTS;
	mei_set_devstate(dev, MEI_DEV_INIT_CLIENTS);
	ret = mei_hbm_start_req(dev);
	if (ret) {
		dev_err(dev->dev, "hbm_start failed ret = %d\n", ret);
		dev->dev_state = MEI_DEV_RESETTING;
		mei_set_devstate(dev, MEI_DEV_RESETTING);
		return ret;
	}

@@ -196,7 +196,7 @@ int mei_start(struct mei_device *dev)

	dev->reset_count = 0;
	do {
		dev->dev_state = MEI_DEV_INITIALIZING;
		mei_set_devstate(dev, MEI_DEV_INITIALIZING);
		ret = mei_reset(dev);

		if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
@@ -231,7 +231,7 @@ int mei_start(struct mei_device *dev)
	return 0;
err:
	dev_err(dev->dev, "link layer initialization failed.\n");
	dev->dev_state = MEI_DEV_DISABLED;
	mei_set_devstate(dev, MEI_DEV_DISABLED);
	mutex_unlock(&dev->device_lock);
	return -ENODEV;
}
@@ -250,7 +250,7 @@ int mei_restart(struct mei_device *dev)

	mutex_lock(&dev->device_lock);

	dev->dev_state = MEI_DEV_POWER_UP;
	mei_set_devstate(dev, MEI_DEV_POWER_UP);
	dev->reset_count = 0;

	err = mei_reset(dev);
@@ -301,7 +301,7 @@ void mei_stop(struct mei_device *dev)
	dev_dbg(dev->dev, "stopping the device.\n");

	mutex_lock(&dev->device_lock);
	dev->dev_state = MEI_DEV_POWER_DOWN;
	mei_set_devstate(dev, MEI_DEV_POWER_DOWN);
	mutex_unlock(&dev->device_lock);
	mei_cl_bus_remove_devices(dev);

@@ -314,7 +314,7 @@ void mei_stop(struct mei_device *dev)

	mei_reset(dev);
	/* move device to disabled state unconditionally */
	dev->dev_state = MEI_DEV_DISABLED;
	mei_set_devstate(dev, MEI_DEV_DISABLED);

	mutex_unlock(&dev->device_lock);
}
+59 −6
Original line number Diff line number Diff line
@@ -28,6 +28,12 @@
#include "mei_dev.h"
#include "client.h"

static struct class *mei_class;
static dev_t mei_devt;
#define MEI_MAX_DEVS  MINORMASK
static DEFINE_MUTEX(mei_minor_lock);
static DEFINE_IDR(mei_idr);

/**
 * mei_open - the open function
 *
@@ -829,12 +835,65 @@ static ssize_t fw_ver_show(struct device *device,
}
static DEVICE_ATTR_RO(fw_ver);

/**
 * dev_state_show - display device state
 *
 * @device: device pointer
 * @attr: attribute pointer
 * @buf:  char out buffer
 *
 * Return: number of the bytes printed into buf or error
 */
static ssize_t dev_state_show(struct device *device,
			      struct device_attribute *attr, char *buf)
{
	struct mei_device *dev = dev_get_drvdata(device);
	enum mei_dev_state dev_state;

	mutex_lock(&dev->device_lock);
	dev_state = dev->dev_state;
	mutex_unlock(&dev->device_lock);

	return sprintf(buf, "%s", mei_dev_state_str(dev_state));
}
static DEVICE_ATTR_RO(dev_state);

static int match_devt(struct device *dev, const void *data)
{
	const dev_t *devt = data;

	return dev->devt == *devt;
}

/**
 * dev_set_devstate: set to new device state and notify sysfs file.
 *
 * @dev: mei_device
 * @state: new device state
 */
void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state)
{
	struct device *clsdev;

	if (dev->dev_state == state)
		return;

	dev->dev_state = state;

	clsdev = class_find_device(mei_class, NULL, &dev->cdev.dev, match_devt);
	if (clsdev) {
		sysfs_notify(&clsdev->kobj, NULL, "dev_state");
		put_device(clsdev);
	}
}

static struct attribute *mei_attrs[] = {
	&dev_attr_fw_status.attr,
	&dev_attr_hbm_ver.attr,
	&dev_attr_hbm_ver_drv.attr,
	&dev_attr_tx_queue_limit.attr,
	&dev_attr_fw_ver.attr,
	&dev_attr_dev_state.attr,
	NULL
};
ATTRIBUTE_GROUPS(mei);
@@ -858,12 +917,6 @@ static const struct file_operations mei_fops = {
	.llseek = no_llseek
};

static struct class *mei_class;
static dev_t mei_devt;
#define MEI_MAX_DEVS  MINORMASK
static DEFINE_MUTEX(mei_minor_lock);
static DEFINE_IDR(mei_idr);

/**
 * mei_minor_get - obtain next free device minor number
 *
+2 −1
Original line number Diff line number Diff line
@@ -525,7 +525,6 @@ struct mei_device {
	struct dentry *dbgfs_dir;
#endif /* CONFIG_DEBUG_FS */


	const struct mei_hw_ops *ops;
	char hw[0] __aligned(sizeof(void *));
};
@@ -584,6 +583,8 @@ int mei_restart(struct mei_device *dev);
void mei_stop(struct mei_device *dev);
void mei_cancel_work(struct mei_device *dev);

void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state);

int mei_dmam_ring_alloc(struct mei_device *dev);
void mei_dmam_ring_free(struct mei_device *dev);
bool mei_dma_ring_is_allocated(struct mei_device *dev);