diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 3ab08e522fb8..eef1c6b46ad8 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -222,7 +222,33 @@ static void mei_bus_event_work(struct work_struct *work) cldev->events = 0; /* Prepare for the next read */ - mei_cl_read_start(cldev->cl, 0, NULL); + if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) + mei_cl_read_start(cldev->cl, 0, NULL); +} + +/** + * mei_cl_bus_notify_event - schedule notify cb on bus client + * + * @cl: host client + */ +void mei_cl_bus_notify_event(struct mei_cl *cl) +{ + struct mei_cl_device *cldev = cl->cldev; + + if (!cldev || !cldev->event_cb) + return; + + if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF))) + return; + + if (!cl->notify_ev) + return; + + set_bit(MEI_CL_EVENT_NOTIF, &cldev->events); + + schedule_work(&cldev->event_work); + + cl->notify_ev = false; } /** @@ -237,6 +263,9 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) if (!cldev || !cldev->event_cb) return; + if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX))) + return; + set_bit(MEI_CL_EVENT_RX, &cldev->events); schedule_work(&cldev->event_work); @@ -247,6 +276,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) * * @cldev: me client devices * @event_cb: callback function + * @events_mask: requested events bitmask * @context: driver context data * * Return: 0 on success @@ -254,6 +284,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) * <0 on other errors */ int mei_cl_register_event_cb(struct mei_cl_device *cldev, + unsigned long events_mask, mei_cl_event_cb_t event_cb, void *context) { int ret; @@ -262,13 +293,24 @@ int mei_cl_register_event_cb(struct mei_cl_device *cldev, return -EALREADY; cldev->events = 0; + cldev->events_mask = events_mask; cldev->event_cb = event_cb; cldev->event_context = context; INIT_WORK(&cldev->event_work, mei_bus_event_work); - ret = mei_cl_read_start(cldev->cl, 0, NULL); - if (ret && ret != -EBUSY) - return ret; + if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { + ret = mei_cl_read_start(cldev->cl, 0, NULL); + if (ret && ret != -EBUSY) + return ret; + } + + if (cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)) { + mutex_lock(&cldev->cl->dev->device_lock); + ret = mei_cl_notify_request(cldev->cl, NULL, event_cb ? 1 : 0); + mutex_unlock(&cldev->cl->dev->device_lock); + if (ret) + return ret; + } return 0; } diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index db2436aee2dc..5fcd70bcdf96 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1375,6 +1375,8 @@ void mei_cl_notify(struct mei_cl *cl) if (cl->ev_async) kill_fasync(&cl->ev_async, SIGIO, POLL_PRI); + + mei_cl_bus_notify_event(cl); } /** diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index c960aaa538c0..e25ee16c658e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -345,6 +345,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking); ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); void mei_cl_bus_rx_event(struct mei_cl *cl); +void mei_cl_bus_notify_event(struct mei_cl *cl); void mei_cl_bus_remove_devices(struct mei_device *bus); int mei_cl_bus_init(void); void mei_cl_bus_exit(void); diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c index 2b77ccf77f81..754a9bb0f58d 100644 --- a/drivers/nfc/mei_phy.c +++ b/drivers/nfc/mei_phy.c @@ -355,7 +355,8 @@ static int nfc_mei_phy_enable(void *phy_id) goto err; } - r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy); + r = mei_cl_register_event_cb(phy->device, BIT(MEI_CL_EVENT_RX), + nfc_mei_event_cb, phy); if (r) { pr_err("Event cb registration failed %d\n", r); goto err; diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index 81ab56dd0ae0..0962b2ca628a 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -28,6 +28,7 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, * @event_cb: Drivers register this callback to get asynchronous ME * events (e.g. Rx buffer pending) notifications. * @event_context: event callback run context + * @events_mask: Events bit mask requested by driver. * @events: Events bitmask sent to the driver. * * @do_match: wheather device can be matched with a driver @@ -46,6 +47,7 @@ struct mei_cl_device { struct work_struct event_work; mei_cl_event_cb_t event_cb; void *event_context; + unsigned long events_mask; unsigned long events; unsigned int do_match:1; @@ -76,10 +78,12 @@ ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length); ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length); int mei_cl_register_event_cb(struct mei_cl_device *device, + unsigned long event_mask, mei_cl_event_cb_t read_cb, void *context); #define MEI_CL_EVENT_RX 0 #define MEI_CL_EVENT_TX 1 +#define MEI_CL_EVENT_NOTIF 2 void *mei_cl_get_drvdata(const struct mei_cl_device *device); void mei_cl_set_drvdata(struct mei_cl_device *device, void *data);