use super::e1000_const::*;
use super::super::Ext;
use super::super::Volatile;
use alloc::vec::Vec;
use core::{cmp::min, mem::size_of, slice::from_raw_parts_mut};
use crate::utils::*;
const TX_RING_SIZE: usize = 256;
const RX_RING_SIZE: usize = 256;
const MBUF_SIZE: usize = 2048;
pub trait KernelFunc {
const PAGE_SIZE: usize = 4096;
fn dma_alloc_coherent(&mut self, pages: usize) -> (usize, usize);
fn dma_free_coherent(&mut self, vaddr: usize, pages: usize);
}
pub struct E1000Device<'a, K: KernelFunc> {
regs: &'static mut [Volatile<u32>],
rx_ring_dma: usize,
tx_ring_dma: usize,
rx_ring: &'a mut [RxDesc], tx_ring: &'a mut [TxDesc],
rx_mbufs: Vec<usize>,
tx_mbufs: Vec<usize>,
mbuf_size: usize,
kfn: K,
}
#[derive(Debug, Clone)]
#[repr(C, align(16))]
pub struct TxDesc {
addr: u64,
length: u16,
cso: u8,
cmd: u8,
status: u8,
css: u8,
special: u16,
}
#[derive(Debug, Clone)]
#[repr(C, align(16))]
pub struct RxDesc {
addr: u64,
length: u16,
csum: u16,
status: u8,
errors: u8,
special: u16,
}
impl<'a, K: KernelFunc> E1000Device<'a, K> {
pub fn new(mut kfn: K, mapped_regs: usize) -> Result<Self, i32> {
info!("New E1000 device @ {:#x}", mapped_regs);
let alloc_tx_ring_pages =
((TX_RING_SIZE * size_of::<TxDesc>()) + (K::PAGE_SIZE - 1)) / K::PAGE_SIZE;
let alloc_rx_ring_pages =
((RX_RING_SIZE * size_of::<RxDesc>()) + (K::PAGE_SIZE - 1)) / K::PAGE_SIZE;
let (tx_ring_vaddr, tx_ring_dma) = kfn.dma_alloc_coherent(alloc_tx_ring_pages);
let (rx_ring_vaddr, rx_ring_dma) = kfn.dma_alloc_coherent(alloc_rx_ring_pages);
let tx_ring = unsafe { from_raw_parts_mut(tx_ring_vaddr as *mut TxDesc, TX_RING_SIZE) };
let rx_ring = unsafe { from_raw_parts_mut(rx_ring_vaddr as *mut RxDesc, RX_RING_SIZE) };
tx_ring.fill(TxDesc {
addr: 0,
length: 0,
cso: 0,
cmd: 0,
status: 0,
css: 0,
special: 0,
});
rx_ring.fill(RxDesc {
addr: 0,
length: 0,
csum: 0,
status: 0,
errors: 0,
special: 0,
});
let mut tx_mbufs = Vec::with_capacity(tx_ring.len());
let mut rx_mbufs = Vec::with_capacity(rx_ring.len());
let alloc_tx_buffer_pages =
((TX_RING_SIZE * MBUF_SIZE) + (K::PAGE_SIZE - 1)) / K::PAGE_SIZE;
let (mut tx_mbufs_vaddr, mut tx_mbufs_dma) = kfn.dma_alloc_coherent(alloc_tx_buffer_pages);
for i in 0..TX_RING_SIZE {
tx_ring[i].status = E1000_TXD_STAT_DD as u8;
tx_ring[i].addr = tx_mbufs_dma as u64;
tx_mbufs.push(tx_mbufs_vaddr);
tx_mbufs_dma += MBUF_SIZE;
tx_mbufs_vaddr += MBUF_SIZE;
}
let alloc_rx_buffer_pages =
((RX_RING_SIZE * MBUF_SIZE) + (K::PAGE_SIZE - 1)) / K::PAGE_SIZE;
let (mut rx_mbufs_vaddr, mut rx_mbufs_dma) = kfn.dma_alloc_coherent(alloc_rx_buffer_pages);
if rx_mbufs_vaddr == 0 {
panic!("e1000, alloc dma rx buffer failed");
}
for i in 0..RX_RING_SIZE {
rx_ring[i].addr = rx_mbufs_dma as u64;
rx_mbufs.push(rx_mbufs_vaddr);
rx_mbufs_dma += MBUF_SIZE;
rx_mbufs_vaddr += MBUF_SIZE;
}
let len = 0x1FFFF / size_of::<u32>();
let regs = unsafe { from_raw_parts_mut(mapped_regs as *mut Volatile<u32>, len) };
let mut e1000dev = E1000Device {
regs,
rx_ring_dma,
tx_ring_dma,
rx_ring,
tx_ring,
rx_mbufs,
tx_mbufs,
mbuf_size: MBUF_SIZE,
kfn,
};
e1000dev.e1000_init();
Ok(e1000dev)
}
pub fn e1000_init(&mut self) {
let stat = self.regs[E1000_STAT].read();
let ctl = self.regs[E1000_CTL].read();
info!("e1000 CTL: {:#x}, Status: {:#x}", ctl, stat);
self.regs[E1000_IMS].write(0); self.regs[E1000_CTL].write(ctl | E1000_CTL_RST);
self.regs[E1000_IMS].write(0);
fence_w();
if (self.tx_ring.len() * size_of::<TxDesc>()) % 128 != 0 {
error!("e1000, size of tx_ring is invalid");
}
self.regs[E1000_TDBAL].write(self.tx_ring_dma as u32);
self.regs[E1000_TDLEN].write((self.tx_ring.len() * size_of::<TxDesc>()) as u32);
self.regs[E1000_TDT].write(0);
self.regs[E1000_TDH].write(0);
if (self.rx_ring.len() * size_of::<RxDesc>()) % 128 != 0 {
error!("e1000, size of rx_ring is invalid");
}
self.regs[E1000_RDBAL].write(self.rx_ring_dma as u32);
self.regs[E1000_RDH].write(0);
self.regs[E1000_RDT].write((RX_RING_SIZE - 1) as u32);
self.regs[E1000_RDLEN].write((self.rx_ring.len() * size_of::<RxDesc>()) as u32);
self.regs[E1000_RA].write(0x12005452);
self.regs[E1000_RA + 1].write(0x5534 | (1 << 31));
for i in 0..(4096 / 32) {
self.regs[E1000_MTA + i].write(0);
}
self.regs[E1000_TCTL].write(
E1000_TCTL_EN | E1000_TCTL_PSP | (0x10 << E1000_TCTL_CT_SHIFT) | (0x40 << E1000_TCTL_COLD_SHIFT),
);
self.regs[E1000_TIPG].write(10 | (8 << 10) | (6 << 20));
self.regs[E1000_RCTL].write(
E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | E1000_RCTL_SECRC,
);
self.regs[E1000_TIDV].write(0);
self.regs[E1000_TADV].write(0);
self.regs[E1000_RDTR].write(0); self.regs[E1000_RADV].write(0); self.regs[E1000_IMS].write(1 << 7);
self.regs[E1000_ICR].read(); self.e1000_write_flush();
info!("e1000_init has been completed");
}
pub fn e1000_transmit(&mut self, packet: &[u8]) -> i32 {
let tindex = self.regs[E1000_TDT].read() as usize;
info!("Read E1000_TDT = {:#x}", tindex);
if (self.tx_ring[tindex].status & E1000_TXD_STAT_DD as u8) == 0 {
error!("E1000 hasn't finished the corresponding previous transmission request");
return -1;
}
let mut length = packet.len();
if length > self.mbuf_size {
error!("The packet: {} to be send is TOO LARGE", length);
length = min(length, self.mbuf_size);
}
let mbuf = unsafe { from_raw_parts_mut(self.tx_mbufs[tindex] as *mut u8, length) };
mbuf.copy_from_slice(packet);
info!(">>>>>>>>> TX PKT {}", length);
info!("\n\r");
self.tx_ring[tindex].length = length as u16;
self.tx_ring[tindex].status = 0;
self.tx_ring[tindex].cmd = (E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP) as u8;
self.regs[E1000_TDT].write(((tindex + 1) % TX_RING_SIZE) as u32);
self.e1000_write_flush();
fence_w();
length as i32
}
pub fn e1000_recv(&mut self) -> Option<Vec<Vec<u8>>> {
let mut recv_packets = Vec::new();
let mut rindex = (self.regs[E1000_RDT].read() as usize + 1) % RX_RING_SIZE;
while (self.rx_ring[rindex].status & E1000_RXD_STAT_DD as u8) != 0 {
info!("Read E1000_RDT + 1 = {:#x}", rindex);
let len = self.rx_ring[rindex].length as usize;
let mbuf = unsafe { from_raw_parts_mut(self.rx_mbufs[rindex] as *mut u8, len) };
info!("RX PKT {} <<<<<<<<<", len);
recv_packets.push(mbuf.to_vec());
net_rx(mbuf);
fence();
mbuf[..min(64, len)].fill(0);
self.rx_ring[rindex].status = 0;
self.regs[E1000_RDT].write(rindex as u32);
self.e1000_write_flush();
fence_w();
rindex = (rindex + 1) % RX_RING_SIZE;
}
info!("e1000_recv\n\r");
if recv_packets.len() > 0 {
Some(recv_packets)
} else {
None
}
}
pub fn e1000_irq_disable(&mut self) {
self.regs[E1000_IMC].write(!0);
self.e1000_write_flush();
}
pub fn e1000_irq_enable(&mut self) {
self.regs[E1000_IMS].write(IMS_ENABLE_MASK);
self.e1000_write_flush();
}
pub fn e1000_write_flush(&mut self) {
self.regs[E1000_STAT].read();
}
pub fn e1000_cause_lsc_int(&mut self) {
self.regs[E1000_ICS].write(E1000_ICR_LSC);
}
pub fn e1000_intr(&mut self) -> u32 {
self.regs[E1000_ICR].read()
}
}
pub fn net_rx(packet: &mut [u8]) {
}