From 7c7a6077f5c7a35fc03a7f452875d8440dd1bc8d Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Wed, 16 Nov 2016 22:51:29 +0200 Subject: mei: bus: split RX and async notification callbacks Split callbacks for RX and async notification events on mei bus to eliminate synchronization problems and to open way for RX optimizations. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 141 +++++++++++++++++++++++++++------------------- drivers/misc/mei/client.c | 5 ++ 2 files changed, 87 insertions(+), 59 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 483587f60249..2fd254ecde2f 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -209,31 +209,40 @@ ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) EXPORT_SYMBOL_GPL(mei_cldev_recv); /** - * mei_cl_bus_event_work - dispatch rx event for a bus device - * and schedule new work + * mei_cl_bus_rx_work - dispatch rx event for a bus device * * @work: work */ -static void mei_cl_bus_event_work(struct work_struct *work) +static void mei_cl_bus_rx_work(struct work_struct *work) { struct mei_cl_device *cldev; struct mei_device *bus; - cldev = container_of(work, struct mei_cl_device, event_work); + cldev = container_of(work, struct mei_cl_device, rx_work); bus = cldev->bus; - if (cldev->event_cb) - cldev->event_cb(cldev, cldev->events); + if (cldev->rx_cb) + cldev->rx_cb(cldev); - cldev->events = 0; + mutex_lock(&bus->device_lock); + mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL); + mutex_unlock(&bus->device_lock); +} - /* Prepare for the next read */ - if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { - mutex_lock(&bus->device_lock); - mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL); - mutex_unlock(&bus->device_lock); - } +/** + * mei_cl_bus_notif_work - dispatch FW notif event for a bus device + * + * @work: work + */ +static void mei_cl_bus_notif_work(struct work_struct *work) +{ + struct mei_cl_device *cldev; + + cldev = container_of(work, struct mei_cl_device, notif_work); + + if (cldev->notif_cb) + cldev->notif_cb(cldev); } /** @@ -248,18 +257,13 @@ bool mei_cl_bus_notify_event(struct mei_cl *cl) { struct mei_cl_device *cldev = cl->cldev; - if (!cldev || !cldev->event_cb) - return false; - - if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF))) + if (!cldev || !cldev->notif_cb) return false; if (!cl->notify_ev) return false; - set_bit(MEI_CL_EVENT_NOTIF, &cldev->events); - - schedule_work(&cldev->event_work); + schedule_work(&cldev->notif_work); cl->notify_ev = false; @@ -267,7 +271,7 @@ bool mei_cl_bus_notify_event(struct mei_cl *cl) } /** - * mei_cl_bus_rx_event - schedule rx event + * mei_cl_bus_rx_event - schedule rx event * * @cl: host client * @@ -278,64 +282,81 @@ bool mei_cl_bus_rx_event(struct mei_cl *cl) { struct mei_cl_device *cldev = cl->cldev; - if (!cldev || !cldev->event_cb) - return false; - - if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX))) + if (!cldev || !cldev->rx_cb) return false; - set_bit(MEI_CL_EVENT_RX, &cldev->events); - - schedule_work(&cldev->event_work); + schedule_work(&cldev->rx_work); return true; } /** - * mei_cldev_register_event_cb - register event callback + * mei_cldev_register_rx_cb - register Rx event callback * * @cldev: me client devices - * @event_cb: callback function - * @events_mask: requested events bitmask + * @rx_cb: callback function * * Return: 0 on success * -EALREADY if an callback is already registered * <0 on other errors */ -int mei_cldev_register_event_cb(struct mei_cl_device *cldev, - unsigned long events_mask, - mei_cldev_event_cb_t event_cb) +int mei_cldev_register_rx_cb(struct mei_cl_device *cldev, mei_cldev_cb_t rx_cb) { struct mei_device *bus = cldev->bus; int ret; - if (cldev->event_cb) + if (!rx_cb) + return -EINVAL; + if (cldev->rx_cb) return -EALREADY; - cldev->events = 0; - cldev->events_mask = events_mask; - cldev->event_cb = event_cb; - INIT_WORK(&cldev->event_work, mei_cl_bus_event_work); + cldev->rx_cb = rx_cb; + INIT_WORK(&cldev->rx_work, mei_cl_bus_rx_work); - if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { - mutex_lock(&bus->device_lock); - ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL); - mutex_unlock(&bus->device_lock); - if (ret && ret != -EBUSY) - return ret; - } + mutex_lock(&bus->device_lock); + ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL); + mutex_unlock(&bus->device_lock); + if (ret && ret != -EBUSY) + return ret; - if (cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)) { - mutex_lock(&bus->device_lock); - ret = mei_cl_notify_request(cldev->cl, NULL, event_cb ? 1 : 0); - mutex_unlock(&bus->device_lock); - if (ret) - return ret; - } + return 0; +} +EXPORT_SYMBOL_GPL(mei_cldev_register_rx_cb); + +/** + * mei_cldev_register_notif_cb - register FW notification event callback + * + * @cldev: me client devices + * @notif_cb: callback function + * + * Return: 0 on success + * -EALREADY if an callback is already registered + * <0 on other errors + */ +int mei_cldev_register_notif_cb(struct mei_cl_device *cldev, + mei_cldev_cb_t notif_cb) +{ + struct mei_device *bus = cldev->bus; + int ret; + + if (!notif_cb) + return -EINVAL; + + if (cldev->notif_cb) + return -EALREADY; + + cldev->notif_cb = notif_cb; + INIT_WORK(&cldev->notif_work, mei_cl_bus_notif_work); + + mutex_lock(&bus->device_lock); + ret = mei_cl_notify_request(cldev->cl, NULL, 1); + mutex_unlock(&bus->device_lock); + if (ret) + return ret; return 0; } -EXPORT_SYMBOL_GPL(mei_cldev_register_event_cb); +EXPORT_SYMBOL_GPL(mei_cldev_register_notif_cb); /** * mei_cldev_get_drvdata - driver data getter @@ -471,8 +492,6 @@ int mei_cldev_disable(struct mei_cl_device *cldev) bus = cldev->bus; - cldev->event_cb = NULL; - mutex_lock(&bus->device_lock); if (!mei_cl_is_connected(cl)) { @@ -619,9 +638,13 @@ static int mei_cl_device_remove(struct device *dev) if (!cldev || !dev->driver) return 0; - if (cldev->event_cb) { - cldev->event_cb = NULL; - cancel_work_sync(&cldev->event_work); + if (cldev->rx_cb) { + cancel_work_sync(&cldev->rx_work); + cldev->rx_cb = NULL; + } + if (cldev->notif_cb) { + cancel_work_sync(&cldev->notif_work); + cldev->notif_cb = NULL; } cldrv = to_mei_cl_driver(dev->driver); diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 46ee9155ada6..9635b14b6011 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -673,6 +673,11 @@ int mei_cl_unlink(struct mei_cl *cl) list_del_init(&cl->link); cl->state = MEI_FILE_UNINITIALIZED; + cl->writing_state = MEI_IDLE; + + WARN_ON(!list_empty(&cl->rd_completed) || + !list_empty(&cl->rd_pending) || + !list_empty(&cl->link)); return 0; } -- cgit v1.2.3