Commit 9fd00df0 authored by Zbigniew Lukwinski's avatar Zbigniew Lukwinski Committed by Alexandre Belloni

i3c: master: handle IBIs in order they came

IBI shall be handled in order they appear on the bus. Otherwise could hit
case when order of handling them in device driver will be different. It may
lead to invalid assembling fragmented packets or events order broken.

Added separate workqueue with option WQ_MEM_RECLAIM for each device driver.
This ensures IBI handling order and improves IBI handling performance: IBI
handlers for device B are not blocked by IBI handlers for device A.

Original solution (single workqueue in main driver) was able to handle also
general IBI (not related to specific device) like HJ or MR. So leaving this
for such purposes.
Signed-off-by: default avatarZbigniew Lukwinski <zbigniew.lukwinski@linux.intel.com>
Link: https://lore.kernel.org/r/20231015222334.1652401-2-zbigniew.lukwinski@linux.intel.comSigned-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent b53e9758
...@@ -2374,7 +2374,7 @@ static void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master) ...@@ -2374,7 +2374,7 @@ static void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master)
void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot)
{ {
atomic_inc(&dev->ibi->pending_ibis); atomic_inc(&dev->ibi->pending_ibis);
queue_work(dev->common.master->wq, &slot->work); queue_work(dev->ibi->wq, &slot->work);
} }
EXPORT_SYMBOL_GPL(i3c_master_queue_ibi); EXPORT_SYMBOL_GPL(i3c_master_queue_ibi);
...@@ -2819,6 +2819,12 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev, ...@@ -2819,6 +2819,12 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
if (!ibi) if (!ibi)
return -ENOMEM; return -ENOMEM;
ibi->wq = alloc_ordered_workqueue(dev_name(i3cdev_to_dev(dev->dev)), WQ_MEM_RECLAIM);
if (!ibi->wq) {
kfree(ibi);
return -ENOMEM;
}
atomic_set(&ibi->pending_ibis, 0); atomic_set(&ibi->pending_ibis, 0);
init_completion(&ibi->all_ibis_handled); init_completion(&ibi->all_ibis_handled);
ibi->handler = req->handler; ibi->handler = req->handler;
...@@ -2846,6 +2852,12 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev) ...@@ -2846,6 +2852,12 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev)
WARN_ON(i3c_dev_disable_ibi_locked(dev)); WARN_ON(i3c_dev_disable_ibi_locked(dev));
master->ops->free_ibi(dev); master->ops->free_ibi(dev);
if (dev->ibi->wq) {
destroy_workqueue(dev->ibi->wq);
dev->ibi->wq = NULL;
}
kfree(dev->ibi); kfree(dev->ibi);
dev->ibi = NULL; dev->ibi = NULL;
} }
......
...@@ -129,6 +129,7 @@ struct i3c_ibi_slot { ...@@ -129,6 +129,7 @@ struct i3c_ibi_slot {
* rejected by the master * rejected by the master
* @num_slots: number of IBI slots reserved for this device * @num_slots: number of IBI slots reserved for this device
* @enabled: reflect the IBI status * @enabled: reflect the IBI status
* @wq: workqueue used to execute IBI handlers.
* @handler: IBI handler specified at i3c_device_request_ibi() call time. This * @handler: IBI handler specified at i3c_device_request_ibi() call time. This
* handler will be called from the controller workqueue, and as such * handler will be called from the controller workqueue, and as such
* is allowed to sleep (though it is recommended to process the IBI * is allowed to sleep (though it is recommended to process the IBI
...@@ -151,6 +152,7 @@ struct i3c_device_ibi_info { ...@@ -151,6 +152,7 @@ struct i3c_device_ibi_info {
unsigned int max_payload_len; unsigned int max_payload_len;
unsigned int num_slots; unsigned int num_slots;
unsigned int enabled; unsigned int enabled;
struct workqueue_struct *wq;
void (*handler)(struct i3c_device *dev, void (*handler)(struct i3c_device *dev,
const struct i3c_ibi_payload *payload); const struct i3c_ibi_payload *payload);
}; };
...@@ -469,7 +471,7 @@ struct i3c_master_controller_ops { ...@@ -469,7 +471,7 @@ struct i3c_master_controller_ops {
* @boardinfo.i2c: list of I2C boardinfo objects * @boardinfo.i2c: list of I2C boardinfo objects
* @boardinfo: board-level information attached to devices connected on the bus * @boardinfo: board-level information attached to devices connected on the bus
* @bus: I3C bus exposed by this master * @bus: I3C bus exposed by this master
* @wq: workqueue used to execute IBI handlers. Can also be used by master * @wq: workqueue which can be used by master
* drivers if they need to postpone operations that need to take place * drivers if they need to postpone operations that need to take place
* in a thread context. Typical examples are Hot Join processing which * in a thread context. Typical examples are Hot Join processing which
* requires taking the bus lock in maintenance, which in turn, can only * requires taking the bus lock in maintenance, which in turn, can only
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment