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

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
...@@ -65,3 +65,18 @@ Description: Display the ME firmware version. ...@@ -65,3 +65,18 @@ Description: Display the ME firmware version.
<platform>:<major>.<minor>.<milestone>.<build_no>. <platform>:<major>.<minor>.<milestone>.<build_no>.
There can be up to three such blocks for different There can be up to three such blocks for different
FW components. 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
...@@ -669,7 +669,7 @@ int mei_cl_unlink(struct mei_cl *cl) ...@@ -669,7 +669,7 @@ int mei_cl_unlink(struct mei_cl *cl)
void mei_host_client_init(struct mei_device *dev) 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; dev->reset_count = 0;
schedule_work(&dev->bus_rescan_work); schedule_work(&dev->bus_rescan_work);
......
...@@ -123,12 +123,12 @@ int mei_reset(struct mei_device *dev) ...@@ -123,12 +123,12 @@ int mei_reset(struct mei_device *dev)
/* enter reset flow */ /* enter reset flow */
interrupts_enabled = state != MEI_DEV_POWER_DOWN; interrupts_enabled = state != MEI_DEV_POWER_DOWN;
dev->dev_state = MEI_DEV_RESETTING; mei_set_devstate(dev, MEI_DEV_RESETTING);
dev->reset_count++; dev->reset_count++;
if (dev->reset_count > MEI_MAX_CONSEC_RESET) { if (dev->reset_count > MEI_MAX_CONSEC_RESET) {
dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n"); 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; return -ENODEV;
} }
...@@ -150,7 +150,7 @@ int mei_reset(struct mei_device *dev) ...@@ -150,7 +150,7 @@ int mei_reset(struct mei_device *dev)
if (state == MEI_DEV_POWER_DOWN) { if (state == MEI_DEV_POWER_DOWN) {
dev_dbg(dev->dev, "powering down: end of reset\n"); 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; return 0;
} }
...@@ -162,11 +162,11 @@ int mei_reset(struct mei_device *dev) ...@@ -162,11 +162,11 @@ int mei_reset(struct mei_device *dev)
dev_dbg(dev->dev, "link is established start sending messages.\n"); 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); ret = mei_hbm_start_req(dev);
if (ret) { if (ret) {
dev_err(dev->dev, "hbm_start failed ret = %d\n", 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; return ret;
} }
...@@ -196,7 +196,7 @@ int mei_start(struct mei_device *dev) ...@@ -196,7 +196,7 @@ int mei_start(struct mei_device *dev)
dev->reset_count = 0; dev->reset_count = 0;
do { do {
dev->dev_state = MEI_DEV_INITIALIZING; mei_set_devstate(dev, MEI_DEV_INITIALIZING);
ret = mei_reset(dev); ret = mei_reset(dev);
if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) { if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
...@@ -231,7 +231,7 @@ int mei_start(struct mei_device *dev) ...@@ -231,7 +231,7 @@ int mei_start(struct mei_device *dev)
return 0; return 0;
err: err:
dev_err(dev->dev, "link layer initialization failed.\n"); 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); mutex_unlock(&dev->device_lock);
return -ENODEV; return -ENODEV;
} }
...@@ -250,7 +250,7 @@ int mei_restart(struct mei_device *dev) ...@@ -250,7 +250,7 @@ int mei_restart(struct mei_device *dev)
mutex_lock(&dev->device_lock); mutex_lock(&dev->device_lock);
dev->dev_state = MEI_DEV_POWER_UP; mei_set_devstate(dev, MEI_DEV_POWER_UP);
dev->reset_count = 0; dev->reset_count = 0;
err = mei_reset(dev); err = mei_reset(dev);
...@@ -301,7 +301,7 @@ void mei_stop(struct mei_device *dev) ...@@ -301,7 +301,7 @@ void mei_stop(struct mei_device *dev)
dev_dbg(dev->dev, "stopping the device.\n"); dev_dbg(dev->dev, "stopping the device.\n");
mutex_lock(&dev->device_lock); 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); mutex_unlock(&dev->device_lock);
mei_cl_bus_remove_devices(dev); mei_cl_bus_remove_devices(dev);
...@@ -314,7 +314,7 @@ void mei_stop(struct mei_device *dev) ...@@ -314,7 +314,7 @@ void mei_stop(struct mei_device *dev)
mei_reset(dev); mei_reset(dev);
/* move device to disabled state unconditionally */ /* move device to disabled state unconditionally */
dev->dev_state = MEI_DEV_DISABLED; mei_set_devstate(dev, MEI_DEV_DISABLED);
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
} }
......
...@@ -28,6 +28,12 @@ ...@@ -28,6 +28,12 @@
#include "mei_dev.h" #include "mei_dev.h"
#include "client.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 * mei_open - the open function
* *
...@@ -829,12 +835,65 @@ static ssize_t fw_ver_show(struct device *device, ...@@ -829,12 +835,65 @@ static ssize_t fw_ver_show(struct device *device,
} }
static DEVICE_ATTR_RO(fw_ver); 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[] = { static struct attribute *mei_attrs[] = {
&dev_attr_fw_status.attr, &dev_attr_fw_status.attr,
&dev_attr_hbm_ver.attr, &dev_attr_hbm_ver.attr,
&dev_attr_hbm_ver_drv.attr, &dev_attr_hbm_ver_drv.attr,
&dev_attr_tx_queue_limit.attr, &dev_attr_tx_queue_limit.attr,
&dev_attr_fw_ver.attr, &dev_attr_fw_ver.attr,
&dev_attr_dev_state.attr,
NULL NULL
}; };
ATTRIBUTE_GROUPS(mei); ATTRIBUTE_GROUPS(mei);
...@@ -858,12 +917,6 @@ static const struct file_operations mei_fops = { ...@@ -858,12 +917,6 @@ static const struct file_operations mei_fops = {
.llseek = no_llseek .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 * mei_minor_get - obtain next free device minor number
* *
......
...@@ -525,7 +525,6 @@ struct mei_device { ...@@ -525,7 +525,6 @@ struct mei_device {
struct dentry *dbgfs_dir; struct dentry *dbgfs_dir;
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
const struct mei_hw_ops *ops; const struct mei_hw_ops *ops;
char hw[0] __aligned(sizeof(void *)); char hw[0] __aligned(sizeof(void *));
}; };
...@@ -584,6 +583,8 @@ int mei_restart(struct mei_device *dev); ...@@ -584,6 +583,8 @@ int mei_restart(struct mei_device *dev);
void mei_stop(struct mei_device *dev); void mei_stop(struct mei_device *dev);
void mei_cancel_work(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); int mei_dmam_ring_alloc(struct mei_device *dev);
void mei_dmam_ring_free(struct mei_device *dev); void mei_dmam_ring_free(struct mei_device *dev);
bool mei_dma_ring_is_allocated(struct mei_device *dev); bool mei_dma_ring_is_allocated(struct mei_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment