diff options
author | dzwdz | 2024-05-04 20:26:13 +0200 |
---|---|---|
committer | dzwdz | 2024-05-04 20:26:13 +0200 |
commit | 80839982e9983c6ccadbf57a44e60eeb0e535421 (patch) | |
tree | f342dffd1222f9ba8cbab0a95fa2afb0c9f56691 /src/kernel/arch/amd64/driver/rtl8139.c | |
parent | 8c7b8d9e4ec40c38c657851354fc74428f0df1ac (diff) |
kernel/rtl8139: prepare for /dev/eth/mac
Diffstat (limited to 'src/kernel/arch/amd64/driver/rtl8139.c')
-rw-r--r-- | src/kernel/arch/amd64/driver/rtl8139.c | 110 |
1 files changed, 69 insertions, 41 deletions
diff --git a/src/kernel/arch/amd64/driver/rtl8139.c b/src/kernel/arch/amd64/driver/rtl8139.c index 42b2abb..d1054a4 100644 --- a/src/kernel/arch/amd64/driver/rtl8139.c +++ b/src/kernel/arch/amd64/driver/rtl8139.c @@ -1,3 +1,4 @@ +#include <camellia/errno.h> #include <kernel/arch/amd64/driver/driver.h> #include <kernel/arch/amd64/driver/util.h> #include <kernel/arch/amd64/interrupts.h> @@ -16,18 +17,18 @@ static VfsReq *blocked_on = NULL; enum { - MAC = 0, - TXSTATUS0 = 0x10, - TXSTART0 = 0x20, - RBSTART = 0x30, - CMD = 0x37, - CAPR = 0x38, - CBR = 0x3A, - INTRMASK = 0x3C, - INTRSTATUS = 0x3E, - TCR = 0x40, - RCR = 0x44, - CONFIG1 = 0x52, + Mac = 0, + TxStatus0 = 0x10, + TxStart0 = 0x20, + RbStart = 0x30, + Cmd = 0x37, + Capr = 0x38, + Cbr = 0x3A, + IntrMask = 0x3C, + IntrStatus = 0x3E, + Tcr = 0x40, + Rcr = 0x44, + Config1 = 0x52, }; static uint16_t iobase; @@ -40,10 +41,11 @@ static size_t rxpos; #define txbuf_len 2048 static char txbuf[4][txbuf_len]; +static uint8_t mac[6]; static void rx_irq_enable(bool v) { uint16_t mask = 1; /* rx ok */ - port_out16(iobase + INTRMASK, v ? mask : 0); + port_out16(iobase + IntrMask, v ? mask : 0); } void rtl8139_init(uint32_t bdf) { @@ -57,15 +59,15 @@ void rtl8139_init(uint32_t bdf) { pcicfg_w32(bdf, PCICFG_CMD, cmd); - port_out8(iobase + CONFIG1, 0); /* power on */ + port_out8(iobase + Config1, 0); /* power on */ - port_out8(iobase + CMD, 0x10); /* software reset */ - while (port_in8(iobase + CMD) & 0x10); + port_out8(iobase + Cmd, 0x10); /* software reset */ + while (port_in8(iobase + Cmd) & 0x10); assert((long)(void*)rxbuf <= 0xFFFFFFFF); - port_out32(iobase + RBSTART, (long)(void*)rxbuf); + port_out32(iobase + RbStart, (long)(void*)rxbuf); - port_out32(iobase + TCR, 0); + port_out32(iobase + Tcr, 0); uint32_t rcr = 0; // rcr |= 1 << 0; /* accept all packets */ @@ -74,17 +76,22 @@ void rtl8139_init(uint32_t bdf) { rcr |= 1 << 3; /* accept broadcast */ rcr |= buflen_shift << 11; rcr |= 7 << 13; /* no rx threshold, copy whole packets */ - port_out32(iobase + RCR, rcr); + port_out32(iobase + Rcr, rcr); - port_out8(iobase + CMD, 0xC); /* enable RX TX */ + port_out8(iobase + Cmd, 0xC); /* enable RX TX */ rx_irq_enable(false); - vfs_root_register("/dev/eth", accept); + for (int i = 0; i < 6; i++) { + mac[i] = port_in8(iobase + Mac + i); + } + kprintf("%02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + vfs_root_register("/dev/eth/", accept); } static void rtl8139_irq(void) { - uint16_t status = port_in16(iobase + INTRSTATUS); + uint16_t status = port_in16(iobase + IntrStatus); if (!(status & 1)) { kprintf("bad rtl8139 status 0x%x\n", status); panic_unimplemented(); @@ -93,21 +100,21 @@ static void rtl8139_irq(void) { /* bit 0 of cmd - Rx Buffer Empty * not a do while() because sometimes the bit is empty on IRQ. no clue why. */ - while (!(port_in8(iobase + CMD) & 1)) { + while (!(port_in8(iobase + Cmd) & 1)) { if (!postqueue_pop(&blocked_on, accept)) { rx_irq_enable(false); break; } } - //kprintf("rxpos %x cbr %x\n", rxpos, port_in16(iobase + CBR)); - port_out16(iobase + INTRSTATUS, status); + //kprintf("rxpos %x cbr %x\n", rxpos, port_in16(iobase + Cbr)); + port_out16(iobase + IntrStatus, status); } static int try_rx(Proc *proc, void __user *dest, size_t dlen) { uint16_t flags, size; /* bit 0 - Rx Buffer Empty */ - if (port_in8(iobase + CMD) & 1) return WAIT; + if (port_in8(iobase + Cmd) & 1) return WAIT; /* https://github.com/qemu/qemu/blob/04ddcda6a/hw/net/rtl8139.c#L1169 */ /* https://www.cs.usfca.edu/~cruse/cs326f04/RTL8139D_DataSheet.pdf page 12 @@ -136,7 +143,7 @@ static int try_rx(Proc *proc, void __user *dest, size_t dlen) { rxpos = (rxpos + 3) & ~3; while (rxpos >= rxbuf_baselen) rxpos -= rxbuf_baselen; /* the device adds the 0x10 back, it's supposed to avoid overflow */ - port_out16(iobase + CAPR, rxpos - 0x10); + port_out16(iobase + Capr, rxpos - 0x10); return size; } @@ -146,7 +153,7 @@ static int try_tx(Proc *proc, const void __user *src, size_t slen) { if (slen > 0xFFF) return -1; if (slen > txbuf_len) return -1; - uint32_t status = port_in32(iobase + TXSTATUS0 + desc*4); + uint32_t status = port_in32(iobase + TxStatus0 + desc*4); if (!(status & (1<<13))) { /* can't (?) be caused (and thus, tested) on a vm */ kprintf("try_tx called with all descriptors full."); @@ -157,24 +164,40 @@ static int try_tx(Proc *proc, const void __user *src, size_t slen) { return -1; } assert((long)(void*)txbuf <= 0xFFFFFFFF); - port_out32(iobase + TXSTART0 + desc*4, (long)(void*)txbuf[desc]); - port_out32(iobase + TXSTATUS0 + desc*4, slen); + port_out32(iobase + TxStart0 + desc*4, (long)(void*)txbuf[desc]); + port_out32(iobase + TxStatus0 + desc*4, slen); desc = (desc + 1) & 3; return slen; } +enum { + HandleRoot, + HandleNet, +}; + static void accept(VfsReq *req) { + long ret; + long id = (long __force)req->id; + if (!req->caller) { vfsreq_finish_short(req, -1); return; } + switch (req->type) { - long ret; - case VFSOP_OPEN: - vfsreq_finish_short(req, req->input.len == 0 ? 0 : -1); - break; - case VFSOP_READ: + case VFSOP_OPEN: + if (reqpathcmp(req, "")) ret = HandleRoot; + else if (reqpathcmp(req, "net")) ret = HandleNet; + else ret = -ENOENT; + vfsreq_finish_short(req, ret); + break; + case VFSOP_READ: + if (id == HandleRoot) { + const char data[] = "net"; + ret = req_readcopy(req, data, sizeof data); + vfsreq_finish_short(req, ret); + } else if (id == HandleNet) { ret = try_rx(req->caller, req->output.buf, req->output.len); if (ret == WAIT) { postqueue_join(&blocked_on, req); @@ -182,13 +205,18 @@ static void accept(VfsReq *req) { } else { vfsreq_finish_short(req, ret); } - break; - case VFSOP_WRITE: + } else panic_invalid_state(); + break; + case VFSOP_WRITE: + if (id == HandleNet) { assert(!req->input.kern); vfsreq_finish_short(req, try_tx(req->caller, req->input.buf, req->input.len)); - break; - default: - vfsreq_finish_short(req, -1); - break; + } else { + vfsreq_finish_short(req, -ENOSYS); + } + break; + default: + vfsreq_finish_short(req, -1); + break; } } |