use std::{cmp, mem, ptr, slice}; use dma::Dma; use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; use syscall::scheme::Scheme; const CTRL: u32 = 0x00; const CTRL_LRST: u32 = 1 << 3; const CTRL_ASDE: u32 = 1 << 5; const CTRL_SLU: u32 = 1 << 6; const CTRL_ILOS: u32 = 1 << 7; const CTRL_VME: u32 = 1 << 30; const CTRL_PHY_RST: u32 = 1 << 31; const STATUS: u32 = 0x08; const FCAL: u32 = 0x28; const FCAH: u32 = 0x2C; const FCT: u32 = 0x30; const FCTTV: u32 = 0x170; const ICR: u32 = 0xC0; const IMS: u32 = 0xD0; const IMS_TXDW: u32 = 1; const IMS_TXQE: u32 = 1 << 1; const IMS_LSC: u32 = 1 << 2; const IMS_RXSEQ: u32 = 1 << 3; const IMS_RXDMT: u32 = 1 << 4; const IMS_RX: u32 = 1 << 6; const IMS_RXT: u32 = 1 << 7; const RCTL: u32 = 0x100; const RCTL_EN: u32 = 1 << 1; const RCTL_UPE: u32 = 1 << 3; const RCTL_MPE: u32 = 1 << 4; const RCTL_LPE: u32 = 1 << 5; const RCTL_LBM: u32 = 1 << 6 | 1 << 7; const RCTL_BAM: u32 = 1 << 15; const RCTL_BSIZE1: u32 = 1 << 16; const RCTL_BSIZE2: u32 = 1 << 17; const RCTL_BSEX: u32 = 1 << 25; const RCTL_SECRC: u32 = 1 << 26; const RDBAL: u32 = 0x2800; const RDBAH: u32 = 0x2804; const RDLEN: u32 = 0x2808; const RDH: u32 = 0x2810; const RDT: u32 = 0x2818; const RAL0: u32 = 0x5400; const RAH0: u32 = 0x5404; #[derive(Debug)] #[repr(packed)] struct Rd { buffer: u64, length: u16, checksum: u16, status: u8, error: u8, special: u16, } const RD_DD: u8 = 1; const RD_EOP: u8 = 1 << 1; const TCTL: u32 = 0x400; const TCTL_EN: u32 = 1 << 1; const TCTL_PSP: u32 = 1 << 3; const TDBAL: u32 = 0x3800; const TDBAH: u32 = 0x3804; const TDLEN: u32 = 0x3808; const TDH: u32 = 0x3810; const TDT: u32 = 0x3818; #[derive(Debug)] #[repr(packed)] struct Td { buffer: u64, length: u16, cso: u8, command: u8, status: u8, css: u8, special: u16, } const TD_CMD_EOP: u8 = 1; const TD_CMD_IFCS: u8 = 1 << 1; const TD_CMD_RS: u8 = 1 << 3; const TD_DD: u8 = 1; pub struct Intel8254x { base: usize, receive_buffer: [Dma<[u8; 16384]>; 16], receive_ring: Dma<[Rd; 16]>, transmit_buffer: [Dma<[u8; 16384]>; 16], transmit_ring: Dma<[Td; 16]> } impl Scheme for Intel8254x { fn open(&self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { Ok(flags) } else { Err(Error::new(EACCES)) } } fn dup(&self, id: usize) -> Result { Ok(id) } fn read(&self, id: usize, buf: &mut [u8]) -> Result { let head = unsafe { self.read(RDH) }; let mut tail = unsafe { self.read(RDT) }; tail += 1; if tail >= self.receive_ring.len() as u32 { tail = 0; } if tail != head { let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) }; if rd.status & RD_DD == RD_DD { rd.status = 0; let data = &self.receive_buffer[tail as usize][.. rd.length as usize]; let mut i = 0; while i < buf.len() && i < data.len() { buf[i] = data[i]; i += 1; } unsafe { self.write(RDT, tail) }; return Ok(i); } } if id & O_NONBLOCK == O_NONBLOCK { Ok(0) } else { Err(Error::new(EWOULDBLOCK)) } } fn write(&self, _id: usize, buf: &[u8]) -> Result { loop { let head = unsafe { self.read(TDH) }; let mut tail = unsafe { self.read(TDT) }; let old_tail = tail; tail += 1; if tail >= self.transmit_ring.len() as u32 { tail = 0; } if tail != head { let td = unsafe { &mut * (self.transmit_ring.as_ptr().offset(old_tail as isize) as *mut Td) }; td.cso = 0; td.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS; td.status = 0; td.css = 0; td.special = 0; td.length = (cmp::min(buf.len(), 0x3FFF)) as u16; let mut data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) }; let mut i = 0; while i < buf.len() && i < data.len() { data[i] = buf[i]; i += 1; } unsafe { self.write(TDT, tail) }; while td.status == 0 { unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } } return Ok(i); } unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } } } fn fevent(&self, _id: usize, _flags: usize) -> Result { Ok(0) } fn fsync(&self, _id: usize) -> Result { Ok(0) } fn close(&self, _id: usize) -> Result { Ok(0) } } impl Intel8254x { pub unsafe fn new(base: usize) -> Result { let mut module = Intel8254x { base: base, receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], receive_ring: Dma::zeroed()?, transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], transmit_ring: Dma::zeroed()? }; module.init(); Ok(module) } pub unsafe fn irq(&self) -> bool { let icr = self.read(ICR); icr != 0 } pub fn next_read(&self) -> usize { let head = unsafe { self.read(RDH) }; let mut tail = unsafe { self.read(RDT) }; tail += 1; if tail >= self.receive_ring.len() as u32 { tail = 0; } if tail != head { let rd = unsafe { &* (self.receive_ring.as_ptr().offset(tail as isize) as *const Rd) }; if rd.status & RD_DD == RD_DD { return rd.length as usize; } } 0 } pub unsafe fn read(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } pub unsafe fn write(&self, register: u32, data: u32) -> u32 { ptr::write_volatile((self.base + register as usize) as *mut u32, data); ptr::read_volatile((self.base + register as usize) as *mut u32) } pub unsafe fn flag(&self, register: u32, flag: u32, value: bool) { if value { self.write(register, self.read(register) | flag); } else { self.write(register, self.read(register) & (0xFFFFFFFF - flag)); } } pub unsafe fn init(&mut self) { // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal self.flag(CTRL, CTRL_ASDE | CTRL_SLU, true); self.flag(CTRL, CTRL_LRST, false); self.flag(CTRL, CTRL_PHY_RST, false); self.flag(CTRL, CTRL_ILOS, false); // No flow control self.write(FCAH, 0); self.write(FCAL, 0); self.write(FCT, 0); self.write(FCTTV, 0); // Do not use VLANs self.flag(CTRL, CTRL_VME, false); // TODO: Clear statistical counters let mac_low = self.read(RAL0); let mac_high = self.read(RAH0); let mac = [mac_low as u8, (mac_low >> 8) as u8, (mac_low >> 16) as u8, (mac_low >> 24) as u8, mac_high as u8, (mac_high >> 8) as u8]; print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // // MTA => 0; // // Receive Buffer for i in 0..self.receive_ring.len() { self.receive_ring[i].buffer = self.receive_buffer[i].physical() as u64; } self.write(RDBAH, (self.receive_ring.physical() >> 32) as u32); self.write(RDBAL, self.receive_ring.physical() as u32); self.write(RDLEN, (self.receive_ring.len() * mem::size_of::()) as u32); self.write(RDH, 0); self.write(RDT, self.receive_ring.len() as u32 - 1); // Transmit Buffer for i in 0..self.transmit_ring.len() { self.transmit_ring[i].buffer = self.transmit_buffer[i].physical() as u64; } self.write(TDBAH, (self.transmit_ring.physical() >> 32) as u32); self.write(TDBAL, self.transmit_ring.physical() as u32); self.write(TDLEN, (self.transmit_ring.len() * mem::size_of::()) as u32); self.write(TDH, 0); self.write(TDT, 0); self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW self.flag(RCTL, RCTL_EN, true); self.flag(RCTL, RCTL_UPE, true); // self.flag(RCTL, RCTL_MPE, true); self.flag(RCTL, RCTL_LPE, true); self.flag(RCTL, RCTL_LBM, false); // RCTL.RDMTS = Minimum threshold size ??? // RCTL.MO = Multicast offset self.flag(RCTL, RCTL_BAM, true); self.flag(RCTL, RCTL_BSIZE1, true); self.flag(RCTL, RCTL_BSIZE2, false); self.flag(RCTL, RCTL_BSEX, true); self.flag(RCTL, RCTL_SECRC, true); self.flag(TCTL, TCTL_EN, true); self.flag(TCTL, TCTL_PSP, true); // TCTL.CT = Collition threshold // TCTL.COLD = Collision distance // TIPG Packet Gap // TODO ... } }