diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2014-01-08 22:19:21 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-09 03:25:15 +0400 |
commit | 544f94601409653f07ae6e22d4a39e3a90dceead (patch) | |
tree | 0939fcf8facae8633eebe3fd40b4f4f00788d76e /drivers/misc/mei/init.c | |
parent | 634608f27acd098b245ca6fe60e06701185eb170 (diff) | |
download | linux-544f94601409653f07ae6e22d4a39e3a90dceead.tar.xz |
mei: do not run reset flow from the interrupt thread
This fixes a potential deadlock in case of a firmware
initiated reset
mei_reset has a dialog with the interrupt thread hence
it has to be run from an another work item
Most of the mei_resets were called from mei_hbm_dispatch
which is called in interrupt thread context so this
function underwent major revamp. The error code is
propagated to the interrupt thread and if needed
the reset is scheduled from there.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei/init.c')
-rw-r--r-- | drivers/misc/mei/init.c | 100 |
1 files changed, 61 insertions, 39 deletions
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 83c879bf9967..87c077bae5d8 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -43,42 +43,6 @@ const char *mei_dev_state_str(int state) #undef MEI_DEV_STATE } -void mei_device_init(struct mei_device *dev) -{ - /* setup our list array */ - INIT_LIST_HEAD(&dev->file_list); - INIT_LIST_HEAD(&dev->device_list); - mutex_init(&dev->device_lock); - init_waitqueue_head(&dev->wait_hw_ready); - init_waitqueue_head(&dev->wait_recvd_msg); - init_waitqueue_head(&dev->wait_stop_wd); - dev->dev_state = MEI_DEV_INITIALIZING; - - mei_io_list_init(&dev->read_list); - mei_io_list_init(&dev->write_list); - mei_io_list_init(&dev->write_waiting_list); - mei_io_list_init(&dev->ctrl_wr_list); - mei_io_list_init(&dev->ctrl_rd_list); - - INIT_DELAYED_WORK(&dev->timer_work, mei_timer); - INIT_WORK(&dev->init_work, mei_host_client_init); - - INIT_LIST_HEAD(&dev->wd_cl.link); - INIT_LIST_HEAD(&dev->iamthif_cl.link); - mei_io_list_init(&dev->amthif_cmd_list); - mei_io_list_init(&dev->amthif_rd_complete_list); - - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->open_handle_count = 0; - - /* - * Reserving the first client ID - * 0: Reserved for MEI Bus Message communications - */ - bitmap_set(dev->host_clients_map, 0, 1); -} -EXPORT_SYMBOL_GPL(mei_device_init); - /** * mei_start - initializes host and fw to start work. * @@ -131,10 +95,15 @@ err: } EXPORT_SYMBOL_GPL(mei_start); - +/** + * mei_cancel_work. Cancel mei background jobs + * + * @dev: the device structure + */ void mei_cancel_work(struct mei_device *dev) { cancel_work_sync(&dev->init_work); + cancel_work_sync(&dev->reset_work); cancel_delayed_work(&dev->timer_work); } @@ -215,11 +184,27 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) dev->dev_state = MEI_DEV_INIT_CLIENTS; - mei_hbm_start_req(dev); - + ret = mei_hbm_start_req(dev); + if (ret) { + dev_err(&dev->pdev->dev, "hbm_start failed disabling the device\n"); + dev->dev_state = MEI_DEV_DISABLED; + return; + } } EXPORT_SYMBOL_GPL(mei_reset); +static void mei_reset_work(struct work_struct *work) +{ + struct mei_device *dev = + container_of(work, struct mei_device, reset_work); + + mutex_lock(&dev->device_lock); + + mei_reset(dev, true); + + mutex_unlock(&dev->device_lock); +} + void mei_stop(struct mei_device *dev) { dev_dbg(&dev->pdev->dev, "stopping the device.\n"); @@ -243,3 +228,40 @@ EXPORT_SYMBOL_GPL(mei_stop); +void mei_device_init(struct mei_device *dev) +{ + /* setup our list array */ + INIT_LIST_HEAD(&dev->file_list); + INIT_LIST_HEAD(&dev->device_list); + mutex_init(&dev->device_lock); + init_waitqueue_head(&dev->wait_hw_ready); + init_waitqueue_head(&dev->wait_recvd_msg); + init_waitqueue_head(&dev->wait_stop_wd); + dev->dev_state = MEI_DEV_INITIALIZING; + + mei_io_list_init(&dev->read_list); + mei_io_list_init(&dev->write_list); + mei_io_list_init(&dev->write_waiting_list); + mei_io_list_init(&dev->ctrl_wr_list); + mei_io_list_init(&dev->ctrl_rd_list); + + INIT_DELAYED_WORK(&dev->timer_work, mei_timer); + INIT_WORK(&dev->init_work, mei_host_client_init); + INIT_WORK(&dev->reset_work, mei_reset_work); + + INIT_LIST_HEAD(&dev->wd_cl.link); + INIT_LIST_HEAD(&dev->iamthif_cl.link); + mei_io_list_init(&dev->amthif_cmd_list); + mei_io_list_init(&dev->amthif_rd_complete_list); + + bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); + dev->open_handle_count = 0; + + /* + * Reserving the first client ID + * 0: Reserved for MEI Bus Message communications + */ + bitmap_set(dev->host_clients_map, 0, 1); +} +EXPORT_SYMBOL_GPL(mei_device_init); + |