ref: e5fc0e1196e8b7531426053807120b186b4920e0
parent: 21637f1b26b398864fed2c874aa2e7f223cc2c77
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Feb 20 15:46:04 EST 2026
ether82563: fix transmission getting stuck When the tproc() encounters the transmit ring to be full, it sets the Txdw in the interrupt mask and uses (ctlr->im & Txdw) == 0 as the wakeup condition. The problem is that the interrupt handler calls wakeup() *before* clearing the Txdw bit in ctlr->im, leading to the following race: 1) cpuX: tproc() sets ctlr->im |= Txdw and writes interrupt mask register 2) cpuY: interrupt handler runs and calls wakeup(&ctlr->trendez) 3) cpuX: tproc() calls sleep, notrim() returns 0 as Txdw is still set 4) cpuY: interrupt handler clears Txdw in ctlr->im 5) cpuX: sleep waits forever, transmission stalled This patch clears Txdw bit in ctlr->im *before* calling wakeup, and also adds 5 millisecond timeout using tsleep().
--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -890,7 +890,7 @@
if(n == i82563cleanup(ctlr)){ctlr->txdw++;
i82563im(ctlr, Txdw);
- sleep(&ctlr->trendez, notrim, ctlr);
+ tsleep(&ctlr->trendez, notrim, ctlr, 5);
continue;
}
bp = qbread(edev->oq, 100000);
@@ -1462,6 +1462,7 @@
}
if(icr & Txdw){im &= ~Txdw;
+ ctlr->im &= ~Txdw;
ctlr->tintr++;
wakeup(&ctlr->trendez);
}
--
⑨