use crate::sys::allocator::PhysBuf; use crate::sys::net::{EthernetDeviceIO, Config, Stats}; use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::TryInto; use core::hint::spin_loop; use core::sync::atomic::{fence, AtomicUsize, Ordering}; use smoltcp::wire::EthernetAddress; use x86_64::instructions::port::Port; // 00 = 8K + 16 bytes // 01 = 16K + 16 bytes // 10 = 32K + 16 bytes // 11 = 64K + 16 bytes const RX_BUFFER_IDX: usize = 0; const MTU: usize = 1536; const RX_BUFFER_PAD: usize = 16; const RX_BUFFER_LEN: usize = 8192 << RX_BUFFER_IDX; const TX_BUFFER_LEN: usize = 2048; const TX_BUFFERS_COUNT: usize = 4; const ROK: u16 = 0x01; const CR_RST: u8 = 1 << 4; // Reset const CR_RE: u8 = 1 << 3; // Receiver Enable const CR_TE: u8 = 1 << 2; // Transmitter Enable const CR_BUFE: u8 = 1 << 0; // Buffer Empty // Rx Buffer Length const RCR_RBLEN: u32 = (RX_BUFFER_IDX << 11) as u32; // When the WRAP bit is set, the nic will keep moving the rest // of the packet data into the memory immediately after the // end of the Rx buffer instead of going back to the begining // of the buffer. So the buffer must have an additionnal 1500 bytes. const RCR_WRAP: u32 = 1 << 7; const RCR_AB: u32 = 1 << 3; // Accept Broadcast packets const RCR_AM: u32 = 1 << 2; // Accept Multicast packets const RCR_APM: u32 = 1 << 1; // Accept Physical Match packets const RCR_AAP: u32 = 1 << 0; // Accept All Packets // Interframe Gap Time const TCR_IFG: u32 = 3 << 24; // Max DMA Burst Size per Tx DMA Burst // 000 = 16 bytes // 001 = 32 bytes // 010 = 64 bytes // 011 = 128 bytes // 100 = 256 bytes // 101 = 512 bytes // 110 = 1024 bytes // 111 = 2048 bytes //const TCR_MXDMA0: u32 = 1 << 8; const TCR_MXDMA1: u32 = 1 << 9; const TCR_MXDMA2: u32 = 1 << 10; // Interrupt Mask Register //const IMR_TOK: u16 = 1 << 2; // Transmit OK Interrupt //const IMR_ROK: u16 = 1 << 0; // Receive OK Interrupt //const CRS: u32 = 1 << 31; // Carrier Sense Lost //const TAB: u32 = 1 << 30; // Transmit Abort //const OWC: u32 = 1 << 29; // Out of Window Collision //const CDH: u32 = 1 << 28; // CD Heart Beat const TOK: u32 = 1 << 15; // Transmit OK //const TUN: u32 = 1 << 14; // Transmit FIFO Underrun const OWN: u32 = 1 << 13; // DMA operation completed #[derive(Clone)] pub struct Ports { pub mac: [Port; 6], // ID Registers (IDR0 ... IDR5) pub tx_cmds: [Port; TX_BUFFERS_COUNT], // Transmit Status of Descriptors (TSD0 .. TSD3) pub tx_addrs: [Port; TX_BUFFERS_COUNT], // Transmit Start Address of Descriptor0 (TSAD0 .. TSAD3) pub config1: Port, // Configuration Register 1 (CONFIG1) pub rx_addr: Port, // Receive (Rx) Buffer Start Address (RBSTART) pub capr: Port, // Current Address of Packet Read (CAPR) pub cba: Port, // Current Buffer Address (CBA) pub cmd: Port, // Command Register (CR) pub imr: Port, // Interrupt Mask Register (IMR) pub isr: Port, // Interrupt Status Register (ISR) pub tx_config: Port, // Transmit (Tx) Configuration Register (TCR) pub rx_config: Port, // Receive (Rx) Configuration Register (RCR) } impl Ports { pub fn new(io_base: u16) -> Self { Self { mac: [ Port::new(io_base + 0x00), Port::new(io_base + 0x01), Port::new(io_base + 0x02), Port::new(io_base + 0x03), Port::new(io_base + 0x04), Port::new(io_base + 0x05), ], tx_cmds: [ Port::new(io_base + 0x10), Port::new(io_base + 0x14), Port::new(io_base + 0x18), Port::new(io_base + 0x1C), ], tx_addrs: [ Port::new(io_base + 0x20), Port::new(io_base + 0x24), Port::new(io_base + 0x28), Port::new(io_base + 0x2C), ], config1: Port::new(io_base + 0x52), rx_addr: Port::new(io_base + 0x30), capr: Port::new(io_base + 0x38), cba: Port::new(io_base + 0x3A), cmd: Port::new(io_base + 0x37), imr: Port::new(io_base + 0x3C), isr: Port::new(io_base + 0x3E), tx_config: Port::new(io_base + 0x40), rx_config: Port::new(io_base + 0x44), } } fn mac(&mut self) -> [u8; 6] { unsafe { [ self.mac[0].read(), self.mac[1].read(), self.mac[2].read(), self.mac[3].read(), self.mac[4].read(), self.mac[5].read(), ] } } } #[derive(Clone)] pub struct Device { config: Arc, stats: Arc, ports: Ports, rx_buffer: PhysBuf, rx_offset: usize, tx_buffers: [PhysBuf; TX_BUFFERS_COUNT], tx_id: Arc, } impl Device { pub fn new(io_base: u16) -> Self { let mut device = Self { config: Arc::new(Config::new()), stats: Arc::new(Stats::new()), ports: Ports::new(io_base), // Add MTU to RX_BUFFER_LEN if RCR_WRAP is set rx_buffer: PhysBuf::new(RX_BUFFER_LEN + RX_BUFFER_PAD + MTU), rx_offset: 0, tx_buffers: [(); TX_BUFFERS_COUNT].map(|_| PhysBuf::new(TX_BUFFER_LEN)), // Before a transmission begin the id is incremented, // so the first transimission will start at 0. tx_id: Arc::new(AtomicUsize::new(TX_BUFFERS_COUNT - 1)), }; device.init(); device } fn init(&mut self) { // Power on unsafe { self.ports.config1.write(0) } // Software reset unsafe { self.ports.cmd.write(CR_RST); fence(Ordering::SeqCst); while self.ports.cmd.read() & CR_RST != 0 { spin_loop(); } } // Set interrupts //unsafe { self.ports.imr.write(IMR_TOK | IMR_ROK) } // Enable Receive and Transmitter unsafe { self.ports.cmd.write(CR_RE | CR_TE) } // Read MAC addr self.config.update_mac(EthernetAddress::from_bytes(&self.ports.mac())); // Get physical address of rx_buffer let rx_addr = self.rx_buffer.addr(); // Init Receive buffer unsafe { self.ports.rx_addr.write(rx_addr as u32) } for i in 0..4 { // Get physical address of each tx_buffer let tx_addr = self.tx_buffers[i].addr(); // Init Transmit buffer unsafe { self.ports.tx_addrs[i].write(tx_addr as u32) } } // Configure receive buffer (RCR) unsafe { self.ports.rx_config.write(RCR_RBLEN | RCR_WRAP | RCR_AB | RCR_AM | RCR_APM | RCR_AAP) } // Configure transmit buffer (TCR) unsafe { self.ports.tx_config.write(TCR_IFG | TCR_MXDMA1 | TCR_MXDMA2); } } } impl EthernetDeviceIO for Device { fn config(&self) -> Arc { self.config.clone() } fn stats(&self) -> Arc { self.stats.clone() } // RxToken buffer, when not empty, will contains: // [header (2 bytes)] // [length (2 bytes)] // [packet (length - 4 bytes)] // [crc (4 bytes)] fn receive_packet(&mut self) -> Option> { let cmd = unsafe { self.ports.cmd.read() }; if (cmd & CR_BUFE) == CR_BUFE { return None; } //let isr = unsafe { self.ports.isr.read() }; let cba = unsafe { self.ports.cba.read() }; // CAPR starts at 65520 and with the pad it overflows to 0 let capr = unsafe { self.ports.capr.read() }; let offset = ((capr as usize) + RX_BUFFER_PAD) % (1 << 16); let header = u16::from_le_bytes(self.rx_buffer[(offset + 0)..(offset + 2)].try_into().unwrap()); if header & ROK != ROK { unsafe { self.ports.capr.write((((cba as usize) % RX_BUFFER_LEN) - RX_BUFFER_PAD) as u16) }; return None; } let n = u16::from_le_bytes(self.rx_buffer[(offset + 2)..(offset + 4)].try_into().unwrap()) as usize; //let crc = u32::from_le_bytes(self.rx_buffer[(offset + n)..(offset + n + 4)].try_into().unwrap()); // Update buffer read pointer self.rx_offset = (offset + n + 4 + 3) & !3; unsafe { self.ports.capr.write(((self.rx_offset % RX_BUFFER_LEN) - RX_BUFFER_PAD) as u16); } //unsafe { self.ports.isr.write(0x1); } Some(self.rx_buffer[(offset + 4)..(offset + n)].to_vec()) } fn transmit_packet(&mut self, len: usize) { let tx_id = self.tx_id.load(Ordering::SeqCst); let mut cmd_port = self.ports.tx_cmds[tx_id].clone(); unsafe { // RTL8139 will not transmit packets smaller than 64 bits let len = len.max(60); // 60 + 4 bits of CRC // Fill in Transmit Status: the size of this packet, the early // transmit threshold, and clear OWN bit in TSD (this starts the // PCI operation). // NOTE: The length of the packet use the first 13 bits (but should // not exceed 1792 bytes), and a value of 0x000000 for the early // transmit threshold means 8 bytes. So we just write the size of // the packet. cmd_port.write(0x1FFF & len as u32); fence(Ordering::SeqCst); while cmd_port.read() & OWN != OWN { spin_loop(); } while cmd_port.read() & TOK != TOK { spin_loop(); } } //unsafe { self.ports.isr.write(0x4); } } fn next_tx_buffer(&mut self, len: usize) -> &mut [u8] { let tx_id = (self.tx_id.load(Ordering::SeqCst) + 1) % TX_BUFFERS_COUNT; self.tx_id.store(tx_id, Ordering::Relaxed); &mut self.tx_buffers[tx_id][0..len] } } /* pub fn interrupt_handler() { printk!("RTL8139 interrupt!\n"); if let Some(mut guard) = sys::net::IFACE.try_lock() { if let Some(ref mut iface) = *guard { unsafe { iface.device_mut().ports.isr.write(0xFFFF) } // Clear the interrupt } } } */