i3c: Support IBI-based system wakeup
v2 cover i3c: Support IBI-based system wakeup
Hi
Intel LPSS I3C controllers support up to two I3C busses and can wake the system from an In-Band Interrupt (IBI) via a PCI PME. Today that wakeup capability lives only at the PCI function, with no way to express which I3C device is actually responsible for waking the system, and no way for user space to enable or disable wakeup on a per-device basis.
This series pushes the wakeup capability down to the individual I3C devices and then aggregates the resulting wakeup state back up to the PCI device.
An IBI-capable I3C device on a bus whose controller can wake the system is marked as wakeup capable, so it can be managed through the standard device wakeup framework (e.g. via power/wakeup in sysfs). When such a device is enabled for wakeup, a wakeup event is reported each time it queues an IBI.
At suspend time, the mipi-i3c-hci PCI driver aggregates the wakeup configuration of the I3C devices across its HCI instances (up to two I3C busses) and enables PCI wakeup (PME) only when at least one attached I3C device is enabled as a wakeup source and has IBI enabled. This keeps the PCI wakeup state in sync with the actual requirements of the devices on the busses.
The series is organised as follows:
- Patch 1 fixes a pre-existing recursive acquisition of the bus rwsem in i3c_master_register_new_i3c_devs(). The remaining patches add work to that same function, so the locking is corrected first.
- Patches 2-5 add the generic I3C core support: an ibi_wakeup flag for controllers, marking IBI-capable devices as wakeup capable, reporting wakeup events on IBIs, a helper to query whether any device on a bus has both wakeup and IBI enabled, and a fix to reject IBI requests from devices that do not advertise IBI capability.
- Patches 6-8 wire this up for the mipi-i3c-hci driver: propagate the aggregated I3C wakeup requirements to the PCI function, factor out i3c_hci_sysdev() for the shared device lookup, and advertise IBI wakeup capability when the underlying system device can wake the system.
Note, since the PCI wakeup state is now derived from the wakeup configuration of the attached I3C devices, the PCI device's power/wakeup sysfs attribute no longer provides independent wakeup control.
Changes in V2:
Dropped the RFC tag.
i3c: master: Fix recursive locking during device registration
New patch
i3c: master: Support IBI-based wakeup capability
Dropped the redundant #include <linux/pm_wakeup.h>. That header must not be included directly, and linux/device.h, which is already included, provides device_set_wakeup_capable().
i3c: master: Add helper to query bus wakeup requirements
i3c_master_any_wakeup_enabled() now also requires the device to have IBI enabled, not just system wakeup enabled, so that a device with no active IBI request does not keep PCI PME enabled. desc->ibi_lock is taken while checking. The commit message and kernel-doc are updated to match.
Rebased onto i3c/next.
Adrian Hunter (8):
i3c: master: Fix recursive locking during device registration
i3c: master: Support IBI-based wakeup capability
i3c: master: Report wakeup events for IBIs
i3c: master: Add helper to query bus wakeup requirements
i3c: master: Reject IBI requests from non-IBI-capable devices
i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI
i3c: mipi-i3c-hci: Factor out i3c_hci_sysdev()
i3c: mipi-i3c-hci: Advertise IBI wakeup capability
drivers/i3c/device.c | 8 ++- drivers/i3c/master.c | 84 +++++++++++++++++++--- drivers/i3c/master/mipi-i3c-hci/core.c | 15 ++++ drivers/i3c/master/mipi-i3c-hci/dma.c | 15 +--- drivers/i3c/master/mipi-i3c-hci/hci.h | 2 + drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 23 +++++- include/linux/i3c/master.h | 5 ++ 7 files changed, 123 insertions(+), 29 deletions(-)
Regards
Adrian
PATCH v2 1/8 i3c: master: Fix recursive locking during device registration
i3c_master_register_new_i3c_devs() registers newly discovered devices while holding i3c_bus_normaluse_lock(), a down_read(). device_register() can immediately probe the device, and probe callbacks typically invoke I3C helpers that take i3c_bus_normaluse_lock() again, leading to a recursive acquisition of the same rwsem. rwsems do not support recursive read locking and can deadlock when a writer is waiting. See the "Recursive read locks" section of Documentation/locking/lockdep-design.rst.
For example, with Intel LPSS I3C, LOCKDEP generates a WARNING like:
# echo intel-lpss-i3c.0 > /sys/bus/platform/drivers/mipi-i3c-hci/unbind
# echo intel-lpss-i3c.0 > /sys/bus/platform/drivers/mipi-i3c-hci/bind
WARNING: possible recursive locking detected
kworker/5:1/94 is trying to acquire lock:
ffff88811c810d78 (&i3cbus->lock){++++}-{4:4}, at: i3c_device_match_id+0x45/0x370
but task is already holding lock:
ffff88811c810d78 (&i3cbus->lock){++++}-{4:4}, at: i3c_master_reg_work_fn+0x21/0x5f0Fix this by separating device creation from device registration. Populate desc->dev under the maintenance lock, collect the devices that still need registration into a local list, then release the lock before calling device_register(). Finally retake the lock and clean up any devices that failed to register.
Use the maintenance lock rather than the normal-use lock while adding device objects. A write-side maintenance lock prevents readers from observing a partially initialized desc->dev during initial device population, or desc->dev disappearing if registration fails.
The local list requires a list node, so add a list node member to struct i3c_device.
---
Changes in V2:
New patch
drivers/i3c/master.c | 45 ++++++++++++++++++++++++++++---------- include/linux/i3c/master.h | 2 ++ 2 files changed, 35 insertions(+), 12 deletions(-)
drivers/i3c/master.c +33 -12
@@ -1973,12 +1973,21 @@ static int i3c_master_early_i3c_dev_add(struct i3c_master_controller *master,static void i3c_master_register_new_i3c_devs (struct i3c_master_controller *master) { +struct i3c_device *i3cdev, *tmp;struct i3c_dev_desc *desc; +LIST_HEAD (i3c_unreg_devs);int ret;if (!master->init_done)return ; +i3c_bus_maintenance_lock (&master->bus); + +if (master->shutting_down) { +i3c_bus_maintenance_unlock (&master->bus); +return ; + } +i3c_bus_for_each_i3cdev (&master->bus, desc) {if (desc->dev || !desc->info.dyn_addr || desc == master->this)continue ;
@@ -1999,25 +2008,37 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)if (desc->boardinfo) desc->dev->dev.of_node = desc->boardinfo->of_node; - ret =device_register (&desc->dev->dev); -if (ret) { -dev_err (&master->dev, -"Failed to add I3C device (err = %d)\n" , ret); - desc->dev->desc =NULL ; -put_device (&desc->dev->dev); - desc->dev =NULL ; - } +list_add_tail (&desc->dev->node, &i3c_unreg_devs); + } + +i3c_bus_maintenance_unlock (&master->bus); + +list_for_each_entry_safe (i3cdev, tmp, &i3c_unreg_devs, node) { + ret =device_register (&i3cdev->dev); +if (ret) +dev_err (&master->dev,"Failed to add I3C device (err = %d)\n" , ret); +else +list_del_init (&i3cdev->node); + } + +i3c_bus_maintenance_lock (&master->bus); + +list_for_each_entry_safe (i3cdev, tmp, &i3c_unreg_devs, node) { +list_del (&i3cdev->node); + desc = i3cdev->desc; + i3cdev->desc =NULL ; +put_device (&i3cdev->dev); + desc->dev =NULL ; } + +i3c_bus_maintenance_unlock (&master->bus); }static void i3c_master_reg_work_fn (struct work_struct *work) {struct i3c_master_controller *master =container_of (work,typeof (*master), reg_work); -i3c_bus_normaluse_lock (&master->bus); -if (!master->shutting_down) -i3c_master_register_new_i3c_devs (master); -i3c_bus_normaluse_unlock (&master->bus); +i3c_master_register_new_i3c_devs (master); }/**
include/linux/i3c/master.h +2 -0
@@ -228,6 +228,7 @@ struct i3c_dev_desc {* every time the I3C device is rediscovered with a different dynamic * address assigned * @bus: I3C bus this device is attached to +* @node: unregistered device list node * * I3C device object exposed to I3C device drivers. The takes care of linking * this object to the relevant &struct_i3c_dev_desc one.
@@ -238,6 +239,7 @@ struct i3c_device {struct device dev;struct i3c_dev_desc *desc;struct i3c_bus *bus; +struct list_head node; };/*
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 1/8] i3c: master: Fix recursive locking during device registration
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Dropping the bus maintenance lock around device_register() exposes i3c_device_uevent() and driver probe functions to a Use-After-Free if a concurrent DAA replaces the device.
Pre-existing issues:
- [High] i3c_device_uevent() leaks uninitialized stack memory to userspace when i3cdev->desc is NULL. --
--- Patch [1]: [PATCH V2 1/8] i3c: master: Fix recursive locking during device registration --- commit 33a4dcd6c5626faef95bc7cd02ec4c56c6710c78
Author: Adrian Hunter <[email protected]>
i3c: master: Fix recursive locking during device registration
This commit separates device creation from registration to fix a recursive locking issue. It drops the bus maintenance lock around device_register() to prevent deadlocks when probe callbacks invoke I3C helpers.
drivers/i3c/master.c +0 -0
[ ... ]
Quoted 9 lines
(quoted diff) +0
-5@@ -1999,25 +2008,37 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) if (desc->boardinfo) desc->dev->dev.of_node = desc->boardinfo->of_node; - ret = device_register(&desc->dev->dev); - if (ret) { - dev_err(&master->dev, - "Failed to add I3C device (err = %d)\n", ret); - desc->dev->desc = NULL;
Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2017
Quoted 10 lines
(quoted diff) +7
-3- put_device(&desc->dev->dev); - desc->dev = NULL; - } + list_add_tail(&desc->dev->node, &i3c_unreg_devs); + } + + i3c_bus_maintenance_unlock(&master->bus); + + list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) { + ret = device_register(&i3cdev->dev);
[Severity: High]
Does dropping the maintenance lock around device_register() expose i3c_device_uevent() and driver probes to a use-after-free?
If a concurrent I3C hot-join event or a sysfs write to do_daa occurs while device_register() is running without the lock, __i3c_master_add_i3c_dev_locked() could find a duplicate PID:
__i3c_master_add_i3c_dev_locked() {
olddev = i3c_master_search_i3c_dev_duplicate(newdev);
if (olddev) {
newdev->dev = olddev->dev;
if (newdev->dev)
newdev->dev->desc = newdev;
...
i3c_master_detach_i3c_dev(olddev);
i3c_master_free_i3c_dev(olddev);
}
}Meanwhile, device_register() triggers a KOBJ_ADD uevent. i3c_device_uevent() reads i3cdev->desc locklessly:
i3c_device_uevent() {
if (i3cdev->desc)
devinfo = i3cdev->desc->info;
}Could this lead to i3c_device_uevent() or driver probe functions dereferencing the old descriptor while it is being freed?
Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2029
Quoted 12 lines
(quoted diff) +12
-0+ if (ret) + dev_err(&master->dev, "Failed to add I3C device (err = %d)\n", ret); + else + list_del_init(&i3cdev->node); + } + + i3c_bus_maintenance_lock(&master->bus); + + list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) { + list_del(&i3cdev->node); + desc = i3cdev->desc; + i3cdev->desc = NULL;
[Severity: High]
This is a pre-existing issue, but does setting i3cdev->desc to NULL before unregistration or cleanup lead to leaking uninitialized stack memory in i3c_device_uevent()?
When a device is unregistered (or if registration fails and triggers a uevent), i3cdev->desc is set to NULL. This bypasses the initialization of devinfo in i3c_device_uevent():
i3c_device_uevent() {
struct i3c_device_info devinfo;
u16 manuf, part, ext;
if (i3cdev->desc)
devinfo = i3cdev->desc->info;
manuf = I3C_PID_MANUF_ID(devinfo.pid);
...
return add_uevent_var(env, "MODALIAS=i3c:dcr%02Xmanuf%04X",
devinfo.dcr, manuf);
}Since devinfo is uninitialized on the stack when desc is NULL, could this broadcast uninitialized kernel stack data to userspace processes listening to netlink uevents?
Quoted 6 lines
(quoted diff) +4
-0+ put_device(&i3cdev->dev); + desc->dev = NULL; } + + i3c_bus_maintenance_unlock(&master->bus); }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH V2 1/8] i3c: master: Fix recursive locking during device registration
Quoted 39 lines · On Tue, Jul 28, 2026 at 04:19:35PM +0000, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Dropping the bus maintenance lock arounddevice_register()exposesi3c_device_uevent()and driver probe functions to a Use-After-Free if a concurrent DAA replaces the device.Pre-existing issues:
- [High]i3c_device_uevent()leaks uninitialized stack memory to userspace wheni3cdev->descis NULL. ----- Patch [1]: [PATCH V2 1/8] i3c: master: Fix recursive locking during device registration --- commit
33a4dcd6c5626faef95bc7cd02ec4c56c6710c78
Author: Adrian Hunter <[email protected]>i3c: master: Fix recursive locking during device registration
This commit separates device creation from registration to fix a recursive locking issue. It drops the bus maintenance lock around
device_register()to prevent deadlocks when probe callbacks invoke I3C helpers.drivers/i3c/master.c +0
-0Quoted 15 lines
(quoted diff) +3
-8@@ -1999,25 +2008,37 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) if (desc->boardinfo) desc->dev->dev.of_node = desc->boardinfo->of_node; - ret = device_register(&desc->dev->dev); - if (ret) { - dev_err(&master->dev, - "Failed to add I3C device (err = %d)\n", ret); - desc->dev->desc = NULL; - put_device(&desc->dev->dev); - desc->dev = NULL; - } + list_add_tail(&desc->dev->node, &i3c_unreg_devs); + } +
Quoted 8 lines
Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2017
Quoted 4 lines
(quoted diff) +4
-0+ i3c_bus_maintenance_unlock(&master->bus); + + list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) { + ret = device_register(&i3cdev->dev);[Severity: High]
Does dropping the maintenance lock arounddevice_register()exposei3c_device_uevent()and driver probes to a use-after-free?
look like make sense.
Frank
Quoted 76 lines
If a concurrent I3C hot-join event or a sysfs write to
do_daaoccurs whiledevice_register()is running without the lock,__i3c_master_add_i3c_dev_locked()could find a duplicate PID:__i3c_master_add_i3c_dev_locked() { olddev = i3c_master_search_i3c_dev_duplicate(newdev); if (olddev) { newdev->dev = olddev->dev; if (newdev->dev) newdev->dev->desc = newdev; ... i3c_master_detach_i3c_dev(olddev); i3c_master_free_i3c_dev(olddev); } }Meanwhile,
device_register()triggers aKOBJ_ADDuevent.i3c_device_uevent()readsi3cdev->desclocklessly:i3c_device_uevent() { if (i3cdev->desc) devinfo = i3cdev->desc->info; }Could this lead to
i3c_device_uevent()or driver probe functions dereferencing the old descriptor while it is being freed?Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2029
Quoted 12 lines
(quoted diff) +12
-0+ if (ret) + dev_err(&master->dev, "Failed to add I3C device (err = %d)\n", ret); + else + list_del_init(&i3cdev->node); + } + + i3c_bus_maintenance_lock(&master->bus); + + list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) { + list_del(&i3cdev->node); + desc = i3cdev->desc; + i3cdev->desc = NULL;[Severity: High]
This is a pre-existing issue, but does settingi3cdev->descto NULL before unregistration or cleanup lead to leaking uninitialized stack memory ini3c_device_uevent()?When a device is unregistered (or if registration fails and triggers a uevent),
i3cdev->descis set to NULL. This bypasses the initialization of devinfo ini3c_device_uevent():i3c_device_uevent() { struct i3c_device_info devinfo; u16 manuf, part, ext; if (i3cdev->desc) devinfo = i3cdev->desc->info; manuf = I3C_PID_MANUF_ID(devinfo.pid); ... return add_uevent_var(env, "MODALIAS=i3c:dcr%02Xmanuf%04X", devinfo.dcr, manuf); }Since devinfo is uninitialized on the stack when desc is NULL, could this broadcast uninitialized kernel stack data to userspace processes listening to netlink uevents?
Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2035
Quoted 6 lines
(quoted diff) +4
-0+ put_device(&i3cdev->dev); + desc->dev = NULL; } + + i3c_bus_maintenance_unlock(&master->bus); }--
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH V2 1/8] i3c: master: Fix recursive locking during device registration
Quoted 49 lines · Frank Li
Quoted 39 lines · On Tue, Jul 28, 2026 at 04:19:35PM +0000, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Dropping the bus maintenance lock arounddevice_register()exposesi3c_device_uevent()and driver probe functions to a Use-After-Free if a concurrent DAA replaces the device.Pre-existing issues:
- [High]i3c_device_uevent()leaks uninitialized stack memory to userspace wheni3cdev->descis NULL. ----- Patch [1]: [PATCH V2 1/8] i3c: master: Fix recursive locking during device registration --- commit
33a4dcd6c5626faef95bc7cd02ec4c56c6710c78
Author: Adrian Hunter <[email protected]>i3c: master: Fix recursive locking during device registration
This commit separates device creation from registration to fix a recursive locking issue. It drops the bus maintenance lock around
device_register()to prevent deadlocks when probe callbacks invoke I3C helpers.drivers/i3c/master.c +0
-0Quoted 15 lines
(quoted diff) +3
-8@@ -1999,25 +2008,37 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) if (desc->boardinfo) desc->dev->dev.of_node = desc->boardinfo->of_node; - ret = device_register(&desc->dev->dev); - if (ret) { - dev_err(&master->dev, - "Failed to add I3C device (err = %d)\n", ret); - desc->dev->desc = NULL; - put_device(&desc->dev->dev); - desc->dev = NULL; - } + list_add_tail(&desc->dev->node, &i3c_unreg_devs); + } +Quoted 8 lines
Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2017
Quoted 4 lines
(quoted diff) +4
-0+ i3c_bus_maintenance_unlock(&master->bus); + + list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) { + ret = device_register(&i3cdev->dev);[Severity: High]
Does dropping the maintenance lock arounddevice_register()exposei3c_device_uevent()and driver probes to a use-after-free?
Quoted 1 line
look like make sense.
Yes, but it is not new. A plain sysfs read like:
cat /sys/bus/i3c/devices/<bus.id>-<pid>/uevent
will invoke i3c_device_uevent() without any lock. It has been that way since commit 6cf7b65f7029 ("i3c: Use i3cdev->desc->info instead of calling i3c_device_get_info() to avoid deadlock")
After this patch it should now be possible to take a lock in i3c_device_uevent(), or alternatively, put a copy of pid and dcr on struct i3c_device for use by i3c_device_uevent() so no lock is needed.
In any case, it is a separate fix.
Quoted 79 lines
Frank
Quoted 76 lines
If a concurrent I3C hot-join event or a sysfs write to
do_daaoccurs whiledevice_register()is running without the lock,__i3c_master_add_i3c_dev_locked()could find a duplicate PID:__i3c_master_add_i3c_dev_locked() { olddev = i3c_master_search_i3c_dev_duplicate(newdev); if (olddev) { newdev->dev = olddev->dev; if (newdev->dev) newdev->dev->desc = newdev; ... i3c_master_detach_i3c_dev(olddev); i3c_master_free_i3c_dev(olddev); } }Meanwhile,
device_register()triggers aKOBJ_ADDuevent.i3c_device_uevent()readsi3cdev->desclocklessly:i3c_device_uevent() { if (i3cdev->desc) devinfo = i3cdev->desc->info; }Could this lead to
i3c_device_uevent()or driver probe functions dereferencing the old descriptor while it is being freed?Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2029
Quoted 12 lines
(quoted diff) +12
-0+ if (ret) + dev_err(&master->dev, "Failed to add I3C device (err = %d)\n", ret); + else + list_del_init(&i3cdev->node); + } + + i3c_bus_maintenance_lock(&master->bus); + + list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) { + list_del(&i3cdev->node); + desc = i3cdev->desc; + i3cdev->desc = NULL;[Severity: High]
This is a pre-existing issue, but does settingi3cdev->descto NULL before unregistration or cleanup lead to leaking uninitialized stack memory ini3c_device_uevent()?When a device is unregistered (or if registration fails and triggers a uevent),
i3cdev->descis set to NULL. This bypasses the initialization of devinfo ini3c_device_uevent():i3c_device_uevent() { struct i3c_device_info devinfo; u16 manuf, part, ext; if (i3cdev->desc) devinfo = i3cdev->desc->info; manuf = I3C_PID_MANUF_ID(devinfo.pid); ... return add_uevent_var(env, "MODALIAS=i3c:dcr%02Xmanuf%04X", devinfo.dcr, manuf); }Since devinfo is uninitialized on the stack when desc is NULL, could this broadcast uninitialized kernel stack data to userspace processes listening to netlink uevents?
Review i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2035
Quoted 6 lines
(quoted diff) +4
-0+ put_device(&i3cdev->dev); + desc->dev = NULL; } + + i3c_bus_maintenance_unlock(&master->bus); }--
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
PATCH v2 2/8 i3c: master: Support IBI-based wakeup capability
In reply to Adrian HunterAn I3C controller acts as a bus controller for one or more I3C devices. If the controller can wake the system in response to an In-Band Interrupt (IBI), then any device on that bus that is capable of generating IBIs can potentially be used as a wakeup source.
Add an ibi_wakeup flag to struct i3c_master_controller so controller drivers can advertise support for IBI-based wakeup.
If set, mark IBI-capable I3C devices as wakeup capable when they are registered, allowing wakeup management through the standard device wakeup framework.
---
Changes in V2:
Dropped the redundant #include <linux/pm_wakeup.h>. That header must not be included directly, and linux/device.h, which is already included, provides device_set_wakeup_capable().
drivers/i3c/master.c | 7 +++++++ include/linux/i3c/master.h | 2 ++ 2 files changed, 9 insertions(+)
drivers/i3c/master.c +7 -0
@@ -2008,6 +2008,13 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)if (desc->boardinfo) desc->dev->dev.of_node = desc->boardinfo->of_node; +/* +* In the case of IBI wakeup, any IBI-capable device can +* wakeup. +*/ +if (master->ibi_wakeup && (desc->info.bcr &I3C_BCR_IBI_REQ_CAP )) +device_set_wakeup_capable (&desc->dev->dev, true); +list_add_tail (&desc->dev->node, &i3c_unreg_devs); }
include/linux/i3c/master.h +2 -0
@@ -513,6 +513,7 @@ struct i3c_master_controller_ops {* @hotjoin: true if the master support hotjoin * @rpm_allowed: true if Runtime PM allowed * @rpm_ibi_allowed: true if IBI and Hot-Join allowed while runtime suspended +* @ibi_wakeup: IBI can wakeup the system * @shutting_down: set to true when master begins shutdown or unregister * @boardinfo.i3c: list of I3C boardinfo objects * @boardinfo.i2c: list of I2C boardinfo objects
@@ -547,6 +548,7 @@ struct i3c_master_controller { unsigned int hotjoin: 1; unsigned int rpm_allowed: 1; unsigned int rpm_ibi_allowed: 1; + unsigned int ibi_wakeup: 1;bool shutting_down;struct {struct list_head i3c;
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 2/8] i3c: master: Support IBI-based wakeup capability
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing of_node_get() when assigning boardinfo->of_node to the device, causing reference count corruption when the device is released. --
--- Patch [2]: [PATCH V2 2/8] i3c: master: Support IBI-based wakeup capability --- commit a4a974dcadbb70afc57836a361635db60b65ebde
Author: Adrian Hunter <[email protected]>
i3c: master: Support IBI-based wakeup capability
This commit adds an ibi_wakeup flag to struct i3c_master_controller to allow controller drivers to advertise support for IBI-based wakeup. It also marks IBI-capable I3C devices as wakeup capable during registration.
drivers/i3c/master.c i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) · line 2009
Quoted 7 lines
drivers/i3c/master.c +0
-0@@ -2008,6 +2008,13 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)if (desc->boardinfo) desc->dev->dev.of_node = desc->boardinfo->of_node;
[Severity: High]
This is a pre-existing issue, but does this assignment miss an of_node_get()?
It looks like boardinfo->of_node holds a reference count acquired in of_i3c_master_add_i3c_boardinfo():
boardinfo->of_node = of_node_get(node);
However, when this pointer is copied to desc->dev->dev.of_node here, the reference count is not incremented. Later, when the device is released, i3c_device_release() unconditionally drops a reference:
of_node_put(i3cdev->dev.of_node);
If the device registration fails or if it is later unregistered (e.g., due to a hot-remove event), this would drain the reference conceptually owned by boardinfo.
If the device is then recreated during a subsequent hot-join, could boardinfo reassign the now-freed of_node pointer and cause a use-after-free and double-free on the next release?
Quoted 11 lines
drivers/i3c/master.c +7
-0+/* +* In the case of IBI wakeup, any IBI-capable device can +* wakeup. +*/ +if (master->ibi_wakeup && (desc->info.bcr &I3C_BCR_IBI_REQ_CAP )) +device_set_wakeup_capable (&desc->dev->dev, true); +list_add_tail (&desc->dev->node, &i3c_unreg_devs); }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
PATCH v2 3/8 i3c: master: Report wakeup events for IBIs
In reply to Adrian HunterAn I3C device configured as a wakeup source can wake the system by generating an In-Band Interrupt (IBI).
When an IBI is queued for processing, record a wakeup event for the device if wakeup is enabled. Use a 100 ms processing interval to give the I3C device driver time to process the IBI.
---
Changes in V2:
None
drivers/i3c/master.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/i3c/master.c +6 -0
@@ -3085,6 +3085,9 @@ static void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master) } } +/* Approximate time for IBI handler to run */ +#define I3C_WAKEUP_PROCESSING_TIME_MS 100 +/** * i3c_master_queue_ibi() - Queue an IBI * @dev: the device this IBI is coming from
@@ -3098,6 +3101,9 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot)if (!dev->ibi || !slot)return ; +if (device_may_wakeup (&dev->dev->dev)) +pm_wakeup_event (&dev->dev->dev,I3C_WAKEUP_PROCESSING_TIME_MS ); +atomic_inc (&dev->ibi->pending_ibis);queue_work (dev->ibi->wq, &slot->work); }
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 3/8] i3c: master: Report wakeup events for IBIs
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Concurrent execution of i3c_master_queue_ibi() and device unregistration leads to a NULL pointer dereference or Use-After-Free on dev->dev.
Pre-existing issues:
- [High] Concurrently accessing dev->ibi and its workqueue without synchronization leads to Use-After-Free. --
--- Patch [3]: [PATCH V2 3/8] i3c: master: Report wakeup events for IBIs --- commit 1c61ec6aa53c785eceea38530075c6fa6b7794f2
Author: Adrian Hunter <[email protected]>
i3c: master: Report wakeup events for IBIs
This commit records a wakeup event using pm_wakeup_event() when an In-Band Interrupt (IBI) is queued for processing and the device has wakeup enabled. It uses a 100 ms processing interval.
Quoted 4 lines
drivers/i3c/master.c +0
-0
[ ... ]
drivers/i3c/master.c void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) · line 3106
Quoted 7 lines
drivers/i3c/master.c +3
-0@@ -3098,6 +3101,9 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot)if (!dev->ibi || !slot)return ; +if (device_may_wakeup (&dev->dev->dev)) +pm_wakeup_event (&dev->dev->dev,I3C_WAKEUP_PROCESSING_TIME_MS ); +
[Severity: High]
Does this introduce a regression where a race condition with device unregistration could lead to a NULL pointer dereference or use-after-free on dev->dev?
If an IBI fires and i3c_master_queue_ibi() executes concurrently with device unregistration (for example, during driver module removal or hot-unplug), i3c_master_unregister_i3c_devs() can free dev->dev and set it to NULL:
drivers/i3c/master.c:i3c_master_unregister_i3c_devs() {
...
if (device_is_registered(&i3cdev->dev->dev))
device_unregister(&i3cdev->dev->dev);
else
put_device(&i3cdev->dev->dev);
i3cdev->dev = NULL;
...
}If i3c_master_queue_ibi() passes the lockless if (!dev->ibi) check just before the unregistration runs, could the subsequent call to device_may_wakeup() dereference a freed or NULL pointer?
drivers/i3c/master.c void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) · line 3109
Quoted 3 lines
drivers/i3c/master.c +0
-0atomic_inc (&dev->ibi->pending_ibis);queue_work (dev->ibi->wq, &slot->work); }
[Severity: High]
This is a pre-existing issue, but can accessing dev->ibi and its workqueue here race with IBI teardown and cause a use-after-free?
If i3c_master_queue_ibi() passes the if (!dev->ibi) check, and concurrently the driver is unbound, i3c_dev_free_ibi_locked() will destroy the workqueue and free dev->ibi:
drivers/i3c/master.c:i3c_dev_free_ibi_locked() {
...
if (dev->ibi->wq) {
destroy_workqueue(dev->ibi->wq);
dev->ibi->wq = NULL;
}
kfree(dev->ibi);
dev->ibi = NULL;
...
}Could the interrupt handler then continue execution and call atomic_inc() and queue_work() using the recently freed dev->ibi struct and destroyed workqueue?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH V2 3/8] i3c: master: Report wakeup events for IBIs
Quoted 4 lines · On 28/07/2026 19:47, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Concurrent execution ofi3c_master_queue_ibi()and device unregistration leads to a NULL pointer dereference or Use-After-Free ondev->dev.
Already fixed by "i3c: master: Fix info leak and UAF in device unregister path"
https://lore.kernel.org/all/[email protected]/
Quoted 83 lines
Pre-existing issues:
- [High] Concurrently accessingdev->ibiand its workqueue without synchronization leads to Use-After-Free. ----- Patch [3]: [PATCH V2 3/8] i3c: master: Report wakeup events for IBIs --- commit
1c61ec6aa53c785eceea38530075c6fa6b7794f2
Author: Adrian Hunter <[email protected]>i3c: master: Report wakeup events for IBIs
This commit records a wakeup event using
pm_wakeup_event()when an In-Band Interrupt (IBI) is queued for processing and the device has wakeup enabled. It uses a 100 ms processing interval.Quoted 4 lines
drivers/i3c/master.c +0
-0[ ... ]
drivers/i3c/master.c void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) · line 3106
Quoted 7 lines
drivers/i3c/master.c +3
-0@@ -3098,6 +3101,9 @@ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot)if (!dev->ibi || !slot)return ; +if (device_may_wakeup (&dev->dev->dev)) +pm_wakeup_event (&dev->dev->dev,I3C_WAKEUP_PROCESSING_TIME_MS ); +[Severity: High]
Does this introduce a regression where a race condition with device unregistration could lead to a NULL pointer dereference or use-after-free ondev->dev?If an IBI fires and
i3c_master_queue_ibi()executes concurrently with device unregistration (for example, during driver module removal or hot-unplug),i3c_master_unregister_i3c_devs()can freedev->devand set it to NULL:drivers/i3c/master.c:i3c_master_unregister_i3c_devs() { ... if (device_is_registered(&i3cdev->dev->dev)) device_unregister(&i3cdev->dev->dev); else put_device(&i3cdev->dev->dev); i3cdev->dev = NULL; ... }If
i3c_master_queue_ibi()passes the lockless if (!dev->ibi) check just before the unregistration runs, could the subsequent call todevice_may_wakeup()dereference a freed or NULL pointer?drivers/i3c/master.c void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) · line 3109
Quoted 3 lines
drivers/i3c/master.c +0
-0atomic_inc (&dev->ibi->pending_ibis);queue_work (dev->ibi->wq, &slot->work); }[Severity: High]
This is a pre-existing issue, but can accessingdev->ibiand its workqueue here race with IBI teardown and cause a use-after-free?If
i3c_master_queue_ibi()passes the if (!dev->ibi) check, and concurrently the driver is unbound,i3c_dev_free_ibi_locked()will destroy the workqueue and freedev->ibi:drivers/i3c/master.c:i3c_dev_free_ibi_locked() { ... if (dev->ibi->wq) { destroy_workqueue(dev->ibi->wq); dev->ibi->wq = NULL; } kfree(dev->ibi); dev->ibi = NULL; ... }Could the interrupt handler then continue execution and call
atomic_inc()andqueue_work()using the recently freeddev->ibistruct and destroyed workqueue?
PATCH v2 4/8 i3c: master: Add helper to query bus wakeup requirements
In reply to Adrian HunterAdd i3c_master_any_wakeup_enabled(), which iterates over the devices on an I3C bus and reports whether any of them are enabled for system wakeup and have IBI enabled.
Controller drivers can use this helper to determine whether wakeup support must remain available while the system is suspended.
---
Changes in V2:
i3c_master_any_wakeup_enabled() now also requires the device to have IBI enabled, not just system wakeup enabled, so that a device with no active IBI request does not keep PCI PME enabled. desc->ibi_lock is taken while checking. The commit message and kernel-doc are updated to match.
drivers/i3c/master.c | 30 ++++++++++++++++++++++++++++++ include/linux/i3c/master.h | 1 + 2 files changed, 31 insertions(+)
drivers/i3c/master.c +30 -0
@@ -2048,6 +2048,36 @@ static void i3c_master_reg_work_fn(struct work_struct *work)i3c_master_register_new_i3c_devs (master); } +/** +* i3c_master_any_wakeup_enabled() - check if any device can wake the system +* @master: I3C master controller +* +* Iterate over devices on the bus and return true if any device has +* system wakeup enabled and IBI enabled. +* +* Return: true if any device may wake the system via IBI, false otherwise. +*/ +bool i3c_master_any_wakeup_enabled (struct i3c_master_controller *master) +{ +struct i3c_dev_desc *desc; +bool wakeup = false; + +i3c_bus_normaluse_lock (&master->bus); +i3c_bus_for_each_i3cdev (&master->bus, desc) { +if (!desc->dev || !device_may_wakeup (&desc->dev->dev)) +continue ; +guard (mutex)(&desc->ibi_lock); +if (desc->ibi && desc->ibi->enabled) { + wakeup = true; +break ; + } + } +i3c_bus_normaluse_unlock (&master->bus); + +return wakeup; +} +EXPORT_SYMBOL_GPL (i3c_master_any_wakeup_enabled); +/** * i3c_master_dma_map_single() - Map buffer for single DMA transfer * @dev: device object of a device doing DMA
include/linux/i3c/master.h +1 -0
@@ -748,6 +748,7 @@ void i3c_generic_ibi_recycle_slot(struct i3c_generic_ibi_pool *pool, struct i3c_ibi_slot *slot);void i3c_master_queue_ibi (struct i3c_dev_desc *dev,struct i3c_ibi_slot *slot); +bool i3c_master_any_wakeup_enabled (struct i3c_master_controller *master);struct i3c_ibi_slot *i3c_master_get_free_ibi_slot (struct i3c_dev_desc *dev);
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 4/8] i3c: master: Add helper to query bus wakeup requirements
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Lockless access to other devices' ibi structures in adi_i3c_master_disable_ibi() leads to Use-After-Free. --
--- Patch [4]: [PATCH V2 4/8] i3c: master: Add helper to query bus wakeup requirements --- commit 26d68568db9401a6324a05672a046e8465035dde
Author: Adrian Hunter <[email protected]>
i3c: master: Add helper to query bus wakeup requirements
Adds i3c_master_any_wakeup_enabled() to iterate over devices on an I3C bus and report whether any are enabled for system wakeup and have ibi enabled. Controller drivers can use this helper to determine whether wakeup support must remain available while the system is suspended.
Quoted 4 lines
drivers/i3c/master.c +0
-0
[ ... ]
Quoted 13 lines
drivers/i3c/master.c +9
-0@@ -2048,6 +2048,36 @@ static void i3c_master_reg_work_fn(struct work_struct *work)i3c_master_register_new_i3c_devs (master); } +/** +* i3c_master_any_wakeup_enabled() - check if any device can wake the system +* @master: I3C master controller +* +* Iterate over devices on the bus and return true if any device has +* system wakeup enabled and IBI enabled. +* +* Return: true if any device may wake the system via IBI, false otherwise. +*/
drivers/i3c/master.c static void i3c_master_reg_work_fn(struct work_struct *work) · line 2069
Quoted 10 lines
drivers/i3c/master.c +10
-0+bool i3c_master_any_wakeup_enabled (struct i3c_master_controller *master) +{ +struct i3c_dev_desc *desc; +bool wakeup = false; + +i3c_bus_normaluse_lock (&master->bus); +i3c_bus_for_each_i3cdev (&master->bus, desc) { +if (!desc->dev || !device_may_wakeup (&desc->dev->dev)) +continue ; +guard (mutex)(&desc->ibi_lock);
[Severity: High]
This is a pre-existing issue, but seeing the correct locking here in i3c_master_any_wakeup_enabled() brings to mind a similar loop in adi_i3c_master_disable_ibi() in drivers/i3c/master/adi-i3c-master.c.
Does that loop also need to hold the ibi_lock? It currently accesses i3cdev->ibi of other devices on the bus without holding their respective ibi_lock:
drivers/i3c/master/adi-i3c-master.c:adi_i3c_master_disable_ibi() {
...
i3c_bus_for_each_i3cdev(&m->bus, i3cdev) {
if (dev != i3cdev && i3cdev->ibi)
enabled |= i3cdev->ibi->enabled;
}
...
}Could this lead to a use-after-free if another device's ibi resources are concurrently freed? For example, if i3c_device_free_ibi() is called for another device during concurrent unbinds, it takes the same bus read lock but could free the ibi pointer while this loop is evaluating i3cdev->ibi->enabled.
Quoted 9 lines
drivers/i3c/master.c +9
-0+if (desc->ibi && desc->ibi->enabled) { + wakeup = true; +break ; + } + } +i3c_bus_normaluse_unlock (&master->bus); + +return wakeup; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Re: [PATCH V2 4/8] i3c: master: Add helper to query bus wakeup requirements
In reply to Adrian HunterQuoted 33 lines · Adrian Hunter
Add
i3c_master_any_wakeup_enabled(), which iterates over the devices on an I3C bus and reports whether any of them are enabled for system wakeup and have IBI enabled.Controller drivers can use this helper to determine whether wakeup support must remain available while the system is suspended.
Signed-off-by Adrian Hunter <[email protected]>---
Changes in V2:
i3c_master_any_wakeup_enabled()now also requires the device to have IBI enabled, not just system wakeup enabled, so that a device with no active IBI request does not keep PCI PME enabled.desc->ibi_lockis taken while checking. The commit message and kernel-doc are updated to match.drivers/i3c/master.c | 30 ++++++++++++++++++++++++++++++ include/linux/i3c/master.h | 1 + 2 files changed, 31 insertions(+)drivers/i3c/master.c +1
-0@@ -2048,6 +2048,36 @@ static void i3c_master_reg_work_fn(struct work_struct *work)i3c_master_register_new_i3c_devs (master); } +/**
drivers/i3c/master.c static void i3c_master_reg_work_fn(struct work_struct *work) · line 2061
Quoted 10 lines
drivers/i3c/master.c +10
-0+* i3c_master_any_wakeup_enabled() - check if any device can wake the system +* @master: I3C master controller +* +* Iterate over devices on the bus and return true if any device has +* system wakeup enabled and IBI enabled. +* +* Return: true if any device may wake the system via IBI, false otherwise. +*/ +bool i3c_master_any_wakeup_enabled (struct i3c_master_controller *master) +{
This check most like introdouce rise condition.
if (i3c_master_any_wakeup_enabled())
do_some_thing()
no lock protection, so between check i3c_master_any_wakeup_enabled() and do_some_thing(), condtion may be changed.
Frank
Quoted 37 lines
drivers/i3c/master.c +19
-0+struct i3c_dev_desc *desc; +bool wakeup = false; + +i3c_bus_normaluse_lock (&master->bus); +i3c_bus_for_each_i3cdev (&master->bus, desc) { +if (!desc->dev || !device_may_wakeup (&desc->dev->dev)) +continue ; +guard (mutex)(&desc->ibi_lock); +if (desc->ibi && desc->ibi->enabled) { + wakeup = true; +break ; + } + } +i3c_bus_normaluse_unlock (&master->bus); + +return wakeup; +} +EXPORT_SYMBOL_GPL (i3c_master_any_wakeup_enabled); +/** * i3c_master_dma_map_single() - Map buffer for single DMA transfer * @dev: device object of a device doing DMA include/linux/i3c/master.h +1
-1@@ -748,6 +748,7 @@ void i3c_generic_ibi_recycle_slot(struct i3c_generic_ibi_pool *pool, struct i3c_ibi_slot *slot);void i3c_master_queue_ibi (struct i3c_dev_desc *dev,struct i3c_ibi_slot *slot); +bool i3c_master_any_wakeup_enabled (struct i3c_master_controller *master);struct i3c_ibi_slot *i3c_master_get_free_ibi_slot (struct i3c_dev_desc *dev); --2.53.0
Re: [PATCH V2 4/8] i3c: master: Add helper to query bus wakeup requirements
Quoted 47 lines · Frank Li
Quoted 33 lines · Adrian Hunter
Add
i3c_master_any_wakeup_enabled(), which iterates over the devices on an I3C bus and reports whether any of them are enabled for system wakeup and have IBI enabled.Controller drivers can use this helper to determine whether wakeup support must remain available while the system is suspended.
Signed-off-by Adrian Hunter <[email protected]>---
Changes in V2:
i3c_master_any_wakeup_enabled()now also requires the device to have IBI enabled, not just system wakeup enabled, so that a device with no active IBI request does not keep PCI PME enabled.desc->ibi_lockis taken while checking. The commit message and kernel-doc are updated to match.drivers/i3c/master.c | 30 ++++++++++++++++++++++++++++++ include/linux/i3c/master.h | 1 + 2 files changed, 31 insertions(+)drivers/i3c/master.c +1
-0@@ -2048,6 +2048,36 @@ static void i3c_master_reg_work_fn(struct work_struct *work)i3c_master_register_new_i3c_devs (master); } +/** drivers/i3c/master.c static void i3c_master_reg_work_fn(struct work_struct *work) · line 2061
Quoted 10 lines
drivers/i3c/master.c +10
-0+* i3c_master_any_wakeup_enabled() - check if any device can wake the system +* @master: I3C master controller +* +* Iterate over devices on the bus and return true if any device has +* system wakeup enabled and IBI enabled. +* +* Return: true if any device may wake the system via IBI, false otherwise. +*/ +bool i3c_master_any_wakeup_enabled (struct i3c_master_controller *master) +{This check most like introdouce rise condition.
Quoted 5 lines
if (
i3c_master_any_wakeup_enabled())do_some_thing()no lock protection, so between check
i3c_master_any_wakeup_enabled()anddo_some_thing(), condtion may be changed.
It should be called when the condition cannot change anymore.
It is being called on controller suspend path. device_may_wakeup() should not change after user space is frozen. I3C device drivers have already had their ->suspend() callbacks called, but should not really be doing anything that alters the outcome of i3c_master_any_wakeup_enabled() anyway.
Quoted 40 lines
Frank
Quoted 37 lines
drivers/i3c/master.c +19
-0+struct i3c_dev_desc *desc; +bool wakeup = false; + +i3c_bus_normaluse_lock (&master->bus); +i3c_bus_for_each_i3cdev (&master->bus, desc) { +if (!desc->dev || !device_may_wakeup (&desc->dev->dev)) +continue ; +guard (mutex)(&desc->ibi_lock); +if (desc->ibi && desc->ibi->enabled) { + wakeup = true; +break ; + } + } +i3c_bus_normaluse_unlock (&master->bus); + +return wakeup; +} +EXPORT_SYMBOL_GPL (i3c_master_any_wakeup_enabled); +/** * i3c_master_dma_map_single() - Map buffer for single DMA transfer * @dev: device object of a device doing DMA include/linux/i3c/master.h +1
-1@@ -748,6 +748,7 @@ void i3c_generic_ibi_recycle_slot(struct i3c_generic_ibi_pool *pool, struct i3c_ibi_slot *slot);void i3c_master_queue_ibi (struct i3c_dev_desc *dev,struct i3c_ibi_slot *slot); +bool i3c_master_any_wakeup_enabled (struct i3c_master_controller *master);struct i3c_ibi_slot *i3c_master_get_free_ibi_slot (struct i3c_dev_desc *dev); --2.53.0
PATCH v2 5/8 i3c: master: Reject IBI requests from non-IBI-capable devices
In reply to Adrian Hunteri3c_device_request_ibi() does not verify that a device advertises IBI support before attempting to set up IBI handling.
Add a check for I3C_BCR_IBI_REQ_CAP and fail with -EOPNOTSUPP when IBI support is not reported by the device. This keeps IBI setup consistent with other IBI-related functionality, such as exposing wakeup capability only for IBI-capable devices.
---
Changes in V2:
None
drivers/i3c/device.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/i3c/device.c +5 -3
@@ -205,12 +205,14 @@ int i3c_device_request_ibi(struct i3c_device *dev,return ret;i3c_bus_normaluse_lock (dev->bus); -if (dev->desc) { +if (!dev->desc) { + ret = -ENOENT ; + }else if (!(dev->desc->info.bcr &I3C_BCR_IBI_REQ_CAP )) { + ret = -EOPNOTSUPP ; + }else {mutex_lock (&dev->desc->ibi_lock); ret =i3c_dev_request_ibi_locked (dev->desc, req);mutex_unlock (&dev->desc->ibi_lock); - }else { - ret = -ENOENT ; }i3c_bus_normaluse_unlock (dev->bus);
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 5/8] i3c: master: Reject IBI requests from non-IBI-capable devices
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Leaked workqueue in i3c_dev_request_ibi_locked() when master->ops->request_ibi() fails. --
--- Patch [5]: [PATCH V2 5/8] i3c: master: Reject IBI requests from non-IBI-capable devices --- commit d69e542b87c33e0789e410767b2ee354fe000c28
Author: Adrian Hunter <[email protected]>
i3c: master: Reject IBI requests from non-IBI-capable devices
This commit adds a check in i3c_device_request_ibi() to ensure a device reports IBI support before attempting to set up IBI handling. If the device does not advertise I3C_BCR_IBI_REQ_CAP, it now fails with -EOPNOTSUPP.
Quoted 6 lines
drivers/i3c/device.c +0
-0@@ -205,12 +205,14 @@ int i3c_device_request_ibi(struct i3c_device *dev,return ret;
drivers/i3c/device.c int i3c_device_request_ibi(struct i3c_device *dev, · line 214
Quoted 10 lines
drivers/i3c/device.c +5
-1i3c_bus_normaluse_lock (dev->bus); -if (dev->desc) { +if (!dev->desc) { + ret = -ENOENT ; + }else if (!(dev->desc->info.bcr &I3C_BCR_IBI_REQ_CAP )) { + ret = -EOPNOTSUPP ; + }else {mutex_lock (&dev->desc->ibi_lock); ret =i3c_dev_request_ibi_locked (dev->desc, req);
[Severity: High]
This is a pre-existing issue, but does i3c_dev_request_ibi_locked() leak the allocated workqueue if the master's request_ibi callback fails?
Looking at i3c_dev_request_ibi_locked() in drivers/i3c/master.c:
ibi->wq = alloc_ordered_workqueue(dev_name(i3cdev_to_dev(dev->dev)),
WQ_MEM_RECLAIM);
if (!ibi->wq) {
kfree(ibi);
return -ENOMEM;
}
...
ret = master->ops->request_ibi(dev, req);
if (ret) {
kfree(ibi);
dev->ibi = NULL;
}If master->ops->request_ibi() returns an error, the error path frees ibi but doesn't call destroy_workqueue(ibi->wq).
If a device probe repeatedly fails at this step, could this result in a workqueue and memory leak?
Quoted 5 lines
drivers/i3c/device.c +0
-2mutex_unlock (&dev->desc->ibi_lock); - }else { - ret = -ENOENT ; }i3c_bus_normaluse_unlock (dev->bus);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Re: [PATCH V2 5/8] i3c: master: Reject IBI requests from non-IBI-capable devices
In reply to Adrian HunterQuoted 10 lines · Adrian Hunter
i3c_device_request_ibi()does not verify that a device advertises IBI support before attempting to set up IBI handling.Add a check for
I3C_BCR_IBI_REQ_CAPand fail with-EOPNOTSUPPwhen IBI support is not reported by the device. This keeps IBI setup consistent with other IBI-related functionality, such as exposing wakeup capability only for IBI-capable devices.Signed-off-by Adrian Hunter <[email protected]>---
Quoted 35 lines
Changes in V2:
None
drivers/i3c/device.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)drivers/i3c/device.c +5
-4@@ -205,12 +205,14 @@ int i3c_device_request_ibi(struct i3c_device *dev,return ret;i3c_bus_normaluse_lock (dev->bus); -if (dev->desc) { +if (!dev->desc) { + ret = -ENOENT ; + }else if (!(dev->desc->info.bcr &I3C_BCR_IBI_REQ_CAP )) { + ret = -EOPNOTSUPP ; + }else {mutex_lock (&dev->desc->ibi_lock); ret =i3c_dev_request_ibi_locked (dev->desc, req);mutex_unlock (&dev->desc->ibi_lock); - }else { - ret = -ENOENT ; }i3c_bus_normaluse_unlock (dev->bus); --2.53.0
PATCH v2 6/8 i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI
In reply to Adrian HunterKeep the PCI wakeup state aligned with the wakeup requirements of the devices served by the controller(s).
The PCI function is the wakeup source for HCI instances exposed beneath it. However, wakeup is only needed when at least one attached I3C device is enabled as a wakeup source.
During suspend, check whether any HCI instance has a wakeup-enabled I3C device and enable wakeup for the PCI function only in that case. Otherwise leave PCI wakeup disabled.
Note, the suspend callback is used for both system and runtime suspend. Although this change may update the PCI wakeup state during runtime suspend, it does so only when the required wakeup state changes. Moreover, PCI wakeup-capable devices already have PME wakeup armed for runtime suspend, so changing the wakeup-enabled state does not affect runtime PM wakeup behavior.
Note also, since the PCI wakeup state is derived from the wakeup configuration of the attached I3C devices, the PCI device power/wakeup sysfs attribute no longer provides independent wakeup control.
---
Changes in V2:
None
.../master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +21 -2
@@ -265,6 +265,8 @@ static bool mipi_i3c_hci_pci_is_operational(struct device *dev, bool update)struct mipi_i3c_hci_pci_pm_data {struct device *dev[INST_MAX ];int dev_cnt; +bool can_wakeup; +bool may_wakeup; };static bool mipi_i3c_hci_pci_is_mfd (struct device *dev)
@@ -272,6 +274,13 @@ static bool mipi_i3c_hci_pci_is_mfd(struct device *dev)return dev_is_platform (dev) &&mfd_get_cell (to_platform_device (dev)); } +static bool mipi_i3c_hci_pci_any_wakeup_enabled (struct device *dev) +{ +struct i3c_hci *hci =dev_get_drvdata (dev); + +return i3c_master_any_wakeup_enabled (&hci->master); +} +static int mipi_i3c_hci_pci_suspend_instance (struct device *dev,void *data) {struct mipi_i3c_hci_pci_pm_data *pm_data = data;
@@ -287,6 +296,9 @@ static int mipi_i3c_hci_pci_suspend_instance(struct device *dev, void *data) pm_data->dev[pm_data->dev_cnt++] = dev; +if (pm_data->can_wakeup &&mipi_i3c_hci_pci_any_wakeup_enabled (dev)) + pm_data->may_wakeup = true; +return 0 ; }
@@ -317,12 +329,19 @@ static int mipi_i3c_hci_pci_suspend(struct device *dev)if (!hci->info->control_instance_pm)return 0 ; + pm_data.can_wakeup =device_can_wakeup (dev); + ret =device_for_each_child_reverse (dev, &pm_data, mipi_i3c_hci_pci_suspend_instance); -if (ret) +if (ret) {for (int i =0 ; i < pm_data.dev_cnt; i++)i3c_hci_rpm_resume (pm_data.dev[i]); +return ret; + } -return ret; +if (device_may_wakeup (dev) != pm_data.may_wakeup) +device_set_wakeup_enable (dev, pm_data.may_wakeup); + +return 0 ; }static int mipi_i3c_hci_pci_resume (struct device *dev)
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 6/8] i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Modifying device wakeup state dynamically during the suspend callback violates PM architecture, overrides sysfs UAPI, and triggers allocations and PM core warnings during system transitions.
- [Medium] The driver violates MFD architectural guidelines by dynamically allocating the mfd_cell array, calling MFD APIs outside drivers/mfd/, and the patch introduces a bespoke accessor that tightly couples parent and child drivers.
Pre-existing issues:
- [High] Unbound child devices cause a NULL pointer dereference and guaranteed kernel panic during the parent's suspend loop. --
--- Patch [6]: [PATCH V2 6/8] i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI --- commit bd9a09f1c602f19882ed3fc13b554af06b2d2298
Author: Adrian Hunter <[email protected]>
i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI
This commit updates the PCI function's wakeup state based on the wakeup requirements of the I3C devices attached to the HCI instances during suspend. It checks if any attached device is enabled as a wakeup source and updates the PCI device's wakeup capability accordingly.
Quoted 5 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +0
-0
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c static bool mipi_i3c_hci_pci_is_mfd(struct device *dev) · line 282
Quoted 9 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +6
-0@@ -272,6 +274,13 @@ static bool mipi_i3c_hci_pci_is_mfd(struct device *dev)return dev_is_platform (dev) &&mfd_get_cell (to_platform_device (dev)); } +static bool mipi_i3c_hci_pci_any_wakeup_enabled (struct device *dev) +{ +struct i3c_hci *hci =dev_get_drvdata (dev); + +return i3c_master_any_wakeup_enabled (&hci->master); +}
[Severity: High]
This is a pre-existing issue, but does this code handle unbound child devices safely?
If the child platform driver is unbound manually via sysfs, or if it fails to probe, dev_get_drvdata() will return NULL. If the hardware bus was left enabled, mipi_i3c_hci_pci_is_operational() can still return true. The parent's suspend loop will then pass the device here, and to the existing i3c_hci_rpm_suspend() function, where both will unconditionally dereference the NULL pointer.
Could a check for a NULL hci pointer be added to prevent a kernel panic during suspend?
[Severity: Medium]
Does this custom accessor bypass MFD architectural guidelines?
The MFD subsystem rules specify that parent drivers should not use custom accessors to dig into the private driver data of child devices. Here, the parent driver is directly extracting the child's internal state (&hci->master) instead of using standard APIs.
Could this state propagation be handled through standard device PM wake APIs rather than directly coupling the parent and child drivers?
[ ... ]
Quoted 7 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +2
-0@@ -317,12 +329,19 @@ static int mipi_i3c_hci_pci_suspend(struct device *dev)if (!hci->info->control_instance_pm)return 0 ; + pm_data.can_wakeup =device_can_wakeup (dev); + ret =device_for_each_child_reverse (dev, &pm_data, mipi_i3c_hci_pci_suspend_instance);
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c static int mipi_i3c_hci_pci_suspend(struct device *dev) · line 342
Quoted 10 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +5
-2-if (ret) +if (ret) {for (int i =0 ; i < pm_data.dev_cnt; i++)i3c_hci_rpm_resume (pm_data.dev[i]); +return ret; + } -return ret; +if (device_may_wakeup (dev) != pm_data.may_wakeup) +device_set_wakeup_enable (dev, pm_data.may_wakeup);
[Severity: High]
Is it safe to call device_set_wakeup_enable() during the suspend execution path?
Calling this function during a system suspend triggers memory allocations via kzalloc(..., GFP_KERNEL) and registers sysfs nodes while the PM transition is actively in progress. This triggers the PM core warning "Suspicious device_wakeup_enable() during system transition!" and introduces memory deadlock risks.
Additionally, does this unconditionally override the user's explicit PM policy configured via the power/wakeup sysfs attribute?
Quoted 3 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +2
-0+ +return 0 ; }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Re: [PATCH V2 6/8] i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI
Quoted 40 lines · On 28/07/2026 20:18, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Modifying device wakeup state dynamically during the suspend callback violates PM architecture, overrides sysfs UAPI, and triggers allocations and PM core warnings during system transitions.
- [Medium] The driver violates MFD architectural guidelines by dynamically allocating themfd_cellarray, calling MFD APIs outsidedrivers/mfd/, and the patch introduces a bespoke accessor that tightly couples parent and child drivers.Pre-existing issues:
- [High] Unbound child devices cause a NULL pointer dereference and guaranteed kernel panic during the parent's suspend loop. ----- Patch [6]: [PATCH V2 6/8] i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI --- commit
bd9a09f1c602f19882ed3fc13b554af06b2d2298
Author: Adrian Hunter <[email protected]>i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI
This commit updates the PCI function's wakeup state based on the wakeup requirements of the I3C devices attached to the HCI instances during suspend. It checks if any attached device is enabled as a wakeup source and updates the PCI device's wakeup capability accordingly.
Quoted 5 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +0
-0drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c static bool mipi_i3c_hci_pci_is_mfd(struct device *dev) · line 282
Quoted 9 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +6
-0@@ -272,6 +274,13 @@ static bool mipi_i3c_hci_pci_is_mfd(struct device *dev)return dev_is_platform (dev) &&mfd_get_cell (to_platform_device (dev)); } +static bool mipi_i3c_hci_pci_any_wakeup_enabled (struct device *dev) +{ +struct i3c_hci *hci =dev_get_drvdata (dev); + +return i3c_master_any_wakeup_enabled (&hci->master); +}[Severity: High]
This is a pre-existing issue, but does this code handle unbound child devices safely?
Quoted 3 lines
If the child platform driver is unbound manually via sysfs, or if it fails to probe,
dev_get_drvdata()will return NULL. If the hardware bus was left enabled
It never is. Doesn't happen.
Quoted 8 lines
mipi_i3c_hci_pci_is_operational()can still return true. The parent's
suspend loop will then pass the device here, and to the existingi3c_hci_rpm_suspend()function, where both will unconditionally dereference the NULL pointer.Could a check for a NULL hci pointer be added to prevent a kernel panic during suspend?
Quoted 7 lines
[Severity: Medium]
Does this custom accessor bypass MFD architectural guidelines?The MFD subsystem rules specify that parent drivers should not use custom accessors to dig into the private driver data of child devices. Here, the parent driver is directly extracting the child's internal state (
&hci->master) instead of using standard APIs.
No, the PCI driver is a glue driver for the platform driver. They are in the same directory and are meant to work together.
Quoted 3 lines
Could this state propagation be handled through standard device PM wake APIs rather than directly coupling the parent and child drivers?
There is no standard API for wakeup propagation.
Quoted 17 lines
[ ... ]
Quoted 14 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +5
-1@@ -317,12 +329,19 @@ static int mipi_i3c_hci_pci_suspend(struct device *dev)if (!hci->info->control_instance_pm)return 0 ; + pm_data.can_wakeup =device_can_wakeup (dev); + ret =device_for_each_child_reverse (dev, &pm_data, mipi_i3c_hci_pci_suspend_instance); -if (ret) +if (ret) {for (int i =0 ; i < pm_data.dev_cnt; i++)i3c_hci_rpm_resume (pm_data.dev[i]); +return ret; + }
Quoted 7 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c static int mipi_i3c_hci_pci_suspend(struct device *dev) · line 342
Quoted 3 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +2
-1-return ret; +if (device_may_wakeup (dev) != pm_data.may_wakeup) +device_set_wakeup_enable (dev, pm_data.may_wakeup);[Severity: High]
Is it safe to calldevice_set_wakeup_enable()during the suspend execution path?
It is not unprecedented. Changes to the wakeup state should be relatively rare i.e. mostly device_may_wakeup(dev) == pm_data.may_wakeup so no actual update.
Quoted 6 lines
Calling this function during a system suspend triggers memory allocations via
kzalloc(..., GFP_KERNEL)and registers sysfs nodes while the PM transition is actively in progress. This triggers the PM core warning "Suspiciousdevice_wakeup_enable()during system transition!" and introduces memory deadlock risks.
There is a debug message, but that is all.
Quoted 3 lines
Additionally, does this unconditionally override the user's explicit PM policy configured via the power/wakeup sysfs attribute?
Not really. The user sets policy via I3C devices' wakeup attributes not the bus controller's wakeup attribute.
Quoted 5 lines
Quoted 4 lines
drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c +2
-0+ +return 0 ; }
PATCH v2 7/8 i3c: mipi-i3c-hci: Factor out i3c_hci_sysdev()
In reply to Adrian HunterThe MIPI I3C HCI driver needs to identify the underlying system device used for DMA mapping and PM operations. The logic for determining that device is currently embedded in the DMA implementation.
Factor this code out into i3c_hci_sysdev() so it can be shared by other parts of the driver and keep the device-selection logic in one place.
---
Changes in V2:
None
drivers/i3c/master/mipi-i3c-hci/core.c | 12 ++++++++++++ drivers/i3c/master/mipi-i3c-hci/dma.c | 15 +-------------- drivers/i3c/master/mipi-i3c-hci/hci.h | 2 ++ 3 files changed, 15 insertions(+), 14 deletions(-)
drivers/i3c/master/mipi-i3c-hci/core.c +12 -0
@@ -15,6 +15,7 @@#include <linux/interrupt.h> #include <linux/iopoll.h> #include <linux/module.h> +#include <linux/pci.h> #include <linux/platform_data/mipi-i3c-hci.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h>
@@ -117,6 +118,17 @@ static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m) return container_of(m, struct i3c_hci, master); } +/* +* Determine the device that does PM / DMA and has IOMMU setup done for it in +* case of enabled IOMMU (for use with the DMA API). +* Such device is either "mipi-i3c-hci" platform device (OF/ACPI enumeration) +* parent or grandparent (PCI enumeration). +*/ +struct device *i3c_hci_sysdev (struct device *dev) +{ +return dev->parent &&dev_is_pci (dev->parent) ? dev->parent : dev; +} +static void i3c_hci_set_master_dyn_addr (struct i3c_hci *hci) { reg_write(MASTER_DEVICE_ADDR,
drivers/i3c/master/mipi-i3c-hci/dma.c +1 -14
@@ -15,7 +15,6 @@#include <linux/errno.h> #include <linux/i3c/master.h> #include <linux/io.h> -#include <linux/pci.h> #include "hci.h" #include "cmd.h"
@@ -301,23 +300,11 @@ static int hci_dma_init(struct i3c_hci *hci) {struct hci_rings_data *rings;struct hci_rh_data *rh; -struct device *sysdev;u32 regval;unsigned int i, nr_rings, xfers_sz, resps_sz;unsigned int ibi_status_ring_sz, ibi_data_ring_sz;int ret; -/* -* Set pointer to a physical device that does DMA and has IOMMU setup -* done for it in case of enabled IOMMU and use it with the DMA API. -* Here such device is either -* "mipi-i3c-hci" platform device (OF/ACPI enumeration) parent or -* grandparent (PCI enumeration). -*/ - sysdev = hci->master.dev.parent; -if (sysdev->parent &&dev_is_pci (sysdev->parent)) - sysdev = sysdev->parent; - regval =rhs_reg_read (CONTROL ); nr_rings =FIELD_GET (MAX_HEADER_COUNT_CAP , regval);dev_dbg (&hci->master.dev,"%d DMA rings available\n" , nr_rings);
@@ -332,7 +319,7 @@ static int hci_dma_init(struct i3c_hci *hci)return -ENOMEM ; hci->io_data = rings; rings->total = nr_rings; - rings->sysdev = sysdev; + rings->sysdev =i3c_hci_sysdev (hci->master.dev.parent);for (i =0 ; i < rings->total; i++) {u32 offset =rhs_reg_read (RHn_OFFSET (i));
drivers/i3c/master/mipi-i3c-hci/hci.h +2 -0
@@ -184,6 +184,8 @@ void amd_set_resp_buf_thld(struct i3c_hci *hci);void i3c_hci_sync_irq_inactive (struct i3c_hci *hci);int i3c_hci_process_xfer (struct i3c_hci *hci,struct hci_xfer *xfer,int n); +struct device *i3c_hci_sysdev (struct device *dev); +#define DEFAULT_AUTOSUSPEND_DELAY_MS 1000int i3c_hci_rpm_suspend (struct device *dev);
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 7/8] i3c: mipi-i3c-hci: Factor out i3c_hci_sysdev()
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 8 lines
The MIPI I3C HCI driver needs to identify the underlying system device used for DMA mapping and PM operations. The logic for determining that device is currently embedded in the DMA implementation.
Factor this code out into
i3c_hci_sysdev()so it can be shared by other parts of the driver and keep the device-selection logic in one place.Signed-off-by Adrian Hunter <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
Re: [PATCH V2 7/8] i3c: mipi-i3c-hci: Factor out i3c_hci_sysdev()
In reply to Adrian HunterQuoted 34 lines · Adrian Hunter
The MIPI I3C HCI driver needs to identify the underlying system device used for DMA mapping and PM operations. The logic for determining that device is currently embedded in the DMA implementation.
Factor this code out into
i3c_hci_sysdev()so it can be shared by other parts of the driver and keep the device-selection logic in one place.Signed-off-by Adrian Hunter <[email protected]>---
Changes in V2:
None
drivers/i3c/master/mipi-i3c-hci/core.c | 12 ++++++++++++ drivers/i3c/master/mipi-i3c-hci/dma.c | 15 +-------------- drivers/i3c/master/mipi-i3c-hci/hci.h | 2 ++ 3 files changed, 15 insertions(+), 14 deletions(-)drivers/i3c/master/mipi-i3c-hci/core.c +1
-0@@ -15,6 +15,7 @@#include <linux/interrupt.h> #include <linux/iopoll.h> #include <linux/module.h> +#include <linux/pci.h> #include <linux/platform_data/mipi-i3c-hci.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h>
drivers/i3c/master/mipi-i3c-hci/core.c static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m) · line 127
Quoted 10 lines
drivers/i3c/master/mipi-i3c-hci/core.c +7
-0@@ -117,6 +118,17 @@ static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m) return container_of(m, struct i3c_hci, master); } +/* +* Determine the device that does PM / DMA and has IOMMU setup done for it in +* case of enabled IOMMU (for use with the DMA API). +* Such device is either "mipi-i3c-hci" platform device (OF/ACPI enumeration) +* parent or grandparent (PCI enumeration). +*/ +struct device *i3c_hci_sysdev (struct device *dev)
Is it simpler if argument is struct i3c_hci *hci
Frank
Quoted 68 lines
drivers/i3c/master/mipi-i3c-hci/core.c +4
-0+{ +return dev->parent &&dev_is_pci (dev->parent) ? dev->parent : dev; +} +static void i3c_hci_set_master_dyn_addr (struct i3c_hci *hci) { reg_write(MASTER_DEVICE_ADDR,drivers/i3c/master/mipi-i3c-hci/dma.c +1
-14@@ -15,7 +15,6 @@#include <linux/errno.h> #include <linux/i3c/master.h> #include <linux/io.h> -#include <linux/pci.h> #include "hci.h" #include "cmd.h" @@ -301,23 +300,11 @@ static int hci_dma_init(struct i3c_hci *hci) {struct hci_rings_data *rings;struct hci_rh_data *rh; -struct device *sysdev;u32 regval;unsigned int i, nr_rings, xfers_sz, resps_sz;unsigned int ibi_status_ring_sz, ibi_data_ring_sz;int ret; -/* -* Set pointer to a physical device that does DMA and has IOMMU setup -* done for it in case of enabled IOMMU and use it with the DMA API. -* Here such device is either -* "mipi-i3c-hci" platform device (OF/ACPI enumeration) parent or -* grandparent (PCI enumeration). -*/ - sysdev = hci->master.dev.parent; -if (sysdev->parent &&dev_is_pci (sysdev->parent)) - sysdev = sysdev->parent; - regval =rhs_reg_read (CONTROL ); nr_rings =FIELD_GET (MAX_HEADER_COUNT_CAP , regval);dev_dbg (&hci->master.dev,"%d DMA rings available\n" , nr_rings);@@ -332,7 +319,7 @@ static int hci_dma_init(struct i3c_hci *hci)return -ENOMEM ; hci->io_data = rings; rings->total = nr_rings; - rings->sysdev = sysdev; + rings->sysdev =i3c_hci_sysdev (hci->master.dev.parent);for (i =0 ; i < rings->total; i++) {u32 offset =rhs_reg_read (RHn_OFFSET (i));drivers/i3c/master/mipi-i3c-hci/hci.h +2
-1@@ -184,6 +184,8 @@ void amd_set_resp_buf_thld(struct i3c_hci *hci);void i3c_hci_sync_irq_inactive (struct i3c_hci *hci);int i3c_hci_process_xfer (struct i3c_hci *hci,struct hci_xfer *xfer,int n); +struct device *i3c_hci_sysdev (struct device *dev); +#define DEFAULT_AUTOSUSPEND_DELAY_MS 1000int i3c_hci_rpm_suspend (struct device *dev); --2.53.0
Re: [PATCH V2 7/8] i3c: mipi-i3c-hci: Factor out i3c_hci_sysdev()
Quoted 38 lines · Frank Li
Quoted 37 lines · Adrian Hunter
The MIPI I3C HCI driver needs to identify the underlying system device used for DMA mapping and PM operations. The logic for determining that device is currently embedded in the DMA implementation.
Factor this code out into
i3c_hci_sysdev()so it can be shared by other parts of the driver and keep the device-selection logic in one place.Signed-off-by Adrian Hunter <[email protected]>---
Changes in V2:
None
drivers/i3c/master/mipi-i3c-hci/core.c | 12 ++++++++++++ drivers/i3c/master/mipi-i3c-hci/dma.c | 15 +-------------- drivers/i3c/master/mipi-i3c-hci/hci.h | 2 ++ 3 files changed, 15 insertions(+), 14 deletions(-)drivers/i3c/master/mipi-i3c-hci/core.c +1
-0@@ -15,6 +15,7 @@#include <linux/interrupt.h> #include <linux/iopoll.h> #include <linux/module.h> +#include <linux/pci.h> #include <linux/platform_data/mipi-i3c-hci.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -117,6 +118,17 @@ static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m) return container_of(m, struct i3c_hci, master); }
Quoted 9 lines
drivers/i3c/master/mipi-i3c-hci/core.c static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m) · line 127
Quoted 7 lines
drivers/i3c/master/mipi-i3c-hci/core.c +7
-0+/* +* Determine the device that does PM / DMA and has IOMMU setup done for it in +* case of enabled IOMMU (for use with the DMA API). +* Such device is either "mipi-i3c-hci" platform device (OF/ACPI enumeration) +* parent or grandparent (PCI enumeration). +*/ +struct device *i3c_hci_sysdev (struct device *dev)Is it simpler if argument is struct
i3c_hci*hci
It will be called before hci->master.dev.parent is populated, see patch 8.
Quoted 71 lines
Frank
Quoted 68 lines
drivers/i3c/master/mipi-i3c-hci/core.c +4
-0+{ +return dev->parent &&dev_is_pci (dev->parent) ? dev->parent : dev; +} +static void i3c_hci_set_master_dyn_addr (struct i3c_hci *hci) { reg_write(MASTER_DEVICE_ADDR,drivers/i3c/master/mipi-i3c-hci/dma.c +1
-14@@ -15,7 +15,6 @@#include <linux/errno.h> #include <linux/i3c/master.h> #include <linux/io.h> -#include <linux/pci.h> #include "hci.h" #include "cmd.h" @@ -301,23 +300,11 @@ static int hci_dma_init(struct i3c_hci *hci) {struct hci_rings_data *rings;struct hci_rh_data *rh; -struct device *sysdev;u32 regval;unsigned int i, nr_rings, xfers_sz, resps_sz;unsigned int ibi_status_ring_sz, ibi_data_ring_sz;int ret; -/* -* Set pointer to a physical device that does DMA and has IOMMU setup -* done for it in case of enabled IOMMU and use it with the DMA API. -* Here such device is either -* "mipi-i3c-hci" platform device (OF/ACPI enumeration) parent or -* grandparent (PCI enumeration). -*/ - sysdev = hci->master.dev.parent; -if (sysdev->parent &&dev_is_pci (sysdev->parent)) - sysdev = sysdev->parent; - regval =rhs_reg_read (CONTROL ); nr_rings =FIELD_GET (MAX_HEADER_COUNT_CAP , regval);dev_dbg (&hci->master.dev,"%d DMA rings available\n" , nr_rings);@@ -332,7 +319,7 @@ static int hci_dma_init(struct i3c_hci *hci)return -ENOMEM ; hci->io_data = rings; rings->total = nr_rings; - rings->sysdev = sysdev; + rings->sysdev =i3c_hci_sysdev (hci->master.dev.parent);for (i =0 ; i < rings->total; i++) {u32 offset =rhs_reg_read (RHn_OFFSET (i));drivers/i3c/master/mipi-i3c-hci/hci.h +2
-1@@ -184,6 +184,8 @@ void amd_set_resp_buf_thld(struct i3c_hci *hci);void i3c_hci_sync_irq_inactive (struct i3c_hci *hci);int i3c_hci_process_xfer (struct i3c_hci *hci,struct hci_xfer *xfer,int n); +struct device *i3c_hci_sysdev (struct device *dev); +#define DEFAULT_AUTOSUSPEND_DELAY_MS 1000int i3c_hci_rpm_suspend (struct device *dev); --2.53.0
PATCH v2 8/8 i3c: mipi-i3c-hci: Advertise IBI wakeup capability
In reply to Adrian HunterSet master->ibi_wakeup during probe when the associated system device advertises wakeup capability, allowing the I3C core to mark IBI-capable I3C devices as wakeup capable.
Tweak the comment for i3c_hci_sysdev() to mention the new usage.
---
Changes in V2:
None
drivers/i3c/master/mipi-i3c-hci/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/i3c/master/mipi-i3c-hci/core.c +6 -3
@@ -120,9 +120,9 @@ static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m)/* * Determine the device that does PM / DMA and has IOMMU setup done for it in -* case of enabled IOMMU (for use with the DMA API). -* Such device is either "mipi-i3c-hci" platform device (OF/ACPI enumeration) -* parent or grandparent (PCI enumeration). +* case of enabled IOMMU (for use with the DMA API). It is also used to check +* for wakeup capability. Such device is either "mipi-i3c-hci" platform device +* (OF/ACPI enumeration) parent or grandparent (PCI enumeration). */ struct device *i3c_hci_sysdev (struct device *dev) {
@@ -1176,6 +1176,9 @@ static int i3c_hci_probe(struct platform_device *pdev)if (hci->quirks &HCI_QUIRK_RPM_IBI_ALLOWED ) hci->master.rpm_ibi_allowed = true; +if (device_can_wakeup (i3c_hci_sysdev (&pdev->dev))) + hci->master.ibi_wakeup = true; +return i3c_master_register (&hci->master, &pdev->dev, &i3c_hci_ops, false); }
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH V2 8/8] i3c: mipi-i3c-hci: Advertise IBI wakeup capability
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 7 lines
Set
master->ibi_wakeupduring probe when the associated system device advertises wakeup capability, allowing the I3C core to mark IBI-capable I3C devices as wakeup capable.Tweak the comment for
i3c_hci_sysdev()to mention the new usage.Signed-off-by Adrian Hunter <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
Re: [PATCH V2 8/8] i3c: mipi-i3c-hci: Advertise IBI wakeup capability
In reply to Adrian HunterQuoted 8 lines · Adrian Hunter
Set
master->ibi_wakeupduring probe when the associated system device advertises wakeup capability, allowing the I3C core to mark IBI-capable I3C devices as wakeup capable.Tweak the comment for
i3c_hci_sysdev()to mention the new usage.Signed-off-by Adrian Hunter <[email protected]>---
Quoted 40 lines
Changes in V2:
None
drivers/i3c/master/mipi-i3c-hci/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)drivers/i3c/master/mipi-i3c-hci/core.c +6
-4@@ -120,9 +120,9 @@ static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m)/* * Determine the device that does PM / DMA and has IOMMU setup done for it in -* case of enabled IOMMU (for use with the DMA API). -* Such device is either "mipi-i3c-hci" platform device (OF/ACPI enumeration) -* parent or grandparent (PCI enumeration). +* case of enabled IOMMU (for use with the DMA API). It is also used to check +* for wakeup capability. Such device is either "mipi-i3c-hci" platform device +* (OF/ACPI enumeration) parent or grandparent (PCI enumeration). */ struct device *i3c_hci_sysdev (struct device *dev) {@@ -1176,6 +1176,9 @@ static int i3c_hci_probe(struct platform_device *pdev)if (hci->quirks &HCI_QUIRK_RPM_IBI_ALLOWED ) hci->master.rpm_ibi_allowed = true; +if (device_can_wakeup (i3c_hci_sysdev (&pdev->dev))) + hci->master.ibi_wakeup = true; +return i3c_master_register (&hci->master, &pdev->dev, &i3c_hci_ops, false); } --2.53.0