diff options
author | Anton Kling <anton@kling.gg> | 2023-11-22 18:34:00 +0100 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-11-22 18:34:00 +0100 |
commit | b3866b0442f55b97833981a99c601f2143d10315 (patch) | |
tree | 2b0ae716da1e0d22311ecb119cc8d5cb2bbed822 /kernel/drivers/rtl8139.c | |
parent | 615fb35efa8b13b7109e6974f86b295238163ebc (diff) |
Kernel/RTL8139/Networking fixes
This is just a commit containing multiple fixes since I am too lazy to
split them up.
Diffstat (limited to 'kernel/drivers/rtl8139.c')
-rw-r--r-- | kernel/drivers/rtl8139.c | 95 |
1 files changed, 56 insertions, 39 deletions
diff --git a/kernel/drivers/rtl8139.c b/kernel/drivers/rtl8139.c index 0ed562e..4b53ef4 100644 --- a/kernel/drivers/rtl8139.c +++ b/kernel/drivers/rtl8139.c @@ -11,6 +11,8 @@ #define CMD 0x37 #define IMR 0x3C +#define RTL8139_RXBUFFER_SIZE (8192 + 16) + #define TSD0 0x10 // transmit status #define TSAD0 0x20 // transmit start address @@ -18,6 +20,7 @@ struct PCI_DEVICE rtl8139; u8 *device_buffer; u8 *send_buffers[4]; +int send_buffers_loop = 0; struct _INT_PACKET_HEADER { u8 ROK : 1; @@ -39,49 +42,63 @@ struct PACKET_HEADER { }; }; -u16 current_packet_read = 0; +u32 current_packet_read = 0; void handle_packet(void) { assert(sizeof(struct _INT_PACKET_HEADER) == sizeof(u16)); - u16 *buf = (u16 *)(device_buffer + current_packet_read); - struct PACKET_HEADER packet_header; - packet_header.raw = *buf; - assert(packet_header.data.ROK); - u16 packet_length = *(buf + 1); - - u8 packet_buffer[8192 + 16]; - if (current_packet_read + packet_length >= 8192 + 16) { - u32 first_run = ((u8 *)buf + (8192 + 16)) - device_buffer; - memcpy(packet_buffer, buf, first_run); - memcpy(packet_buffer, device_buffer, packet_length - first_run); - } else { - memcpy(packet_buffer, buf, packet_length); + for (int i = 0; 0 == (inb(rtl8139.gen.base_mem_io + 0x37) & 1); i++) { + u16 *buf = (u16 *)(device_buffer + current_packet_read); + struct PACKET_HEADER packet_header; + packet_header.raw = *buf; + if (packet_header.data.FAE) { + return; + } + if (packet_header.data.CRC) { + return; + } + if (!packet_header.data.ROK) { + return; + } + u16 packet_length = *(buf + 1); + assert(packet_length <= 2048); + + u8 packet_buffer[RTL8139_RXBUFFER_SIZE]; + if (current_packet_read + packet_length >= RTL8139_RXBUFFER_SIZE) { + u32 end = RTL8139_RXBUFFER_SIZE - current_packet_read; + memcpy(packet_buffer, buf, end); + u32 rest = packet_length - end; + memcpy(packet_buffer + end, device_buffer, rest); + } else { + memcpy(packet_buffer, buf, packet_length); + } + + // I have no documentation backing this implementation of updating + // the CBR. It is just a (somewhat)uneducated guess. But it does + // seem to work. + u32 old = current_packet_read; + current_packet_read = (current_packet_read + packet_length + 4 + 3) & (~3); + current_packet_read %= RTL8139_RXBUFFER_SIZE; + outw(rtl8139.gen.base_mem_io + 0x38, current_packet_read - 0x10); + current_packet_read = inw(rtl8139.gen.base_mem_io + 0x3A); + outw(rtl8139.gen.base_mem_io + 0x38, current_packet_read - 0x10); + + assert(current_packet_read != old); + + handle_ethernet((u8 *)packet_buffer + 4, packet_length); } - - handle_ethernet((u8 *)packet_buffer + 4, packet_length); - - // Thanks to exscape - // https://github.com/exscape/exscapeOS/blob/master/src/kernel/net/rtl8139.c - // and the programmers guide - // https://www.cs.usfca.edu/~cruse/cs326f04/RTL8139_ProgrammersGuide.pdf I - // have no clue what this calculation, I can't find anything possibly relating - // to this in the manual, but it does work I guess. - current_packet_read = (current_packet_read + packet_length + 4 + 3) & (~3); - current_packet_read %= 8192 + 16; - outw(rtl8139.gen.base_mem_io + 0x38, current_packet_read - 0x10); } __attribute__((interrupt)) void rtl8139_handler(void *regs) { (void)regs; u16 status = inw(rtl8139.gen.base_mem_io + 0x3e); - outw(rtl8139.gen.base_mem_io + 0x3E, 0x5); if (status & (1 << 2)) { } if (status & (1 << 0)) { handle_packet(); } + outw(rtl8139.gen.base_mem_io + 0x3E, 0x5); EOI(0xB); } @@ -92,15 +109,14 @@ int rtl8139_send_data(u8 *data, u16 data_size) { // buffer if (data_size > 0x1000) return 0; - static int loop = 0; - if (loop > 3) { - loop = 0; + if (send_buffers_loop > 3) { + send_buffers_loop = 0; } - memcpy(send_buffers[loop], data, data_size); - outl(device->gen.base_mem_io + 0x20 + loop * 4, - (u32)virtual_to_physical(send_buffers[loop], NULL)); - outl(device->gen.base_mem_io + 0x10 + loop * 4, data_size); - loop += 1; + memcpy(send_buffers[send_buffers_loop], data, data_size); + outl(device->gen.base_mem_io + 0x20 + send_buffers_loop * 4, + (u32)virtual_to_physical(send_buffers[send_buffers_loop], NULL)); + outl(device->gen.base_mem_io + 0x10 + send_buffers_loop * 4, data_size); + send_buffers_loop += 1; return 1; } @@ -150,14 +166,15 @@ void rtl8139_init(void) { outb(base_address + CMD, 0x10); for (; 0 != (inb(base_address + CMD) & 0x10);) ; - device_buffer = ksbrk(8192 + 16); - memset(device_buffer, 0, 8192 + 16); + device_buffer = ksbrk(RTL8139_RXBUFFER_SIZE); + memset(device_buffer, 0, RTL8139_RXBUFFER_SIZE); // Setupt the recieve buffer u32 rx_buffer = (u32)virtual_to_physical(device_buffer, NULL); outl(base_address + RBSTART, rx_buffer); // Set IMR + ISR - outw(base_address + IMR, (1 << 2) | (1 << 3) | (1 << 0)); + // outw(base_address + IMR, (1 << 2) | (1 << 3) | (1 << 0)); + outw(base_address + IMR, (1 << 2) | (1 << 0)); // Set transmit and reciever enable outb(base_address + 0x37, (1 << 2) | (1 << 3)); @@ -166,7 +183,7 @@ void rtl8139_init(void) { outl(base_address + 0x44, 0xf); // 0xf is AB+AM+APM+AAP - install_handler(rtl8139_handler, INT_32_INTERRUPT_GATE(0x0), + install_handler(rtl8139_handler, INT_32_INTERRUPT_GATE(0x3), 0x20 + interrupt_line); // ksbrk() seems to have the magical ability of disabling interrupts? |