[PATCH 4/8] i3c: master: Ensure Hot-Join operations are stopped on shutdown

Frank Li Frank.li at nxp.com
Wed May 13 12:04:35 PDT 2026


On Wed, May 13, 2026 at 08:31:56AM +0300, Adrian Hunter wrote:
> On 12/05/2026 19:27, Frank Li wrote:
> > On Tue, May 12, 2026 at 03:17:28PM +0300, Adrian Hunter wrote:
> >> System shutdown invokes each device's bus shutdown callback to quiesce
> >> hardware, but the I3C bus type does not currently implement one.  As a
> >> result, on shutdown the controller's Hot-Join work and any in-flight
> >> i3c_master_do_daa() can keep running (or be newly triggered) while the
> >> rest of the system is being torn down.
> >>
> >> A similar window exists at i3c_master_unregister() time: cancel_work_sync()
> >> on hj_work prevents queued work from completing, but does not stop a
> >> fresh Hot-Join IBI from re-queueing the worker, nor a concurrent sysfs
> >> writer from toggling Hot-Join via i3c_set_hotjoin().
> >>
> >> Introduce a single "shutting down" gate in the I3C core, set under the
> >> bus maintenance lock so it is observed by any in-progress DAA path
> >> before pending work is cancelled.  Install an i3c_bus_type shutdown
> >> callback that engages this gate for master devices during system
> >> shutdown, and use the same gate in i3c_master_unregister() so both
> >> paths get identical guarantees.
> >>
> >> Once the gate is engaged, the Hot-Join worker, i3c_master_do_daa_ext()
> >> and i3c_set_hotjoin() all bail out cleanly, so Hot-Join IBIs that race
> >> with shutdown become no-ops, direct DAA callers see -ENODEV, and sysfs
> >> writers can no longer re-enable Hot-Join through ops->enable_hotjoin()
> >> while the controller is going away.
> >>
> >> No functional change for the steady-state runtime path; the new checks
> >> only take effect once the controller has been marked as shutting down.
> >>
> >> Signed-off-by: Adrian Hunter <adrian.hunter at intel.com>
> >> ---
> >>  drivers/i3c/master.c       | 52 +++++++++++++++++++++++++++-----------
> >>  include/linux/i3c/master.h |  2 ++
> >>  2 files changed, 39 insertions(+), 15 deletions(-)
> >>
> >> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> >> index cdb5cb2aa65d..a59c4b744b36 100644
> >> --- a/drivers/i3c/master.c
> >> +++ b/drivers/i3c/master.c
> >> @@ -368,14 +368,6 @@ static void i3c_device_remove(struct device *dev)
> >>  		driver->remove(i3cdev);
> >>  }
> >>
> >> -const struct bus_type i3c_bus_type = {
> >> -	.name = "i3c",
> >> -	.match = i3c_device_match,
> >> -	.probe = i3c_device_probe,
> >> -	.remove = i3c_device_remove,
> >> -};
> >> -EXPORT_SYMBOL_GPL(i3c_bus_type);
> >> -
> >
> > why need move this tunk?
>
> To avoid forward declarations.
>
> i3c_device_shutdown() references i3c_masterdev_type so it needs to be
> after i3c_masterdev_type definition.  i3c_device_shutdown() is being
> added to struct i3c_bus_type, so i3c_bus_type needs to be after
> i3c_device_shutdown().

Okay
Reviewed-by: Frank Li <Frank.Li at nxp.com>
>
> >
> >>  static enum i3c_addr_slot_status
> >>  i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask)
> >>  {
> >> @@ -637,7 +629,8 @@ static void i3c_master_hj_work_fn(struct work_struct *work)
> >>  {
> >>  	struct i3c_master_controller *master = container_of(work, typeof(*master), hj_work);
> >>
> >> -	i3c_master_do_daa(master);
> >> +	if (!master->shutting_down)
> >> +		i3c_master_do_daa(master);
> >>  }
> >>
> >>  static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
> >> @@ -658,7 +651,9 @@ static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
> >>
> >>  	i3c_bus_maintenance_lock(&master->bus);
> >
> > later, consider change to use cleanup, so
> > 	if (master->shutting_down)
> > 		return -ENODEV
> >
> > 	and avoid use else if branch.
> >
> > but this change is okay for now.
> >
> > Frank
>



More information about the linux-i3c mailing list