From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 20 Apr 2017 10:02:34 +0300 Subject: [PATCH] mei: expose device state in sysfs Expose mei device state to user-space through sysfs. This gave indication to applications that driver is in transition, e.g. in link reset state. Change-Id: Id908459d6b9e22ea3a668fda6accd0534cf5278a Signed-off-by: Alexander Usyskin --- Documentation/ABI/testing/sysfs-class-mei | 15 +++++++++++++ drivers/misc/mei/client.c | 2 +- drivers/misc/mei/init.c | 22 ++++++++++--------- drivers/misc/mei/main.c | 26 +++++++++++++++++++++++ drivers/misc/mei/mei_dev.h | 11 ++++++++++ 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-mei b/Documentation/ABI/testing/sysfs-class-mei index 17d7444a2397..cb135822f2c0 100644 --- a/Documentation/ABI/testing/sysfs-class-mei +++ b/Documentation/ABI/testing/sysfs-class-mei @@ -65,3 +65,18 @@ Description: Display the ME firmware version. :.... There can be up to three such blocks for different FW components. + +What: /sys/class/mei/meiN/dev_state +Date: Sep 2019 +KernelVersion: 4.19 +Contact: Tomas Winkler +Description: Display the ME device state. + + The device state can have following values: + INITIALIZING + INIT_CLIENTS + ENABLED + RESETTING + DISABLED + POWER_DOWN + POWER_UP diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index d6e871fb25af..e6833acb81d5 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -722,7 +722,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); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index eb026e2a0537..d75173dc1b23 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -133,12 +133,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; } @@ -160,7 +160,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; } @@ -172,11 +172,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; } @@ -206,7 +206,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) { @@ -241,7 +241,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; } @@ -260,7 +260,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); @@ -311,7 +311,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); @@ -324,7 +324,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); } @@ -389,6 +389,8 @@ void mei_device_init(struct mei_device *dev, INIT_WORK(&dev->reset_work, mei_reset_work); INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work); + dev->sysfs_state = NULL; + bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); dev->open_handle_count = 0; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 59a6a7a19621..86d81cb855fe 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -1014,12 +1014,36 @@ 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 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); @@ -1116,6 +1140,8 @@ int mei_register(struct mei_device *dev, struct device *parent) goto err_dev_create; } + dev->sysfs_state = sysfs_get_dirent(clsdev->kobj.sd, "dev_state"); + ret = mei_dbgfs_register(dev, dev_name(clsdev)); if (ret) { dev_err(clsdev, "cannot register debugfs ret = %d\n", ret); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index f385c27de023..07147c31b102 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -469,6 +469,8 @@ struct mei_fw_version { * * @dbgfs_dir : debugfs mei root directory * + * @sysfs_state : sysfs state object + * * @ops: : hw specific operations * @hw : hw specific data */ @@ -556,6 +558,7 @@ struct mei_device { struct dentry *dbgfs_dir; #endif /* CONFIG_DEBUG_FS */ + struct kernfs_node *sysfs_state; const struct mei_hw_ops *ops; char hw[0] __aligned(sizeof(void *)); @@ -615,6 +618,14 @@ int mei_restart(struct mei_device *dev); void mei_stop(struct mei_device *dev); void mei_cancel_work(struct mei_device *dev); +static inline void mei_set_devstate(struct mei_device *dev, + enum mei_dev_state state) +{ + dev->dev_state = state; + if (dev->sysfs_state) + sysfs_notify_dirent(dev->sysfs_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); -- https://clearlinux.org