mirror of https://github.com/vinc/moros.git
304 lines
10 KiB
Rust
304 lines
10 KiB
Rust
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<u8>; 6], // ID Registers (IDR0 ... IDR5)
|
|
pub tx_cmds: [Port<u32>; TX_BUFFERS_COUNT], // Transmit Status of Descriptors (TSD0 .. TSD3)
|
|
pub tx_addrs: [Port<u32>; TX_BUFFERS_COUNT], // Transmit Start Address of Descriptor0 (TSAD0 .. TSAD3)
|
|
pub config1: Port<u8>, // Configuration Register 1 (CONFIG1)
|
|
pub rx_addr: Port<u32>, // Receive (Rx) Buffer Start Address (RBSTART)
|
|
pub capr: Port<u16>, // Current Address of Packet Read (CAPR)
|
|
pub cba: Port<u16>, // Current Buffer Address (CBA)
|
|
pub cmd: Port<u8>, // Command Register (CR)
|
|
pub imr: Port<u16>, // Interrupt Mask Register (IMR)
|
|
pub isr: Port<u16>, // Interrupt Status Register (ISR)
|
|
pub tx_config: Port<u32>, // Transmit (Tx) Configuration Register (TCR)
|
|
pub rx_config: Port<u32>, // 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<Config>,
|
|
stats: Arc<Stats>,
|
|
ports: Ports,
|
|
|
|
rx_buffer: PhysBuf,
|
|
rx_offset: usize,
|
|
tx_buffers: [PhysBuf; TX_BUFFERS_COUNT],
|
|
tx_id: Arc<AtomicUsize>,
|
|
}
|
|
|
|
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<Config> {
|
|
self.config.clone()
|
|
}
|
|
|
|
fn stats(&self) -> Arc<Stats> {
|
|
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<Vec<u8>> {
|
|
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
|
|
}
|
|
}
|
|
}
|
|
*/
|