rtl8139.c (12702B)
1 /* RTL8139 Network Card Driver */ 2 #include "rtl8139.h" 3 #include "terminal.h" 4 #include <stdint.h> 5 #include <string.h> 6 #include <lauxlib.h> 7 8 /* RTL8139 PCI Configuration */ 9 #define RTL8139_VENDOR_ID 0x10EC 10 #define RTL8139_DEVICE_ID 0x8139 11 12 /* RTL8139 Register Offsets */ 13 #define RTL8139_MAC0 0x00 /* MAC address */ 14 #define RTL8139_MAR0 0x08 /* Multicast filter */ 15 #define RTL8139_TXSTATUS0 0x10 /* Transmit status (4 TXDs) */ 16 #define RTL8139_TXADDR0 0x20 /* Transmit address (4 TXDs) */ 17 #define RTL8139_RXBUF 0x30 /* Receive buffer start address */ 18 #define RTL8139_RXEARLYCNT 0x34 /* Early RX byte count */ 19 #define RTL8139_RXEARLYSTATUS 0x36 /* Early RX status */ 20 #define RTL8139_CHIPCMD 0x37 /* Command register */ 21 #define RTL8139_RXBUFTAIL 0x38 /* Current address of packet read */ 22 #define RTL8139_RXBUFHEAD 0x3A /* Current buffer address */ 23 #define RTL8139_INTRMASK 0x3C /* Interrupt mask */ 24 #define RTL8139_INTRSTATUS 0x3E /* Interrupt status */ 25 #define RTL8139_TXCONFIG 0x40 /* TX config */ 26 #define RTL8139_RXCONFIG 0x44 /* RX config */ 27 #define RTL8139_TIMER 0x48 /* Timer */ 28 #define RTL8139_RXMISSED 0x4C /* Missed packet counter */ 29 #define RTL8139_CFG9346 0x50 /* 93C46 command register */ 30 #define RTL8139_CONFIG0 0x51 /* Configuration 0 */ 31 #define RTL8139_CONFIG1 0x52 /* Configuration 1 */ 32 #define RTL8139_MSR 0x58 /* Media status register */ 33 #define RTL8139_CONFIG3 0x59 /* Configuration 3 */ 34 #define RTL8139_CONFIG4 0x5A /* Configuration 4 */ 35 #define RTL8139_MULINT 0x5C /* Multiple interrupt select */ 36 #define RTL8139_RERID 0x5E /* PCI revision ID */ 37 #define RTL8139_TSAD 0x60 /* Transmit status of all descriptors */ 38 #define RTL8139_BMCR 0x62 /* Basic mode control register */ 39 #define RTL8139_BMSR 0x64 /* Basic mode status register */ 40 41 /* Command register bits */ 42 #define RTL8139_CMD_RESET 0x10 43 #define RTL8139_CMD_RX_ENABLE 0x08 44 #define RTL8139_CMD_TX_ENABLE 0x04 45 #define RTL8139_CMD_BUF_EMPTY 0x01 46 47 /* Interrupt status/mask bits */ 48 #define RTL8139_INT_PCIERR 0x8000 /* PCI error */ 49 #define RTL8139_INT_TIMEOUT 0x4000 /* Timeout */ 50 #define RTL8139_INT_RXFIFO_OVERFLOW 0x0040 /* RX FIFO overflow */ 51 #define RTL8139_INT_RXBUF_OVERFLOW 0x0010 /* RX buffer overflow */ 52 #define RTL8139_INT_TX_OK 0x0004 /* Transmit OK */ 53 #define RTL8139_INT_RX_OK 0x0001 /* Receive OK */ 54 55 /* RX Config bits */ 56 #define RTL8139_RXCFG_ACCEPT_PHYS_MATCH 0x00000001 57 #define RTL8139_RXCFG_ACCEPT_PHYS_MULTICAST 0x00000002 58 #define RTL8139_RXCFG_ACCEPT_BROADCAST 0x00000008 59 #define RTL8139_RXCFG_ACCEPT_ALL_PHYS 0x00000001 60 #define RTL8139_RXCFG_WRAP 0x00000080 61 #define RTL8139_RXCFG_DMA_UNLIMITED 0x00000700 62 #define RTL8139_RXCFG_RBLEN_8K 0x00000000 63 #define RTL8139_RXCFG_RBLEN_16K 0x00000800 64 #define RTL8139_RXCFG_RBLEN_32K 0x00001000 65 #define RTL8139_RXCFG_RBLEN_64K 0x00001800 66 67 /* TX Config bits */ 68 #define RTL8139_TXCFG_DMA_UNLIMITED 0x00000700 69 #define RTL8139_TXCFG_RETRY_COUNT 0x000F0000 70 71 /* Buffer sizes */ 72 #define RTL8139_RX_BUF_SIZE (8192 + 16 + 1500) /* 8KB + header + MTU */ 73 #define RTL8139_TX_BUF_SIZE 1536 74 75 /* I/O port functions */ 76 static inline void outb(uint16_t port, uint8_t val) { 77 __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); 78 } 79 80 static inline uint8_t inb(uint16_t port) { 81 uint8_t ret; 82 __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port)); 83 return ret; 84 } 85 86 static inline void outw(uint16_t port, uint16_t val) { 87 __asm__ volatile ("outw %0, %1" : : "a"(val), "Nd"(port)); 88 } 89 90 static inline uint16_t inw(uint16_t port) { 91 uint16_t ret; 92 __asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port)); 93 return ret; 94 } 95 96 static inline void outl(uint16_t port, uint32_t val) { 97 __asm__ volatile ("outl %0, %1" : : "a"(val), "Nd"(port)); 98 } 99 100 static inline uint32_t inl(uint16_t port) { 101 uint32_t ret; 102 __asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port)); 103 return ret; 104 } 105 106 /* PCI Configuration Space */ 107 #define PCI_CONFIG_ADDRESS 0xCF8 108 #define PCI_CONFIG_DATA 0xCFC 109 110 static uint32_t pci_read_config(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { 111 uint32_t address = (uint32_t)( 112 (1 << 31) | /* Enable bit */ 113 (bus << 16) | 114 (slot << 11) | 115 (func << 8) | 116 (offset & 0xFC) 117 ); 118 outl(PCI_CONFIG_ADDRESS, address); 119 return inl(PCI_CONFIG_DATA); 120 } 121 122 static void pci_write_config(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value) { 123 uint32_t address = (uint32_t)( 124 (1 << 31) | 125 (bus << 16) | 126 (slot << 11) | 127 (func << 8) | 128 (offset & 0xFC) 129 ); 130 outl(PCI_CONFIG_ADDRESS, address); 131 outl(PCI_CONFIG_DATA, value); 132 } 133 134 /* RTL8139 State */ 135 static struct { 136 uint16_t io_base; 137 uint8_t mac_address[6]; 138 uint8_t* rx_buffer; 139 uint8_t* tx_buffer[4]; 140 int current_tx_desc; 141 uint16_t rx_buffer_offset; 142 int initialized; 143 } rtl8139_state = {0}; 144 145 /* Find RTL8139 on PCI bus */ 146 static int rtl8139_find_device(void) { 147 terminal_writestring("Scanning PCI bus for RTL8139...\n"); 148 149 /* Scan PCI bus 0, slots 0-31 */ 150 for (uint8_t slot = 0; slot < 32; slot++) { 151 uint32_t vendor_device = pci_read_config(0, slot, 0, 0x00); 152 153 /* Skip if no device */ 154 if (vendor_device == 0xFFFFFFFF || vendor_device == 0x00000000) { 155 continue; 156 } 157 158 uint16_t vendor_id = vendor_device & 0xFFFF; 159 uint16_t device_id = (vendor_device >> 16) & 0xFFFF; 160 161 /* Check for RTL8139 */ 162 if (vendor_id == RTL8139_VENDOR_ID && device_id == RTL8139_DEVICE_ID) { 163 terminal_writestring("Found RTL8139\n"); 164 165 /* Get I/O base address from BAR0 */ 166 uint32_t bar0 = pci_read_config(0, slot, 0, 0x10); 167 rtl8139_state.io_base = bar0 & 0xFFFC; /* Mask off I/O space bit */ 168 169 terminal_writestring("I/O Base configured\n"); 170 171 /* Enable bus mastering and I/O space */ 172 uint32_t command = pci_read_config(0, slot, 0, 0x04); 173 command |= 0x05; /* Enable I/O space (bit 0) and bus mastering (bit 2) */ 174 pci_write_config(0, slot, 0, 0x04, command); 175 176 return 1; 177 } 178 } 179 180 terminal_writestring("RTL8139 not found on PCI bus\n"); 181 return 0; 182 } 183 184 /* Allocate memory for buffers */ 185 extern void* malloc(size_t size); 186 187 /* Initialize RTL8139 */ 188 int rtl8139_init(void) { 189 terminal_writestring("Initializing RTL8139 network card...\n"); 190 191 /* Find device on PCI bus */ 192 if (!rtl8139_find_device()) { 193 return -1; 194 } 195 196 uint16_t io = rtl8139_state.io_base; 197 198 /* Power on */ 199 outb(io + RTL8139_CONFIG1, 0x00); 200 201 /* Software reset */ 202 terminal_writestring("Resetting RTL8139...\n"); 203 outb(io + RTL8139_CHIPCMD, RTL8139_CMD_RESET); 204 205 /* Wait for reset to complete */ 206 int timeout = 1000000; 207 while ((inb(io + RTL8139_CHIPCMD) & RTL8139_CMD_RESET) && timeout--) { 208 /* Busy wait */ 209 } 210 211 if (timeout <= 0) { 212 terminal_writestring("RTL8139 reset timeout!\n"); 213 return -1; 214 } 215 216 terminal_writestring("Reset complete\n"); 217 218 /* Read MAC address */ 219 for (int i = 0; i < 6; i++) { 220 rtl8139_state.mac_address[i] = inb(io + RTL8139_MAC0 + i); 221 } 222 223 terminal_writestring("MAC Address read successfully\n"); 224 225 /* Allocate receive buffer (must be physically contiguous) */ 226 rtl8139_state.rx_buffer = (uint8_t*)malloc(RTL8139_RX_BUF_SIZE + 16); 227 if (!rtl8139_state.rx_buffer) { 228 terminal_writestring("Failed to allocate RX buffer\n"); 229 return -1; 230 } 231 232 /* Align to 4-byte boundary */ 233 uint32_t rx_phys = (uint32_t)rtl8139_state.rx_buffer; 234 rx_phys = (rx_phys + 3) & ~3; 235 rtl8139_state.rx_buffer = (uint8_t*)rx_phys; 236 237 /* Allocate transmit buffers */ 238 for (int i = 0; i < 4; i++) { 239 rtl8139_state.tx_buffer[i] = (uint8_t*)malloc(RTL8139_TX_BUF_SIZE); 240 if (!rtl8139_state.tx_buffer[i]) { 241 terminal_writestring("Failed to allocate TX buffer\n"); 242 return -1; 243 } 244 } 245 246 /* Set receive buffer address */ 247 outl(io + RTL8139_RXBUF, (uint32_t)rtl8139_state.rx_buffer); 248 249 /* Set IMR + ISR (enable all interrupts) */ 250 outw(io + RTL8139_INTRMASK, 0x0005); /* RX OK + TX OK */ 251 252 /* Configure RX: accept broadcast, multicast, and physical match packets */ 253 uint32_t rx_config = RTL8139_RXCFG_ACCEPT_BROADCAST | 254 RTL8139_RXCFG_ACCEPT_PHYS_MATCH | 255 RTL8139_RXCFG_ACCEPT_PHYS_MULTICAST | 256 RTL8139_RXCFG_WRAP | 257 RTL8139_RXCFG_DMA_UNLIMITED | 258 RTL8139_RXCFG_RBLEN_8K; 259 outl(io + RTL8139_RXCONFIG, rx_config); 260 261 /* Configure TX */ 262 uint32_t tx_config = RTL8139_TXCFG_DMA_UNLIMITED | (0x03 << 24); /* Max DMA burst, default retry */ 263 outl(io + RTL8139_TXCONFIG, tx_config); 264 265 /* Enable RX and TX */ 266 outb(io + RTL8139_CHIPCMD, RTL8139_CMD_RX_ENABLE | RTL8139_CMD_TX_ENABLE); 267 268 rtl8139_state.current_tx_desc = 0; 269 rtl8139_state.rx_buffer_offset = 0; 270 rtl8139_state.initialized = 1; 271 272 terminal_writestring("RTL8139 initialized successfully!\n"); 273 return 0; 274 } 275 276 /* Send packet */ 277 int rtl8139_send(const uint8_t* data, uint16_t length) { 278 if (!rtl8139_state.initialized) { 279 return -1; 280 } 281 282 if (length > RTL8139_TX_BUF_SIZE - 4) { 283 return -1; /* Packet too large */ 284 } 285 286 uint16_t io = rtl8139_state.io_base; 287 int desc = rtl8139_state.current_tx_desc; 288 289 /* Copy data to TX buffer */ 290 memcpy(rtl8139_state.tx_buffer[desc], data, length); 291 292 /* Set TX address */ 293 outl(io + RTL8139_TXADDR0 + (desc * 4), (uint32_t)rtl8139_state.tx_buffer[desc]); 294 295 /* Set TX status (clears OWN bit and sets length) */ 296 outl(io + RTL8139_TXSTATUS0 + (desc * 4), length); 297 298 /* Move to next descriptor */ 299 rtl8139_state.current_tx_desc = (desc + 1) % 4; 300 301 return length; 302 } 303 304 /* Receive packet */ 305 int rtl8139_receive(uint8_t* buffer, uint16_t max_length) { 306 if (!rtl8139_state.initialized) { 307 return -1; 308 } 309 310 uint16_t io = rtl8139_state.io_base; 311 312 /* Check if RX buffer is empty */ 313 uint8_t cmd = inb(io + RTL8139_CHIPCMD); 314 if (cmd & RTL8139_CMD_BUF_EMPTY) { 315 return 0; /* No packets */ 316 } 317 318 /* Get current buffer offset */ 319 uint16_t offset = rtl8139_state.rx_buffer_offset; 320 321 /* Read packet header (4 bytes) */ 322 uint16_t* header = (uint16_t*)(rtl8139_state.rx_buffer + offset); 323 uint16_t status = header[0]; 324 uint16_t length = header[1]; 325 326 /* Check if packet is valid */ 327 if (!(status & 0x01)) { /* ROK bit */ 328 return -1; /* Bad packet */ 329 } 330 331 /* Remove CRC from length */ 332 length -= 4; 333 334 if (length > max_length) { 335 length = max_length; 336 } 337 338 /* Copy packet data (skip 4-byte header) */ 339 memcpy(buffer, rtl8139_state.rx_buffer + offset + 4, length); 340 341 /* Update offset (packet length + header + CRC, aligned to 4 bytes) */ 342 offset = (offset + length + 4 + 4 + 3) & ~3; 343 offset %= RTL8139_RX_BUF_SIZE; 344 rtl8139_state.rx_buffer_offset = offset; 345 346 /* Update CAPR (current address of packet read) */ 347 outw(io + RTL8139_RXBUFTAIL, offset - 0x10); 348 349 return length; 350 } 351 352 /* Get MAC address */ 353 void rtl8139_get_mac(uint8_t mac[6]) { 354 if (!rtl8139_state.initialized) { 355 memset(mac, 0, 6); 356 return; 357 } 358 memcpy(mac, rtl8139_state.mac_address, 6); 359 } 360 361 /* Check if initialized */ 362 int rtl8139_is_initialized(void) { 363 return rtl8139_state.initialized; 364 } 365 366 /* Lua binding: Initialize RTL8139 */ 367 int lua_rtl8139_init(lua_State* L) { 368 int result = rtl8139_init(); 369 lua_pushboolean(L, result == 0); 370 return 1; 371 } 372 373 /* Lua binding: Send packet */ 374 int lua_rtl8139_send(lua_State* L) { 375 size_t length; 376 const uint8_t* data = (const uint8_t*)luaL_checklstring(L, 1, &length); 377 378 int result = rtl8139_send(data, (uint16_t)length); 379 lua_pushinteger(L, result); 380 return 1; 381 } 382 383 /* Lua binding: Receive packet */ 384 int lua_rtl8139_receive(lua_State* L) { 385 static uint8_t buffer[2048]; 386 int length = rtl8139_receive(buffer, sizeof(buffer)); 387 388 if (length > 0) { 389 lua_pushlstring(L, (const char*)buffer, length); 390 return 1; 391 } else if (length == 0) { 392 lua_pushnil(L); /* No packet */ 393 return 1; 394 } else { 395 lua_pushnil(L); /* Error */ 396 return 1; 397 } 398 } 399 400 /* Lua binding: Get MAC address */ 401 int lua_rtl8139_get_mac(lua_State* L) { 402 uint8_t mac[6]; 403 rtl8139_get_mac(mac); 404 405 lua_newtable(L); 406 for (int i = 0; i < 6; i++) { 407 lua_pushinteger(L, mac[i]); 408 lua_rawseti(L, -2, i + 1); 409 } 410 return 1; 411 }