Serenity Operating System
at portability 399 lines 13 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <Kernel/Net/RTL8139NetworkAdapter.h> 28#include <LibBareMetal/IO.h> 29 30//#define RTL8139_DEBUG 31 32namespace Kernel { 33 34#define REG_MAC 0x00 35#define REG_MAR0 0x08 36#define REG_MAR4 0x12 37#define REG_TXSTATUS0 0x10 38#define REG_TXADDR0 0x20 39#define REG_RXBUF 0x30 40#define REG_COMMAND 0x37 41#define REG_CAPR 0x38 42#define REG_IMR 0x3C 43#define REG_ISR 0x3E 44#define REG_TXCFG 0x40 45#define REG_RXCFG 0x44 46#define REG_MPC 0x4C 47#define REG_CFG9346 0x50 48#define REG_CONFIG1 0x52 49#define REG_MSR 0x58 50#define REG_BMCR 0x62 51 52#define TX_STATUS_OWN 0x2000 53#define TX_STATUS_THRESHOLD_MAX 0x3F0000 54 55#define COMMAND_RX_EMPTY 0x01 56#define COMMAND_TX_ENABLE 0x04 57#define COMMAND_RX_ENABLE 0x08 58#define COMMAND_RESET 0x10 59 60#define INT_RXOK 0x01 61#define INT_RXERR 0x02 62#define INT_TXOK 0x04 63#define INT_TXERR 0x08 64#define INT_RX_BUFFER_OVERFLOW 0x10 65#define INT_LINK_CHANGE 0x20 66#define INT_RX_FIFO_OVERFLOW 0x40 67#define INT_LENGTH_CHANGE 0x2000 68#define INT_SYSTEM_ERROR 0x8000 69 70#define CFG9346_NONE 0x00 71#define CFG9346_EEM0 0x40 72#define CFG9346_EEM1 0x80 73 74#define TXCFG_TXRR_ZERO 0x00 75#define TXCFG_MAX_DMA_16B 0x000 76#define TXCFG_MAX_DMA_32B 0x100 77#define TXCFG_MAX_DMA_64B 0x200 78#define TXCFG_MAX_DMA_128B 0x300 79#define TXCFG_MAX_DMA_256B 0x400 80#define TXCFG_MAX_DMA_512B 0x500 81#define TXCFG_MAX_DMA_1K 0x600 82#define TXCFG_MAX_DMA_2K 0x700 83#define TXCFG_IFG11 0x3000000 84 85#define RXCFG_AAP 0x01 86#define RXCFG_APM 0x02 87#define RXCFG_AM 0x04 88#define RXCFG_AB 0x08 89#define RXCFG_AR 0x10 90#define RXCFG_WRAP_INHIBIT 0x80 91#define RXCFG_MAX_DMA_16B 0x000 92#define RXCFG_MAX_DMA_32B 0x100 93#define RXCFG_MAX_DMA_64B 0x200 94#define RXCFG_MAX_DMA_128B 0x300 95#define RXCFG_MAX_DMA_256B 0x400 96#define RXCFG_MAX_DMA_512B 0x500 97#define RXCFG_MAX_DMA_1K 0x600 98#define RXCFG_MAX_DMA_UNLIMITED 0x0700 99#define RXCFG_RBLN_8K 0x0000 100#define RXCFG_RBLN_16K 0x0800 101#define RXCFG_RBLN_32K 0x1000 102#define RXCFG_RBLN_64K 0x1800 103#define RXCFG_FTH_NONE 0xE000 104 105#define MSR_LINKB 0x02 106#define MSR_RX_FLOW_CONTROL_ENABLE 0x40 107 108#define BMCR_SPEED 0x2000 109#define BMCR_AUTO_NEGOTIATE 0x1000 110#define BMCR_DUPLEX 0x0100 111 112#define RX_MULTICAST 0x8000 113#define RX_PHYSICAL_MATCH 0x4000 114#define RX_BROADCAST 0x2000 115#define RX_INVALID_SYMBOL_ERROR 0x20 116#define RX_RUNT 0x10 117#define RX_LONG 0x08 118#define RX_CRC_ERROR 0x04 119#define RX_FRAME_ALIGNMENT_ERROR 0x02 120#define RX_OK 0x01 121 122#define PACKET_SIZE_MAX 0x600 123#define PACKET_SIZE_MIN 0x16 124 125#define RX_BUFFER_SIZE 32768 126#define TX_BUFFER_SIZE PACKET_SIZE_MAX 127 128void RTL8139NetworkAdapter::detect(const PCI::Address& address) 129{ 130 if (address.is_null()) 131 return; 132 static const PCI::ID rtl8139_id = { 0x10EC, 0x8139 }; 133 PCI::ID id = PCI::get_id(address); 134 if (id != rtl8139_id) 135 return; 136 u8 irq = PCI::get_interrupt_line(address); 137 (void)adopt(*new RTL8139NetworkAdapter(address, irq)).leak_ref(); 138} 139 140RTL8139NetworkAdapter::RTL8139NetworkAdapter(PCI::Address address, u8 irq) 141 : PCI::Device(address, irq) 142{ 143 set_interface_name("rtl8139"); 144 145 kprintf("RTL8139: Found at PCI address %b:%b:%b\n", pci_address().bus(), pci_address().slot(), pci_address().function()); 146 147 enable_bus_mastering(pci_address()); 148 149 m_io_base = PCI::get_BAR0(pci_address()) & ~1; 150 m_interrupt_line = PCI::get_interrupt_line(pci_address()); 151 kprintf("RTL8139: IO port base: %w\n", m_io_base); 152 kprintf("RTL8139: Interrupt line: %u\n", m_interrupt_line); 153 154 // we add space to account for overhang from the last packet - the rtl8139 155 // can optionally guarantee that packets will be contiguous by 156 // purposefully overrunning the rx buffer 157 m_rx_buffer_addr = (uintptr_t)virtual_to_low_physical(kmalloc_aligned(RX_BUFFER_SIZE + PACKET_SIZE_MAX, 16)); 158 kprintf("RTL8139: RX buffer: P%p\n", m_rx_buffer_addr); 159 160 auto tx_buffer_addr = (uintptr_t)virtual_to_low_physical(kmalloc_aligned(TX_BUFFER_SIZE * 4, 16)); 161 for (int i = 0; i < RTL8139_TX_BUFFER_COUNT; i++) { 162 m_tx_buffer_addr[i] = tx_buffer_addr + TX_BUFFER_SIZE * i; 163 kprintf("RTL8139: TX buffer %d: P%p\n", i, m_tx_buffer_addr[i]); 164 } 165 166 m_packet_buffer = (uintptr_t)kmalloc(PACKET_SIZE_MAX); 167 168 reset(); 169 170 read_mac_address(); 171 const auto& mac = mac_address(); 172 kprintf("RTL8139: MAC address: %s\n", mac.to_string().characters()); 173 174 enable_irq(); 175} 176 177RTL8139NetworkAdapter::~RTL8139NetworkAdapter() 178{ 179} 180 181void RTL8139NetworkAdapter::handle_irq(RegisterState&) 182{ 183 for (;;) { 184 int status = in16(REG_ISR); 185 out16(REG_ISR, status); 186 187#ifdef RTL8139_DEBUG 188 kprintf("RTL8139NetworkAdapter::handle_irq status=%#04x\n", status); 189#endif 190 191 if ((status & (INT_RXOK | INT_RXERR | INT_TXOK | INT_TXERR | INT_RX_BUFFER_OVERFLOW | INT_LINK_CHANGE | INT_RX_FIFO_OVERFLOW | INT_LENGTH_CHANGE | INT_SYSTEM_ERROR)) == 0) 192 break; 193 194 if (status & INT_RXOK) { 195#ifdef RTL8139_DEBUG 196 kprintf("RTL8139NetworkAdapter: rx ready\n"); 197#endif 198 receive(); 199 } 200 if (status & INT_RXERR) { 201 kprintf("RTL8139NetworkAdapter: rx error - resetting device\n"); 202 reset(); 203 } 204 if (status & INT_TXOK) { 205#ifdef RTL8139_DEBUG 206 kprintf("RTL8139NetworkAdapter: tx complete\n"); 207#endif 208 } 209 if (status & INT_TXERR) { 210 kprintf("RTL8139NetworkAdapter: tx error - resetting device\n"); 211 reset(); 212 } 213 if (status & INT_RX_BUFFER_OVERFLOW) { 214 kprintf("RTL8139NetworkAdapter: rx buffer overflow\n"); 215 } 216 if (status & INT_LINK_CHANGE) { 217 m_link_up = (in8(REG_MSR) & MSR_LINKB) == 0; 218 kprintf("RTL8139NetworkAdapter: link status changed up=%d\n", m_link_up); 219 } 220 if (status & INT_RX_FIFO_OVERFLOW) { 221 kprintf("RTL8139NetworkAdapter: rx fifo overflow\n"); 222 } 223 if (status & INT_LENGTH_CHANGE) { 224 kprintf("RTL8139NetworkAdapter: cable length change\n"); 225 } 226 if (status & INT_SYSTEM_ERROR) { 227 kprintf("RTL8139NetworkAdapter: system error - resetting device\n"); 228 reset(); 229 } 230 } 231} 232 233void RTL8139NetworkAdapter::reset() 234{ 235 m_rx_buffer_offset = 0; 236 m_tx_next_buffer = 0; 237 238 // reset the device to clear out all the buffers and config 239 out8(REG_COMMAND, COMMAND_RESET); 240 while ((in8(REG_COMMAND) & COMMAND_RESET) != 0) 241 ; 242 243 // unlock config registers 244 out8(REG_CFG9346, CFG9346_EEM0 | CFG9346_EEM1); 245 // turn on multicast 246 out32(REG_MAR0, 0xffffffff); 247 out32(REG_MAR4, 0xffffffff); 248 // enable rx/tx 249 out8(REG_COMMAND, COMMAND_RX_ENABLE | COMMAND_TX_ENABLE); 250 // device might be in sleep mode, this will take it out 251 out8(REG_CONFIG1, 0); 252 // set up rx buffer 253 out32(REG_RXBUF, m_rx_buffer_addr); 254 // reset missed packet counter 255 out8(REG_MPC, 0); 256 // "basic mode control register" options - 100mbit, full duplex, auto 257 // negotiation 258 out16(REG_BMCR, BMCR_SPEED | BMCR_AUTO_NEGOTIATE | BMCR_DUPLEX); 259 // enable flow control 260 out8(REG_MSR, MSR_RX_FLOW_CONTROL_ENABLE); 261 // configure rx: accept physical (MAC) match, multicast, and broadcast, 262 // use the optional contiguous packet feature, the maximum dma transfer 263 // size, a 32k buffer, and no fifo threshold 264 out32(REG_RXCFG, RXCFG_APM | RXCFG_AM | RXCFG_AB | RXCFG_WRAP_INHIBIT | RXCFG_MAX_DMA_UNLIMITED | RXCFG_RBLN_32K | RXCFG_FTH_NONE); 265 // configure tx: default retry count (16), max DMA burst size of 1024 266 // bytes, interframe gap time of the only allowable value. the DMA burst 267 // size is important - silent failures have been observed with 2048 bytes. 268 out32(REG_TXCFG, TXCFG_TXRR_ZERO | TXCFG_MAX_DMA_1K | TXCFG_IFG11); 269 // tell the chip where we want it to DMA from for outgoing packets. 270 for (int i = 0; i < 4; i++) 271 out32(REG_TXADDR0 + (i * 4), m_tx_buffer_addr[i]); 272 // re-lock config registers 273 out8(REG_CFG9346, CFG9346_NONE); 274 // enable rx/tx again in case they got turned off (apparently some cards 275 // do this?) 276 out8(REG_COMMAND, COMMAND_RX_ENABLE | COMMAND_TX_ENABLE); 277 278 // choose irqs, then clear any pending 279 out16(REG_IMR, INT_RXOK | INT_RXERR | INT_TXOK | INT_TXERR | INT_RX_BUFFER_OVERFLOW | INT_LINK_CHANGE | INT_RX_FIFO_OVERFLOW | INT_LENGTH_CHANGE | INT_SYSTEM_ERROR); 280 out16(REG_ISR, 0xffff); 281} 282 283void RTL8139NetworkAdapter::read_mac_address() 284{ 285 u8 mac[6]; 286 for (int i = 0; i < 6; i++) 287 mac[i] = in8(REG_MAC + i); 288 set_mac_address(mac); 289} 290 291void RTL8139NetworkAdapter::send_raw(const u8* data, size_t length) 292{ 293#ifdef RTL8139_DEBUG 294 kprintf("RTL8139NetworkAdapter::send_raw length=%d\n", length); 295#endif 296 297 if (length > PACKET_SIZE_MAX) { 298 kprintf("RTL8139NetworkAdapter: packet was too big; discarding\n"); 299 return; 300 } 301 302 int hw_buffer = -1; 303 for (int i = 0; i < RTL8139_TX_BUFFER_COUNT; i++) { 304 int potential_buffer = (m_tx_next_buffer + i) % 4; 305 306 auto status = in32(REG_TXSTATUS0 + (potential_buffer * 4)); 307 if (status & TX_STATUS_OWN) { 308 hw_buffer = potential_buffer; 309 break; 310 } 311 } 312 313 if (hw_buffer == -1) { 314 kprintf("RTL8139NetworkAdapter: hardware buffers full; discarding packet\n"); 315 return; 316 } else { 317#ifdef RTL8139_DEBUG 318 kprintf("RTL8139NetworkAdapter: chose buffer %d @ %p\n", hw_buffer, m_tx_buffer_addr[hw_buffer]); 319#endif 320 m_tx_next_buffer = (hw_buffer + 1) % 4; 321 } 322 323 memcpy((void*)low_physical_to_virtual(m_tx_buffer_addr[hw_buffer]), data, length); 324 memset((void*)(low_physical_to_virtual(m_tx_buffer_addr[hw_buffer]) + length), 0, TX_BUFFER_SIZE - length); 325 326 // the rtl8139 will not actually emit packets onto the network if they're 327 // smaller than 64 bytes. the rtl8139 adds a checksum to the end of each 328 // packet, and that checksum is four bytes long, so we pad the packet to 329 // 60 bytes if necessary to make sure the whole thing is large enough. 330 if (length < 60) { 331#ifdef RTL8139_DEBUG 332 kprintf("RTL8139NetworkAdapter: adjusting payload size from %zu to 60\n", length); 333#endif 334 length = 60; 335 } 336 337 out32(REG_TXSTATUS0 + (hw_buffer * 4), length); 338} 339 340void RTL8139NetworkAdapter::receive() 341{ 342 auto* start_of_packet = (const u8*)(low_physical_to_virtual(m_rx_buffer_addr) + m_rx_buffer_offset); 343 344 u16 status = *(const u16*)(start_of_packet + 0); 345 u16 length = *(const u16*)(start_of_packet + 2); 346 347#ifdef RTL8139_DEBUG 348 kprintf("RTL8139NetworkAdapter::receive status=%04x length=%d offset=%d\n", status, length, m_rx_buffer_offset); 349#endif 350 351 if (!(status & RX_OK) || (status & (RX_INVALID_SYMBOL_ERROR | RX_CRC_ERROR | RX_FRAME_ALIGNMENT_ERROR)) || (length >= PACKET_SIZE_MAX) || (length < PACKET_SIZE_MIN)) { 352 kprintf("RTL8139NetworkAdapter::receive got bad packet status=%04x length=%d\n", status, length); 353 reset(); 354 return; 355 } 356 357 // we never have to worry about the packet wrapping around the buffer, 358 // since we set RXCFG_WRAP_INHIBIT, which allows the rtl8139 to write data 359 // past the end of the alloted space. 360 memcpy((u8*)m_packet_buffer, (const u8*)(start_of_packet + 4), length - 4); 361 // let the card know that we've read this data 362 m_rx_buffer_offset = ((m_rx_buffer_offset + length + 4 + 3) & ~3) % RX_BUFFER_SIZE; 363 out16(REG_CAPR, m_rx_buffer_offset - 0x10); 364 m_rx_buffer_offset %= RX_BUFFER_SIZE; 365 366 did_receive((const u8*)m_packet_buffer, length - 4); 367} 368 369void RTL8139NetworkAdapter::out8(u16 address, u8 data) 370{ 371 IO::out8(m_io_base + address, data); 372} 373 374void RTL8139NetworkAdapter::out16(u16 address, u16 data) 375{ 376 IO::out16(m_io_base + address, data); 377} 378 379void RTL8139NetworkAdapter::out32(u16 address, u32 data) 380{ 381 IO::out32(m_io_base + address, data); 382} 383 384u8 RTL8139NetworkAdapter::in8(u16 address) 385{ 386 return IO::in8(m_io_base + address); 387} 388 389u16 RTL8139NetworkAdapter::in16(u16 address) 390{ 391 return IO::in16(m_io_base + address); 392} 393 394u32 RTL8139NetworkAdapter::in32(u16 address) 395{ 396 return IO::in32(m_io_base + address); 397} 398 399}