mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 04:23:03 +02:00
net: mana: Clear RDMA teardown and suspend state in mana_rdma_probe()
mana_rdma_remove() sets gd->rdma_teardown to stop
mana_rdma_service_handle() from acting on servicing events, but nothing
ever clears it. A hardware service reset (GDMA_EQE_HWC_RESET_REQUEST)
goes through mana_gd_suspend() -> mana_rdma_remove() and mana_gd_resume()
-> mana_rdma_probe(), so from the first reset onwards every
GDMA_EQE_HWC_SOC_SERVICE event returns early and RDMA suspend/resume
servicing is silently dropped for the life of the device.
gd->is_suspended has the same problem: it is set when servicing removes
the adev and is cleared only by a matching resume. A reset while RDMA is
suspended re-adds the adev but leaves is_suspended set, so a later resume
event calls add_adev() on top of a live gd->adev and leaks it. This is
currently masked by the rdma_teardown bug.
Clear both in mana_rdma_probe(). On the reset path mana_rdma_remove()
has closed the gate and drained the service workqueue, so clear
is_suspended first and re-open the gate with smp_store_release(), paired
with smp_load_acquire() in the handler, so the handler cannot observe an
open gate with a stale is_suspended. On the initial probe path the gate
was never closed and both flags are already clear.
This does not order gd->adev, which add_adev() publishes afterwards. A
servicing event arriving in that window is still dropped, as it is in
mainline today on the initial probe path; closing it needs probe and the
handler to be serialized and is left to a separate change.
Fixes: 505cc26bca ("net: mana: Add support for auxiliary device servicing events")
Signed-off-by: Long Li <longli@microsoft.com>
Link: https://patch.msgid.link/20260902175153.3410560-1-longli@microsoft.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
1b8e56030d
commit
f6d61fe4c1
|
|
@ -3987,7 +3987,8 @@ static void mana_rdma_service_handle(struct work_struct *work)
|
|||
struct device *dev = gd->gdma_context->dev;
|
||||
int ret;
|
||||
|
||||
if (READ_ONCE(gd->rdma_teardown))
|
||||
/* Pairs with the smp_store_release() in mana_rdma_probe(). */
|
||||
if (smp_load_acquire(&gd->rdma_teardown))
|
||||
goto out;
|
||||
|
||||
switch (serv_work->event) {
|
||||
|
|
@ -4283,6 +4284,21 @@ int mana_rdma_probe(struct gdma_dev *gd)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/* Clear the state left by a previous mana_rdma_remove() so servicing
|
||||
* events are handled again after a reset cycle.
|
||||
*/
|
||||
gd->is_suspended = false;
|
||||
|
||||
/* Publish is_suspended before re-opening the gate, so the handler
|
||||
* cannot observe an open gate with a stale is_suspended. Pairs
|
||||
* with the smp_load_acquire() in mana_rdma_service_handle(). This
|
||||
* matters on the reset path, where mana_rdma_remove() closed the
|
||||
* gate and drained the workqueue; on the initial probe path the
|
||||
* gate was never closed and both flags are already clear. It does
|
||||
* not order gd->adev, which add_adev() publishes below.
|
||||
*/
|
||||
smp_store_release(&gd->rdma_teardown, false);
|
||||
|
||||
err = add_adev(gd, "rdma");
|
||||
if (err)
|
||||
mana_gd_deregister_device(gd);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user