rtl8139: let go of the device when asked

The kernel's rtl8139 driver had no release hook, so /dev/pci refused
every request for the card ("the kernel would not release it") and a
hosted 8139too could never run on a machine where this driver probed
first.

release() follows e1000_release(): silence the chip before unhooking the
interrupt, reset it and clear bus mastering so it stops writing into its
buffers, take the interface out of the stack, then give the DMA buffers
back.

Tested in QEMU: ldlsd takes the card from the kernel, 8139too probes it,
DHCP binds ldls0, and ping 10.9.0.2 gets 3 of 3 replies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HH7xukt4aaiGj1nQEAoQf1
This commit is contained in:
Nexoniarz 2026-10-22 09:23:34 +02:00
commit f1798e7443

View file

@ -370,6 +370,68 @@ rtl8139_probe(struct pci_dev *d)
return 0; return 0;
} }
// Let go of the device, so another driver can have it.
//
// Without this the kernel's answer to "may I have the 8139" was always no, and
// a hosted driver for it could never run on a machine where this one had
// probed first -- which is every machine with one:
//
// found 10ec:8139 at 00:04.0, held by rtl8139
// the kernel would not release it
//
// The order is the one e1000_release() follows and for the same reasons. The
// chip is silenced *before* the handler goes, because a level-triggered line
// left asserted with nobody to clear it is an interrupt storm. Then it is
// reset, which stops the receiver writing into a buffer that is about to be
// freed, and bus mastering is cleared so that nothing it still has queued can
// reach memory. Only then are the buffers given back: the arena will hand them
// to the next driver, and a chip still pointed at them would be writing frames
// into somebody else's descriptors.
static int
rtl8139_release(struct pci_dev *d)
{
struct rtl8139 *r = 0;
for (int i = 0; i < RTL8139_MAX_NICS; i++)
if (nics[i].pdev == d) { r = &nics[i]; break; }
if (!r || !r->ready)
return 0; // never came up, or already let go
acquire(&r->lock);
r->ready = 0; // transmit and receive refuse from here on
wr16(r, R_IMR, 0); // no more interrupts from it
wr16(r, R_ISR, 0xFFFF); // and none left pending
wr8(r, R_CR, 0); // receiver and transmitter off
release(&r->lock);
if (d->irq != 0xFF && d->irq < 24)
irq_unregister(d->irq, rtl8139_intr, r);
// Reset, and wait for it, so the chip has truly stopped before its buffers
// are reused. The reset bit clears itself when the chip is done.
wr8(r, R_CR, CR_RST);
for (int i = 0; i < 10000 && (rd8(r, R_CR) & CR_RST); i++)
microdelay(10);
pci_disable(d, PCI_CMD_BUS_MASTER);
// Out of the stack, for the reason e1000_release() spells out: an interface
// left behind keeps its address and its route, and the stack goes on sending
// into a driver that now refuses every frame.
if (r->ndev)
net_detach(r->ndev);
dma_free(r->rxbuf, RXBUF_TOTAL);
dma_free(r->txbuf, NTX * TXBUF);
r->rxbuf = r->txbuf = 0;
r->tx_slot = 0;
r->tx_packets = 0;
r->rx_packets = 0;
cprintf("rtl8139: released; the interface is down\n");
return 0;
}
static void static void
rtl8139_attached(struct pci_dev *d, struct device *dev) rtl8139_attached(struct pci_dev *d, struct device *dev)
{ {
@ -400,4 +462,5 @@ const struct pci_driver rtl8139_driver = {
.ops = &rtl8139_netdev_ops, .ops = &rtl8139_netdev_ops,
.probe = rtl8139_probe, .probe = rtl8139_probe,
.attached = rtl8139_attached, .attached = rtl8139_attached,
.release = rtl8139_release,
}; };