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]>



Reply via email to