git: 9front

Download patch

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);
 		}
--