diff options
Diffstat (limited to 'drivers/misc/mei/bus.c')
-rw-r--r-- | drivers/misc/mei/bus.c | 83 |
1 files changed, 51 insertions, 32 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 772d02922529..b1133739fb4b 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -74,6 +74,23 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, goto out; } + while (cl->tx_cb_queued >= bus->tx_queue_limit) { + mutex_unlock(&bus->device_lock); + rets = wait_event_interruptible(cl->tx_wait, + cl->writing_state == MEI_WRITE_COMPLETE || + (!mei_cl_is_connected(cl))); + mutex_lock(&bus->device_lock); + if (rets) { + if (signal_pending(current)) + rets = -EINTR; + goto out; + } + if (!mei_cl_is_connected(cl)) { + rets = -ENODEV; + goto out; + } + } + cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL); if (!cb) { rets = -ENOMEM; @@ -450,6 +467,29 @@ bool mei_cldev_enabled(struct mei_cl_device *cldev) EXPORT_SYMBOL_GPL(mei_cldev_enabled); /** + * mei_cl_bus_module_get - acquire module of the underlying + * hw driver. + * + * @cldev: mei client device + * + * Return: true on success; false if the module was removed. + */ +static bool mei_cl_bus_module_get(struct mei_cl_device *cldev) +{ + return try_module_get(cldev->bus->dev->driver->owner); +} + +/** + * mei_cl_bus_module_put - release the underlying hw module. + * + * @cldev: mei client device + */ +static void mei_cl_bus_module_put(struct mei_cl_device *cldev) +{ + module_put(cldev->bus->dev->driver->owner); +} + +/** * mei_cldev_enable - enable me client device * create connection with me client * @@ -487,9 +527,17 @@ int mei_cldev_enable(struct mei_cl_device *cldev) goto out; } + if (!mei_cl_bus_module_get(cldev)) { + dev_err(&cldev->dev, "get hw module failed"); + ret = -ENODEV; + goto out; + } + ret = mei_cl_connect(cl, cldev->me_cl, NULL); - if (ret < 0) + if (ret < 0) { dev_err(&cldev->dev, "cannot connect\n"); + mei_cl_bus_module_put(cldev); + } out: mutex_unlock(&bus->device_lock); @@ -553,6 +601,8 @@ int mei_cldev_disable(struct mei_cl_device *cldev) dev_err(bus->dev, "Could not disconnect from the ME client\n"); out: + mei_cl_bus_module_put(cldev); + /* Flush queues and remove any pending read */ mei_cl_flush_queues(cl, NULL); mei_cl_unlink(cl); @@ -563,37 +613,6 @@ out: EXPORT_SYMBOL_GPL(mei_cldev_disable); /** - * mei_cl_bus_module_get - acquire module of the underlying - * hw module. - * - * @cl: host client - * - * Return: true on success; false if the module was removed. - */ -bool mei_cl_bus_module_get(struct mei_cl *cl) -{ - struct mei_cl_device *cldev = cl->cldev; - - if (!cldev) - return true; - - return try_module_get(cldev->bus->dev->driver->owner); -} - -/** - * mei_cl_bus_module_put - release the underlying hw module. - * - * @cl: host client - */ -void mei_cl_bus_module_put(struct mei_cl *cl) -{ - struct mei_cl_device *cldev = cl->cldev; - - if (cldev) - module_put(cldev->bus->dev->driver->owner); -} - -/** * mei_cl_device_find - find matching entry in the driver id table * * @cldev: me client device |