From: Jaidev Shastri <[email protected]> dpaa2_io_create() adds the new object to dpio_list and dpio_by_cpu[] under dpio_list_lock, but service_select_by_cpu() reads dpio_by_cpu[] without the lock on behalf of dpaa2_io_service_select() and dpaa2_io_service_register().
obj->dev is assigned after the lock is dropped, so a reader can pick the object up and pass a NULL supplier to device_link_add(), which fails with -EINVAL and fails the consumer's probe. The publication is a plain store, so a reader that does not take the lock is also not ordered against the stores that set obj->swp, the notification list and the object's spinlocks. dpaa2-eth probes from the deferred probe worker and retries whenever another device binds, so it runs while the remaining DPIO objects are still being created on multi-core LS2 and LX2 parts. Finish the object before publishing it and store dpio_by_cpu[] with smp_store_release(), paired with smp_load_acquire() in service_select_by_cpu(). service_select() takes the lock and is unchanged. Found with MBCheck, a static herd7-based memory consistency checker. Signed-off-by: Jaidev Shastri <[email protected]> --- drivers/soc/fsl/dpio/dpio-service.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 317ca50b0..2dbd14aed 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -70,8 +70,12 @@ static inline struct dpaa2_io *service_select_by_cpu(struct dpaa2_io *d, if (cpu < 0) cpu = raw_smp_processor_id(); - /* If a specific cpu was requested, pick it up immediately */ - return dpio_by_cpu[cpu]; + /* + * If a specific cpu was requested, pick it up immediately. Pairs with + * the smp_store_release() in dpaa2_io_create(): the object is only + * used once every field written before the publication is visible. + */ + return smp_load_acquire(&dpio_by_cpu[cpu]); } static inline struct dpaa2_io *service_select(struct dpaa2_io *d) @@ -177,12 +181,6 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc, if (obj->dpio_desc.receives_notifications) qbman_swp_push_set(obj->swp, 0, 1); - spin_lock(&dpio_list_lock); - list_add_tail(&obj->node, &dpio_list); - if (desc->cpu >= 0 && !dpio_by_cpu[desc->cpu]) - dpio_by_cpu[desc->cpu] = obj; - spin_unlock(&dpio_list_lock); - obj->dev = dev; memset(&obj->rx_dim, 0, sizeof(obj->rx_dim)); @@ -191,6 +189,19 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc, obj->bytes = 0; obj->frames = 0; + /* + * dpaa2_io_service_select() reads dpio_by_cpu[] without taking + * dpio_list_lock, so the object must be complete before it is + * published and the publication needs release semantics. + */ + spin_lock(&dpio_list_lock); + list_add_tail(&obj->node, &dpio_list); + if (desc->cpu >= 0 && !dpio_by_cpu[desc->cpu]) { + /* Pairs with the smp_load_acquire() in service_select_by_cpu(). */ + smp_store_release(&dpio_by_cpu[desc->cpu], obj); + } + spin_unlock(&dpio_list_lock); + return obj; } --- base-commit: 93f51579e7df248780214094418f205253383cc5 change-id: 20260921-mb-dpio-f3f7dcf0ef41 Best regards, -- Jaidev Shastri <[email protected]>
