From: Jaidev Shastri <[email protected]> dpaa_eth, caam and the portal drivers poll qman_is_probed(), bman_is_probed(), qman_portals_probed() and bman_portals_probed() before they touch the state the probe functions set up: qman_ip_rev, the CCSR and portal register maps, the FQD and PFDR bases, affine_portals and the pool allocators.
Each flag is set with a plain store at the end of its probe function and read with a plain load in the exported accessor. The stores that build the state are not ordered before the store to the flag, and the consumer's load of the flag is not ordered before its loads of the state. A consumer probing on another CPU can see the flag set and then read state that is still stale or zeroed, and program the hardware with it. Set the flags with smp_store_release() and read them with smp_load_acquire(). The error paths storing -1 keep their plain stores: a consumer that sees -1 fails its own probe without touching the state. Found with MBCheck, a static herd7-based memory consistency checker. Signed-off-by: Jaidev Shastri <[email protected]> --- drivers/soc/fsl/qbman/bman_ccsr.c | 6 ++++-- drivers/soc/fsl/qbman/bman_portal.c | 6 ++++-- drivers/soc/fsl/qbman/qman_ccsr.c | 11 +++++++++-- drivers/soc/fsl/qbman/qman_portal.c | 6 ++++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c index b0f26f6f7..c5be35aba 100644 --- a/drivers/soc/fsl/qbman/bman_ccsr.c +++ b/drivers/soc/fsl/qbman/bman_ccsr.c @@ -180,7 +180,8 @@ static irqreturn_t bman_isr(int irq, void *ptr) int bman_is_probed(void) { - return __bman_probed; + /* Pairs with smp_store_release() in fsl_bman_probe(). */ + return smp_load_acquire(&__bman_probed); } EXPORT_SYMBOL_GPL(bman_is_probed); @@ -279,7 +280,8 @@ static int fsl_bman_probe(struct platform_device *pdev) return ret; } - __bman_probed = 1; + /* Order bm_ccsr_start, bman_ip_rev and the pool allocator before the flag. */ + smp_store_release(&__bman_probed, 1); return 0; }; diff --git a/drivers/soc/fsl/qbman/bman_portal.c b/drivers/soc/fsl/qbman/bman_portal.c index 4d7b9caee..056fe3fbb 100644 --- a/drivers/soc/fsl/qbman/bman_portal.c +++ b/drivers/soc/fsl/qbman/bman_portal.c @@ -90,7 +90,8 @@ static int bman_online_cpu(unsigned int cpu) int bman_portals_probed(void) { - return __bman_portals_probed; + /* Pairs with smp_store_release() in bman_portal_probe(). */ + return smp_load_acquire(&__bman_portals_probed); } EXPORT_SYMBOL_GPL(bman_portals_probed); @@ -157,7 +158,8 @@ static int bman_portal_probe(struct platform_device *pdev) spin_lock(&bman_lock); cpu = cpumask_first_zero(&portal_cpus); if (cpu >= nr_cpu_ids) { - __bman_portals_probed = 1; + /* All CPU-bound portals are initialised and in affine_bportals. */ + smp_store_release(&__bman_portals_probed, 1); /* unassigned portal, skip init */ spin_unlock(&bman_lock); goto check_cleanup; diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c index aa5348f49..b46cfb964 100644 --- a/drivers/soc/fsl/qbman/qman_ccsr.c +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -711,7 +711,8 @@ static int qman_resource_init(struct device *dev) int qman_is_probed(void) { - return __qman_probed; + /* Pairs with smp_store_release() in fsl_qman_probe(). */ + return smp_load_acquire(&__qman_probed); } EXPORT_SYMBOL_GPL(qman_is_probed); @@ -864,7 +865,13 @@ static int fsl_qman_probe(struct platform_device *pdev) if (ret) return ret; - __qman_probed = 1; + /* + * Publish the flag only after every store made above (qman_ip_rev, + * qm_ccsr_start, the FQD/PFDR bases, the work queue) is visible to + * the consumers that poll qman_is_probed() and then call into + * qman_set_sdest(), qman_liodn_fixup(), qman_alloc_*(). + */ + smp_store_release(&__qman_probed, 1); return 0; } diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index 456ef5d5c..181c0f373 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -175,7 +175,8 @@ static int qman_online_cpu(unsigned int cpu) int qman_portals_probed(void) { - return __qman_portals_probed; + /* Pairs with smp_store_release() in qman_portal_probe(). */ + return smp_load_acquire(&__qman_portals_probed); } EXPORT_SYMBOL_GPL(qman_portals_probed); @@ -251,7 +252,8 @@ static int qman_portal_probe(struct platform_device *pdev) spin_lock(&qman_lock); cpu = cpumask_first_zero(&portal_cpus); if (cpu >= nr_cpu_ids) { - __qman_portals_probed = 1; + /* All CPU-bound portals are initialised and in affine_portals. */ + smp_store_release(&__qman_portals_probed, 1); /* unassigned portal, skip init */ spin_unlock(&qman_lock); goto check_cleanup; --- base-commit: 93f51579e7df248780214094418f205253383cc5 change-id: 20260921-mb-qbman-84f56ef0f84c Best regards, -- Jaidev Shastri <[email protected]>
