#![allow(dead_code)]
use alloc::boxed::Box;
use core::mem;
use pci_types::{Bar, InterruptLine, MAX_BARS};
use x86::io::*;
use crate::arch::kernel::core_local::increment_irq_counter;
use crate::arch::kernel::interrupts::*;
use crate::arch::mm::paging::virt_to_phys;
use crate::arch::mm::VirtAddr;
use crate::arch::pci::PciConfigRegion;
use crate::drivers::error::DriverError;
use crate::drivers::net::{network_irqhandler, NetworkDriver};
use crate::drivers::pci::{PciCommand, PciDevice};
use crate::executor::device::{RxToken, TxToken};
const RX_BUF_LEN: usize = 8192;
const TX_BUF_LEN: usize = 4096;
const IDR0: u16 = 0x0;
const TSD0: u16 = 0x10;
const TSAD0: u16 = 0x20;
const TSAD1: u16 = 0x24;
const TNPDS: u16 = 0x20;
const TSAD2: u16 = 0x28;
const TSAD3: u16 = 0x2c;
const CR: u16 = 0x37;
const CAPR: u16 = 0x38;
const IMR: u16 = 0x3c;
const ISR: u16 = 0x3e;
const TCR: u16 = 0x40;
const RCR: u16 = 0x44;
const CR9346: u16 = 0x50;
const CONFIG0: u16 = 0x51;
const CONFIG1: u16 = 0x52;
const MSR: u16 = 0x58;
const RBSTART: u16 = 0x30;
const BMCR: u16 = 0x62;
const BMSR: u16 = 0x64;
const CR_RST: u8 = 0x10;
const CR_RE: u8 = 0x08;
const CR_TE: u8 = 0x04;
const CR_BUFE: u8 = 0x01;
const CR9346_EEM1: u8 = 0x80;
const CR9346_EEM0: u8 = 0x40;
const CR9346_EESK: u8 = 0x4;
const CR9346_EEDI: u8 = 0x2;
const CR9346_EEDO: u8 = 0x1;
const CONFIG1_LEDS: u8 = 0xC0;
const CONFIG1_DVRLOAD: u8 = 0x20;
const CONFIG1_LWACT: u8 = 0x10;
const CONFIG1_MEMMAP: u8 = 0x8;
const CONFIG1_IOMAP: u8 = 0x4;
const CONFIG1_VPD: u8 = 0x2;
const CONFIG1_PMEN: u8 = 0x1;
const MSR_TXFCE: u8 = 0x80; const MSR_RXFCE: u8 = 0x40; const MSR_AS: u8 = 0x10; const MSR_SPEED: u8 = 0x8; const MSR_LINKB: u8 = 0x4; const MSR_TXPF: u8 = 0x2; const MSR_RXPF: u8 = 0x1;
const RCR_ERTH3: u32 = 0x0800_0000; const RCR_ERTH2: u32 = 0x0400_0000; const RCR_ERTH1: u32 = 0x0200_0000; const RCR_ERTH0: u32 = 0x0100_0000; const RCR_MRINT: u32 = 0x20000; const RCR_RER8: u32 = 0x10000; const RCR_RXFTH2: u32 = 0x8000; const RCR_RXFTH1: u32 = 0x4000; const RCR_RXFTH0: u32 = 0x2000; const RCR_RBLEN1: u32 = 0x1000; const RCR_RBLEN0: u32 = 0x800; const RCR_MXDMA2: u32 = 0x400; const RCR_MXDMA1: u32 = 0x200; const RCR_MXDMA0: u32 = 0x100; const RCR_WRAP: u32 = 0x80; const RCR_EEPROMSEL: u32 = 0x40; const RCR_AER: u32 = 0x20; const RCR_AR: u32 = 0x10; const RCR_AB: u32 = 0x08; const RCR_AM: u32 = 0x04; const RCR_APM: u32 = 0x02; const RCR_AAP: u32 = 0x01;
const TCR_HWVERID: u32 = 0x7CC0_0000; const TCR_HWOFFSET: u32 = 22;
const TCR_IFG: u32 = 0x0300_0000; const TCR_LBK1: u32 = 0x40000; const TCR_LBK0: u32 = 0x20000; const TCR_CRC: u32 = 0x10000; const TCR_MXDMA2: u32 = 0x400; const TCR_MXDMA1: u32 = 0x200; const TCR_MXDMA0: u32 = 0x100; const TCR_TXRR: u32 = 0xF0; const TCR_CLRABT: u32 = 0x01;
const BMCR_RESET: u16 = 0x8000; const BMCR_SPD100: u16 = 1 << 13; const BMCR_SPD1000: u16 = 1 << 6; const BMCR_ANE: u16 = 0x1000; const BMCR_RAN: u16 = 0x400; const BMCR_DUPLEX: u16 = 0x200;
const ISR_SERR: u16 = 0x8000; const ISR_TUN: u16 = 0x4000; const ISR_SWINT: u16 = 0x100; const ISR_TDU: u16 = 0x80; const ISR_FIFOOVW: u16 = 0x40; const ISR_PUN: u16 = 0x20; const ISR_RXOVW: u16 = 0x10; const ISR_TER: u16 = 0x08; const ISR_TOK: u16 = 0x04; const ISR_RER: u16 = 0x02; const ISR_ROK: u16 = 0x01; const R39_INTERRUPT_MASK: u16 = 0x7f;
const TSD_CRS: u32 = 1 << 31; const TSD_TABT: u32 = 1 << 30; const TSD_OWC: u32 = 1 << 29; const TSD_CDH: u32 = 1 << 28; const TSD_NCC: u32 = 0x0F00_0000; const TSD_EARTH: u32 = 0x003F_0000; const TSD_TOK: u32 = 1 << 15; const TSD_TUN: u32 = 1 << 14; const TSD_OWN: u32 = 1 << 13; const TSD_SIZE: u32 = 0x1fff;
const INT_MASK: u16 = ISR_ROK | ISR_TOK | ISR_RXOVW | ISR_TER | ISR_RER;
const INT_MASK_NO_ROK: u16 = ISR_TOK | ISR_RXOVW | ISR_TER | ISR_RER;
const NO_TX_BUFFERS: usize = 4;
#[derive(Debug)]
pub enum RTL8139Error {
InitFailed,
ResetFailed,
Unknown,
}
pub(crate) struct RTL8139Driver {
iobase: u16,
mtu: u16,
irq: InterruptLine,
mac: [u8; 6],
tx_in_use: [bool; NO_TX_BUFFERS],
tx_counter: usize,
rxbuffer: Box<[u8]>,
rxpos: usize,
txbuffer: Box<[u8]>,
}
impl NetworkDriver for RTL8139Driver {
fn get_mac_address(&self) -> [u8; 6] {
self.mac
}
fn get_mtu(&self) -> u16 {
self.mtu
}
fn send_packet<R, F>(&mut self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let id = self.tx_counter % NO_TX_BUFFERS;
if self.tx_in_use[id] || len > TX_BUF_LEN {
panic!("Unable to get TX buffer");
} else {
self.tx_in_use[id] = true;
self.tx_counter += 1;
let buffer = &mut self.txbuffer[id * TX_BUF_LEN..][..len];
let result = f(buffer);
unsafe {
outl(
self.iobase + TSD0 + (4 * id as u16),
len.try_into().unwrap(),
); }
result
}
}
fn has_packet(&self) -> bool {
let cmd = unsafe { inb(self.iobase + CR) };
if (cmd & CR_BUFE) != CR_BUFE {
let header = self.rx_peek_u16();
if header & ISR_ROK == ISR_ROK {
return true;
}
}
false
}
fn receive_packet(&mut self) -> Option<(RxToken, TxToken)> {
let cmd = unsafe { inb(self.iobase + CR) };
if (cmd & CR_BUFE) != CR_BUFE {
let header = self.rx_peek_u16();
self.advance_rxpos(mem::size_of::<u16>());
if header & ISR_ROK == ISR_ROK {
let length = self.rx_peek_u16() - 4; let pos = (self.rxpos + mem::size_of::<u16>()) % RX_BUF_LEN;
let vec_data = if pos + length as usize > RX_BUF_LEN {
let first = &self.rxbuffer[pos..RX_BUF_LEN];
let second = &self.rxbuffer[..length as usize - first.len()];
[first, second].concat()
} else {
(self.rxbuffer[pos..][..length.into()]).to_vec()
};
self.consume_current_buffer();
Some((RxToken::new(vec_data), TxToken::new()))
} else {
warn!(
"RTL8192: invalid header {:#x}, rx_pos {}\n",
header, self.rxpos
);
None
}
} else {
None
}
}
fn set_polling_mode(&mut self, value: bool) {
if value {
unsafe {
outw(self.iobase + IMR, INT_MASK_NO_ROK);
}
} else {
unsafe {
outw(self.iobase + IMR, INT_MASK);
}
}
}
fn handle_interrupt(&mut self) -> bool {
increment_irq_counter(32 + self.irq);
let isr_contents = unsafe { inw(self.iobase + ISR) };
if (isr_contents & ISR_TOK) == ISR_TOK {
self.tx_handler();
}
if (isr_contents & ISR_RER) == ISR_RER {
error!("RTL88139: RX error detected!\n");
}
if (isr_contents & ISR_TER) == ISR_TER {
trace!("RTL88139r: TX error detected!\n");
}
if (isr_contents & ISR_RXOVW) == ISR_RXOVW {
trace!("RTL88139: RX overflow detected!\n");
}
let ret = (isr_contents & ISR_ROK) == ISR_ROK;
unsafe {
outw(
self.iobase + ISR,
isr_contents & (ISR_RXOVW | ISR_TER | ISR_RER | ISR_TOK | ISR_ROK),
);
}
ret
}
}
impl RTL8139Driver {
fn consume_current_buffer(&mut self) {
let length = self.rx_peek_u16();
self.advance_rxpos(usize::from(length) + mem::size_of::<u16>());
self.rxpos = ((self.rxpos + 3) & !0x3) % RX_BUF_LEN;
if self.rxpos >= 0x10 {
unsafe {
outw(self.iobase + CAPR, (self.rxpos - 0x10).try_into().unwrap());
}
} else {
unsafe {
outw(
self.iobase + CAPR,
(RX_BUF_LEN - (0x10 - self.rxpos)).try_into().unwrap(),
);
}
}
}
fn rx_peek_u16(&self) -> u16 {
u16::from_ne_bytes(
self.rxbuffer[self.rxpos..][..mem::size_of::<u16>()]
.try_into()
.unwrap(),
)
}
fn advance_rxpos(&mut self, count: usize) {
self.rxpos += count;
self.rxpos %= RX_BUF_LEN;
}
fn tx_handler(&mut self) {
for i in 0..self.tx_in_use.len() {
if self.tx_in_use[i] {
let txstatus = unsafe { inl(self.iobase + TSD0 + i as u16 * 4) };
if (txstatus & (TSD_TABT | TSD_OWC)) > 0 {
error!("RTL8139: major error");
continue;
}
if (txstatus & TSD_TUN) == TSD_TUN {
error!("RTL8139: transmit underrun");
}
if (txstatus & TSD_TOK) == TSD_TOK {
self.tx_in_use[i] = false;
}
}
}
}
}
impl Drop for RTL8139Driver {
fn drop(&mut self) {
debug!("Dropping RTL8129Driver!");
unsafe {
outb(self.iobase + CR, CR_RST);
}
}
}
pub(crate) fn init_device(
device: &PciDevice<PciConfigRegion>,
) -> Result<RTL8139Driver, DriverError> {
let irq = device.get_irq().unwrap();
let mut iobase: Option<u32> = None;
for i in 0..MAX_BARS {
if let Some(Bar::Io { port }) = device.get_bar(i.try_into().unwrap()) {
iobase = Some(port)
}
}
let iobase: u16 = iobase
.ok_or(DriverError::InitRTL8139DevFail(RTL8139Error::Unknown))?
.try_into()
.unwrap();
debug!("Found RTL8139 at iobase {:#x} (irq {})", iobase, irq);
device.set_command(PciCommand::PCI_COMMAND_MASTER);
let mac: [u8; 6] = unsafe {
[
inb(iobase + IDR0),
inb(iobase + IDR0 + 1),
inb(iobase + IDR0 + 2),
inb(iobase + IDR0 + 3),
inb(iobase + IDR0 + 4),
inb(iobase + IDR0 + 5),
]
};
debug!(
"MAC address {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
);
unsafe {
if inl(iobase + TCR) == 0x00FF_FFFFu32 {
error!("Unable to initialize RTL8192");
return Err(DriverError::InitRTL8139DevFail(RTL8139Error::InitFailed));
}
outb(iobase + CR, CR_RST);
crate::arch::kernel::processor::udelay(10000);
let mut tmp: u16 = 10000;
while (inb(iobase + CR) & CR_RST) == CR_RST && tmp > 0 {
tmp -= 1;
}
if tmp == 0 {
error!("RTL8139 reset failed");
return Err(DriverError::InitRTL8139DevFail(RTL8139Error::ResetFailed));
}
outb(iobase + CR, CR_TE | CR_RE);
outb(iobase + CR9346, CR9346_EEM1 | CR9346_EEM0);
outb(iobase + CONFIG1, 0);
outb(
iobase + CONFIG1,
(inb(iobase + CONFIG1) & !(CONFIG1_DVRLOAD | CONFIG1_LWACT)) | CONFIG1_DVRLOAD,
);
outb(iobase + CR9346, 0);
outl(
iobase + RCR,
RCR_MXDMA2 | RCR_MXDMA1 | RCR_MXDMA0 | RCR_AB | RCR_AM | RCR_APM | RCR_AAP,
);
outl(iobase + TCR, TCR_IFG | TCR_MXDMA0 | TCR_MXDMA1 | TCR_MXDMA2);
}
let rxbuffer = vec![0; RX_BUF_LEN].into_boxed_slice();
let txbuffer = vec![0; NO_TX_BUFFERS * TX_BUF_LEN].into_boxed_slice();
debug!(
"Allocate TxBuffer at {:p} and RxBuffer at {:p}",
txbuffer, rxbuffer
);
let phys_addr = |p| {
virt_to_phys(VirtAddr::from_usize(p as _))
.as_u64()
.try_into()
.unwrap()
};
unsafe {
outl(iobase + RBSTART, phys_addr(rxbuffer.as_ptr()));
outl(iobase + TSAD0, phys_addr(txbuffer[..TX_BUF_LEN].as_ptr()));
outl(
iobase + TSAD1,
phys_addr(txbuffer[TX_BUF_LEN..][..TX_BUF_LEN].as_ptr()),
);
outl(
iobase + TSAD2,
phys_addr(txbuffer[2 * TX_BUF_LEN..][..TX_BUF_LEN].as_ptr()),
);
outl(
iobase + TSAD3,
phys_addr(txbuffer[3 * TX_BUF_LEN..][..TX_BUF_LEN].as_ptr()),
);
outw(iobase + IMR, INT_MASK);
outw(iobase + BMCR, BMCR_ANE);
let speed;
let tmp = inw(iobase + BMCR);
if tmp & BMCR_SPD1000 == BMCR_SPD1000 {
speed = 1000;
} else if tmp & BMCR_SPD100 == BMCR_SPD100 {
speed = 100;
} else {
speed = 10;
}
outb(iobase + CR, CR_TE | CR_RE);
info!(
"RTL8139: CR = {:#x}, ISR = {:#x}, speed = {} mbps",
inb(iobase + CR),
inw(iobase + ISR),
speed
);
}
debug!("Install interrupt handler for RTL8139 at {}", irq);
irq_install_handler(irq, network_irqhandler);
add_irq_name(irq, "rtl8139_net");
Ok(RTL8139Driver {
iobase,
mtu: 1500,
irq,
mac,
tx_in_use: [false; NO_TX_BUFFERS],
tx_counter: 0,
rxbuffer,
rxpos: 0,
txbuffer,
})
}