[PATCH v16 6/8] i3c: hub: Add support for the I3C interface in the I3C hub

Lakshay Piplani lakshay.piplani at nxp.com
Thu Aug 27 00:07:20 PDT 2026


Hi Frank,

Thanks for the review.

> > > +/**
> > > + * i3c_hub_do_daa() - Perform DAA via hub port
> > > + * @hub: Hub instance
> > > + * @controller: Virtual controller for a hub port
> > > + *
> > > + * Enables the port connection, performs DAA on the parent
> > > +controller,
> > > + * then disables the connection.
> > > + */
> > > +static int i3c_hub_do_daa(struct i3c_hub *hub,
> > > +                   struct i3c_master_controller *controller) {
> > > + struct i3c_master_controller *parent;
> > > + int ret;
> > > +
> > > + if (!hub || !hub->hub_dev)
> > > +         return -ENODEV;
> > > +
> > > + parent = i3c_dev_get_master(hub->hub_dev->desc);
> > > + if (!parent)
> > > +         return -ENODEV;
> > > +
> > > + /*
> > > +  * Lock order: hub routing mutex before the parent bus lock (taken here
> > > +  * inside i3c_master_do_daa()). The depth-keyed lockdep classes above
> > > +  * keep this nesting acyclic when the parent is itself a hub.
> > > +  */
> > > + mutex_lock(&hub->lock);
> > > + i3c_hub_enable_port(controller);
> > > +
> > > + /*
> > > +  * Downstream devices reachable through hub target-port routes share
> the
> > > +  * parent controller's I3C address space. The hub gates access to a
> > > +  * target-port network, but it does not create an independent dynamic
> > > +  * address domain per virtual bus.
> > > +  *
> > > +  * Run DAA on the parent controller so dynamic addresses remain
> unique
> > > +  * across all downstream devices, even when they are behind different
> > > +  * target ports.
> > > +  */
> > > + ret = i3c_master_do_daa(parent);
> >
> > [Severity: High]
> > Does delegating DAA to the physical parent controller break
> > reachability for downstream devices?
> >
> > When devices respond to ENTDAA, they are instantiated on the parent
> > bus rather than the virtual bus. If drivers subsequently initiate
> > transfers, they use the parent controller's transfer operations
> > directly, bypassing the hub's i3c_hub_master_priv_xfers(). As a
> > result, the hub target port is never enabled during the transfer,
> > leaving these downstream devices permanently unreachable.
>
> where reorder port, is it true?
>


No, P3H2x4x never re-orders or re-switches ports. All I3C ports are connected once at probe and stay connected (always_enable makes enable/disable_port no-ops), so a prior DAA never goes stale.
DAA runs on the parent on purpose: all downstream devices share the parent's single address domain, so addresses stay unique across ports.
DT addresses are reserved for the parent-bus lifetime and aren't freed on a port toggle, so enable/disable only gates reachability, never reallocates. I'll add a comment.
(enable/disable_port are kept as part of the generic hub op set and would be the hook for optional sysfs port control later - out of scope here.)

> >
> > > + i3c_hub_disable_port(controller);
> > > + mutex_unlock(&hub->lock);
> > > +
> > > + return ret;
> > > +}
> > [ ... ]
> > > +static int i3c_hub_send_ccc_cmd(struct i3c_hub *hub,
> > > +                         struct i3c_master_controller *controller,
> > > +                         struct i3c_ccc_cmd *cmd)
> > > +{
> > > + struct i3c_master_controller *parent;
> > > + int ret;
> > > +
> > > + if (!hub || !hub->hub_dev)
> > > +         return -ENODEV;
> > > +
> > > + parent = i3c_dev_get_master(hub->hub_dev->desc);
> > > + if (!parent)
> > > +         return -ENODEV;
> > > +
> > > + mutex_lock(&hub->lock);
> > > + i3c_hub_enable_port(controller);
> > > + ret = i3c_master_send_ccc_cmd(parent, cmd);
> >
> > [Severity: Medium]
> > Can forwarding unfiltered broadcast CCCs to the parent controller
> > break virtual bus isolation?
> >
> > If a driver on a specific virtual bus issues broadcast commands (such
> > as SETMRL, SETMWL, or ENEC), this forwards them to the parent
> > controller which broadcasts them globally. This will unintentionally
> > alter the configuration or event state of all peer devices on the
> > parent bus and other open target ports.
>
> Look like system design limiation, add comments here incase it happen.
>

Agreed - it's a system limitation, I'll note that a broadcast CCC on a virtual bus has parent-bus scope. RSTDAA stays blocked, as forwarding it would reset the hub's own address.

> >
> > > + i3c_hub_disable_port(controller);
> > > + mutex_unlock(&hub->lock);
> > > +
> > > + return ret;
> > > +}
> > [ ... ]
> > > +int i3c_hub_reserve_parent_addrslots_from_dt(struct i3c_hub_controller
> *hubc,
> > > +                                      struct device_node *node) {
> > > + struct i3c_master_controller *parent = hubc->parent;
> > > + enum i3c_addr_slot_status status;
> > > + u32 assigned_addr;
> > > + u32 reg[3];
> > > + int ret;
> > > +
> > > + if (!parent || !node)
> > > +         return -ENODEV;
> > > +
> > > + for_each_available_child_of_node_scoped(node, child) {
> > > +         /*
> > > +          * Only consider addressable bus nodes: a valid "reg" is
> > > +          * required to describe a device, but its static-address value
> > > +          * does not affect the reservation below.
> > > +          */
> > > +         ret = of_property_read_variable_u32_array(child, "reg", reg, 1,
> 3);
> > > +         if (ret < 0)
> > > +                 continue;
> > > +
> > > +         ret = of_property_read_u32(child, "assigned-address",
> &assigned_addr);
> > > +         if (ret)
> > > +                 continue;
> > > +
> > > +         /* Skip nodes without a usable dynamic address. */
> > > +         if (!assigned_addr || assigned_addr > I3C_MAX_ADDR)
> > > +                 continue;
> > > +
> > > +         i3c_bus_maintenance_lock(&parent->bus);
> > > +         status = i3c_bus_get_addr_slot_status(&parent->bus,
> > > +                                               assigned_addr);
> > > +         if (status == I3C_ADDR_SLOT_FREE)
> > > +                 i3c_bus_set_addr_slot_status(&parent->bus,
> > > +                                              assigned_addr,
> > > +                                              I3C_ADDR_SLOT_I3C_DEV);
> >
> > [Severity: High]
> > Does this code permanently leak parent bus address slots when the hub
> > driver is removed?
> >
> > The address slots in the parent bus state are set to I3C_ADDR_SLOT_I3C_DEV.
> > However, there appears to be no corresponding teardown mechanism
> > provided to revert these slots to I3C_ADDR_SLOT_FREE when the virtual
> > controllers are destroyed or the hub driver is unbound. This leak can
> > eventually exhaust the address space and cause failures for subsequent
> devices.
>
> I suppose if hub have hotplug later, we have to reserver all static/assigned
> address. Can you add comments here.

Agreed - I'll add a comment. The reserved addresses come from the fixed DT topology and are held for the parent-bus lifetime. If the hub is removed and comes back, it re-reads the same DT and reserves the same addresses again, so nothing is used up over time.

>
> Thank you for great work, fixed the most problem.
>
> Frank

Thanks, Frank. I appreciate your reviews and feedback throughout this series.

Regards
Lakshay

NXP Confidential



More information about the linux-i3c mailing list