diff --git a/Cargo.toml b/Cargo.toml index 8f95ce5..8726af2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,6 @@ members = [ resolver = "3" [workspace.dependencies] +futures = {version = "0.3", default-features = false} thiserror = {version = "2.0", default-features = false} -tock-registers = {version = "0.10"} \ No newline at end of file +tock-registers = {version = "0.10"} diff --git a/igb/Cargo.toml b/igb/Cargo.toml index c05dee8..b1e532f 100644 --- a/igb/Cargo.toml +++ b/igb/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" [dependencies] dma-api = {version = "0.3", features = ["alloc"]} +futures = {workspace = true} log = "0.4" mbarrier = "0.1" thiserror = {workspace = true} @@ -14,6 +15,8 @@ trait-ffi = "0.1" [dev-dependencies] bare-test = "0.4" pcie = "0.3" +smoltcp = {version = "0.12", default-features = false, features = ["alloc", "medium-ethernet", "proto-ipv4", "socket-icmp"]} +spin_on = "0.1" [build-dependencies] bare-test-macros = "0.2" diff --git a/igb/bare-test.toml b/igb/bare-test.toml index aa7228a..88db777 100644 --- a/igb/bare-test.toml +++ b/igb/bare-test.toml @@ -2,4 +2,4 @@ machine = "virt" cpu = "cortex-a53" graphic = false -args = "-netdev user,id=net0 -device igb,netdev=net0 -d trace:e1000*,trace:igb*" +args = "-netdev user,id=net0 -device igb,netdev=net0 -d trace:e1000*,trace:igb*,trace:*net*" diff --git a/igb/src/descriptor.rs b/igb/src/descriptor.rs new file mode 100644 index 0000000..4bf7406 --- /dev/null +++ b/igb/src/descriptor.rs @@ -0,0 +1,462 @@ +pub trait Descriptor {} + +// Advanced Receive Descriptor constants +pub mod rx_desc_consts { + // Read Format bit masks + pub const ADDR_MASK: u64 = 0xFFFF_FFFF_FFFF_FFFE; // Address bits [63:1] + pub const NSE_MASK: u64 = 0x0000_0000_0000_0001; // No-Snoop Enable bit [0] + pub const DD_MASK: u64 = 0x0000_0000_0000_0001; // Descriptor Done bit [0] + + // Write-back Format bit masks and shifts + // Low DWORD (63:0) + pub const RSS_HASH_MASK: u32 = 0xFFFF_FFFF; // RSS Hash [31:0] + pub const FRAG_CSUM_MASK: u32 = 0xFFFF_0000; // Fragment Checksum [31:16] + pub const FRAG_CSUM_SHIFT: u32 = 16; + pub const IP_ID_MASK: u32 = 0x0000_FFFF; // IP identification [15:0] + + // 注意:根据Intel文档,位字段应该是: + // 63:48 - RSS Hash/Fragment Checksum (高16位) + // 47:32 - IP identification + // 31:22 - HDR_LEN (Header Length) + // 21 - SPH (Split Header) + // 20:0 - Extended Status + pub const HDR_LEN_MASK: u32 = 0xFFC0_0000; // Header Length [31:22] + pub const HDR_LEN_SHIFT: u32 = 22; + pub const SPH_MASK: u32 = 0x0020_0000; // Split Header [21] + pub const SPH_SHIFT: u32 = 21; + pub const EXT_STATUS_LO_MASK: u32 = 0x001F_FFFF; // Extended Status [20:0] + + // High DWORD (127:64) + // 63:48 - VLAN Tag + // 47:32 - PKT_LEN (Packet Length) + // 31:20 - Extended Error + // 19:17 - RSS Type + // 16:4 - Packet Type + // 3:0 - Extended Status + pub const EXT_ERROR_MASK: u32 = 0xFFF0_0000; // Extended Error [31:20] + pub const EXT_ERROR_SHIFT: u32 = 20; + pub const RSS_TYPE_MASK: u32 = 0x000E_0000; // RSS Type [19:17] + pub const RSS_TYPE_SHIFT: u32 = 17; + pub const PKT_TYPE_MASK: u32 = 0x0001_FFF0; // Packet Type [16:4] + pub const PKT_TYPE_SHIFT: u32 = 4; + pub const EXT_STATUS_HI_MASK: u32 = 0x0000_000F; // Extended Status [3:0] + + pub const VLAN_TAG_MASK: u32 = 0xFFFF_0000; // VLAN Tag [31:16] + pub const VLAN_TAG_SHIFT: u32 = 16; + pub const PKT_LEN_MASK: u32 = 0x0000_FFFF; // Packet Length [15:0] + + // Extended Status bits + pub const DD_BIT: u32 = 1 << 0; // Descriptor Done + pub const EOP_BIT: u32 = 1 << 1; // End of Packet + pub const VP_BIT: u32 = 1 << 3; // VLAN Packet + pub const UDPCS_BIT: u32 = 1 << 4; // UDP Checksum + pub const L4I_BIT: u32 = 1 << 5; // L4 Integrity check + pub const IPCS_BIT: u32 = 1 << 6; // IP Checksum + pub const PIF_BIT: u32 = 1 << 7; // Passed In-exact Filter + pub const VEXT_BIT: u32 = 1 << 9; // First VLAN on double VLAN + pub const UDPV_BIT: u32 = 1 << 10; // UDP Valid + pub const LLINT_BIT: u32 = 1 << 11; // Low Latency Interrupt + pub const SECP_BIT: u32 = 1 << 17; // Security Processing + pub const LB_BIT: u32 = 1 << 18; // Loopback + pub const TS_BIT: u32 = 1 << 16; // Time Stamped + + // Extended Error bits + pub const HBO_BIT: u32 = 1 << 3; // Header Buffer Overflow + pub const SECERR_MASK: u32 = 0x0000_0180; // Security Error [8:7] + pub const SECERR_SHIFT: u32 = 7; + pub const L4E_BIT: u32 = 1 << 9; // L4 Error + pub const IPE_BIT: u32 = 1 << 10; // IP Error + pub const RXE_BIT: u32 = 1 << 11; // RX Error +} + +// Advanced Transmit Descriptor constants +pub mod tx_desc_consts { + // CMD_TYPE_LEN field bits + pub const CMD_EOP: u32 = 1 << 24; // End of Packet + pub const CMD_IFCS: u32 = 1 << 25; // Insert FCS + pub const CMD_IC: u32 = 1 << 26; // Insert Checksum + pub const CMD_RS: u32 = 1 << 27; // Report Status + pub const CMD_DEXT: u32 = 1 << 29; // Descriptor Extension + pub const CMD_VLE: u32 = 1 << 30; // VLAN Packet Enable + pub const CMD_IDE: u32 = 1 << 31; // Interrupt Delay Enable + + // Descriptor types + pub const DTYPE_DATA: u32 = 0b11 << 20; // Data descriptor + pub const DTYPE_CONTEXT: u32 = 0b10 << 20; // Context descriptor + + // Length mask + pub const LEN_MASK: u32 = 0x000F_FFFF; // Packet Length [19:0] + + // Status bits in write-back format + pub const DD_BIT: u32 = 1 << 0; // Descriptor Done +} + +/// RSS类型枚举 +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum RssType { + None = 0x0, + HashTcpIpv4 = 0x1, + HashIpv4 = 0x2, + HashTcpIpv6 = 0x3, + HashIpv6Ex = 0x4, + HashIpv6 = 0x5, + HashTcpIpv6Ex = 0x6, + HashUdpIpv4 = 0x7, + HashUdpIpv6 = 0x8, + HashUdpIpv6Ex = 0x9, + Reserved(u8), +} + +impl From for RssType { + fn from(val: u8) -> Self { + match val { + 0x0 => RssType::None, + 0x1 => RssType::HashTcpIpv4, + 0x2 => RssType::HashIpv4, + 0x3 => RssType::HashTcpIpv6, + 0x4 => RssType::HashIpv6Ex, + 0x5 => RssType::HashIpv6, + 0x6 => RssType::HashTcpIpv6Ex, + 0x7 => RssType::HashUdpIpv4, + 0x8 => RssType::HashUdpIpv6, + 0x9 => RssType::HashUdpIpv6Ex, + _ => RssType::Reserved(val), + } + } +} + +/// 安全错误类型枚举 +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SecurityError { + None = 0b00, + NoSaMatch = 0b01, + ReplayError = 0b10, + BadSignature = 0b11, +} + +impl From for SecurityError { + fn from(val: u8) -> Self { + match val & 0b11 { + 0b00 => SecurityError::None, + 0b01 => SecurityError::NoSaMatch, + 0b10 => SecurityError::ReplayError, + 0b11 => SecurityError::BadSignature, + _ => unreachable!(), + } + } +} + +#[derive(Clone, Copy)] +pub union AdvTxDesc { + pub read: AdvTxDescRead, + pub write: AdvTxDescWB, +} + +impl Descriptor for AdvTxDesc {} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct AdvTxDescRead { + pub buffer_addr: u64, + pub cmd_type_len: u32, + pub olinfo_status: u32, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct AdvTxDescWB { + pub rsvd: u64, + pub nxtseq_seed: u32, + pub status: u32, +} + +/// Advanced Receive Descriptor (82576EB) +/// +/// 这个联合体表示Intel 82576EB控制器的高级接收描述符, +/// 支持软件写入格式(Read Format)和硬件写回格式(Write-back Format) +/// +/// 根据Intel 82576EB GbE Controller文档第7.1.5节: +/// - Read Format: 软件写入描述符队列,硬件从主机内存读取 +/// - Write-back Format: 硬件写回描述符到主机内存 +#[derive(Clone, Copy)] +pub union AdvRxDesc { + /// 软件写入格式 - 提供包和头部缓冲区地址 + pub read: AdvRxDescRead, + /// 硬件写回格式 - 包含接收状态、长度、校验和等信息 + pub write: AdvRxDescWB, +} + +impl Descriptor for AdvRxDesc {} + +/// Advanced Receive Descriptor Read Format (软件写入格式) +/// +/// 根据Intel 82576EB文档Table 7-10,这是软件写入描述符队列的格式: +/// +/// ```text +/// 63 0 +/// +------------------------------------------------------------------+ +/// | Packet Buffer Address [63:1] | A0/NSE| +/// +------------------------------------------------------------------+ +/// | Header Buffer Address [63:1] | DD | +/// +------------------------------------------------------------------+ +/// ``` +/// +/// - Packet Buffer Address: 包缓冲区的物理地址 +/// - A0/NSE: 最低位是地址位A0或No-Snoop Enable位 +/// - Header Buffer Address: 头部缓冲区的物理地址 +/// - DD: Descriptor Done位,硬件写回时设置 +#[derive(Clone, Copy)] +#[repr(C)] +pub struct AdvRxDescRead { + /// Packet Buffer Address [63:1] + A0/NSE [0] + /// 物理地址的最低位是 A0 (地址的LSB) 或 NSE (No-Snoop Enable) + pub pkt_addr: u64, + /// Header Buffer Address [63:1] + DD [0] + /// 头部缓冲区物理地址,最低位是 DD (Descriptor Done) + pub hdr_addr: u64, +} +/// Advanced Receive Descriptor Write-back Format (硬件写回格式) +/// +/// 根据Intel 82576EB文档Table 7-11,这是硬件写回到主机内存的格式: +/// +/// ```text +/// 127 64 +/// +------------------------------------------------------------------+ +/// | VLAN Tag | PKT_LEN |Ext Err|RSS|Pkt Type|Ext Status | +/// +------------------------------------------------------------------+ +/// 63 48 47 32 31 21 20 19 17 16 0 +/// +------------------------------------------------------------------+ +/// |RSS Hash/Frag | IP ID |HDR_LEN|S| RSV |Ext Status | +/// | Checksum | | |P| | | +/// +------------------------------------------------------------------+ +/// ``` +/// +/// 字段说明: +/// - RSS Hash/Fragment Checksum: RSS哈希值或片段校验和 +/// - IP ID: IP标识符(用于片段重组) +/// - HDR_LEN: 头部长度 +/// - SPH: Split Header位 +/// - PKT_LEN: 包长度 +/// - VLAN Tag: VLAN标签 +/// - Ext Status: 扩展状态(包含DD、EOP等位) +/// - Ext Error: 扩展错误信息 +/// - RSS Type: RSS类型 +/// - Pkt Type: 包类型 +#[derive(Clone, Copy)] +#[repr(C)] +pub struct AdvRxDescWB { + /// Lower 64 bits of write-back descriptor + /// 63:48 - RSS Hash Value/Fragment Checksum + /// 47:32 - IP identification + /// 31:21 - HDR_LEN (Header Length) + /// 20 - SPH (Split Header) + /// 19:0 - Extended Status + pub lo_dword: LoDword, + /// Upper 64 bits of write-back descriptor + /// 63:48 - VLAN Tag + /// 47:32 - PKT_LEN (Packet Length) + /// 31:20 - Extended Error + /// 19:17 - RSS Type + /// 16:4 - Packet Type + /// 3:0 - Extended Status + pub hi_dword: HiDword, +} + +#[derive(Clone, Copy)] +pub union LoDword { + /// 完整的64位数据 + pub data: u64, + /// RSS Hash / Fragment Checksum + IP identification + HDR_LEN + SPH + Extended Status + pub fields: LoFields, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct LoFields { + /// 31:0 - RSS Hash Value (32-bit) 或 Fragment Checksum (16-bit, 31:16) + IP identification (16-bit, 15:0) + pub rss_hash_or_csum_ip: u32, + /// 63:32 - HDR_LEN (31:22) + SPH (21) + RSV (20:17) + Extended Status (16:0) + pub hdr_status: u32, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub union HiDword { + /// 完整的64位数据 + pub data: u64, + /// 分解的字段 + pub fields: HiFields, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct HiFields { + /// 31:0 - Extended Error (31:20) + RSS Type (19:17) + Packet Type (16:4) + Extended Status (3:0) + pub error_type_status: u32, + /// 63:32 - VLAN Tag (31:16) + PKT_LEN (15:0) + pub vlan_length: u32, +} + +impl AdvRxDescRead { + /// 创建新的接收描述符 + pub fn new(pkt_addr: u64, hdr_addr: u64, nse: bool) -> Self { + let pkt_addr = if nse { + pkt_addr | rx_desc_consts::NSE_MASK + } else { + pkt_addr & !rx_desc_consts::NSE_MASK + }; + + Self { + pkt_addr, + hdr_addr: hdr_addr & !rx_desc_consts::DD_MASK, // 确保DD位为0 + } + } + + /// 获取包缓冲区地址 + pub fn packet_buffer_addr(&self) -> u64 { + self.pkt_addr & rx_desc_consts::ADDR_MASK + } + + /// 获取头部缓冲区地址 + pub fn header_buffer_addr(&self) -> u64 { + self.hdr_addr & rx_desc_consts::ADDR_MASK + } + + /// 检查是否启用了No-Snoop + pub fn no_snoop_enabled(&self) -> bool { + self.pkt_addr & rx_desc_consts::NSE_MASK != 0 + } +} + +impl AdvRxDescWB { + /// 检查描述符是否已完成 (DD bit) + pub fn is_done(&self) -> bool { + unsafe { self.hi_dword.fields.error_type_status & rx_desc_consts::DD_BIT != 0 } + } + + /// 检查是否为包的最后一个描述符 (EOP bit) + pub fn is_end_of_packet(&self) -> bool { + unsafe { self.hi_dword.fields.error_type_status & rx_desc_consts::EOP_BIT != 0 } + } + + /// 获取包长度 + pub fn packet_length(&self) -> u16 { + unsafe { (self.hi_dword.fields.vlan_length & rx_desc_consts::PKT_LEN_MASK) as u16 } + } + + /// 获取VLAN标签 + pub fn vlan_tag(&self) -> u16 { + unsafe { + ((self.hi_dword.fields.vlan_length & rx_desc_consts::VLAN_TAG_MASK) + >> rx_desc_consts::VLAN_TAG_SHIFT) as u16 + } + } + + /// 获取RSS哈希值 + pub fn rss_hash(&self) -> u32 { + unsafe { self.lo_dword.fields.rss_hash_or_csum_ip } + } + + /// 获取头部长度 + pub fn header_length(&self) -> u16 { + unsafe { + ((self.lo_dword.fields.hdr_status & rx_desc_consts::HDR_LEN_MASK) + >> rx_desc_consts::HDR_LEN_SHIFT) as u16 + } + } + + /// 检查是否分割头部 (SPH bit) + pub fn is_split_header(&self) -> bool { + unsafe { self.lo_dword.fields.hdr_status & rx_desc_consts::SPH_MASK != 0 } + } + + /// 获取包类型 + pub fn packet_type(&self) -> u16 { + unsafe { + ((self.hi_dword.fields.error_type_status & rx_desc_consts::PKT_TYPE_MASK) + >> rx_desc_consts::PKT_TYPE_SHIFT) as u16 + } + } + + /// 获取RSS类型 + pub fn rss_type(&self) -> u8 { + unsafe { + ((self.hi_dword.fields.error_type_status & rx_desc_consts::RSS_TYPE_MASK) + >> rx_desc_consts::RSS_TYPE_SHIFT) as u8 + } + } + + /// 检查是否有错误 + pub fn has_errors(&self) -> bool { + unsafe { + (self.hi_dword.fields.error_type_status & rx_desc_consts::EXT_ERROR_MASK) != 0 + || (self.hi_dword.fields.error_type_status + & (rx_desc_consts::L4E_BIT | rx_desc_consts::IPE_BIT | rx_desc_consts::RXE_BIT)) + != 0 + } + } + + /// 检查IP校验和是否有效 + pub fn ip_checksum_valid(&self) -> bool { + unsafe { + (self.hi_dword.fields.error_type_status & rx_desc_consts::IPCS_BIT) != 0 + && (self.hi_dword.fields.error_type_status & rx_desc_consts::IPE_BIT) == 0 + } + } + + /// 检查L4校验和是否有效 + pub fn l4_checksum_valid(&self) -> bool { + unsafe { + (self.hi_dword.fields.error_type_status & rx_desc_consts::L4I_BIT) != 0 + && (self.hi_dword.fields.error_type_status & rx_desc_consts::L4E_BIT) == 0 + } + } + + /// 获取RSS类型枚举 + pub fn rss_type_enum(&self) -> RssType { + RssType::from(self.rss_type()) + } + + /// 获取安全错误类型 + pub fn security_error(&self) -> SecurityError { + unsafe { + let error_bits = (self.hi_dword.fields.error_type_status & rx_desc_consts::SECERR_MASK) + >> rx_desc_consts::SECERR_SHIFT; + SecurityError::from(error_bits as u8) + } + } + + /// 检查是否有头部缓冲区溢出 + pub fn has_header_buffer_overflow(&self) -> bool { + unsafe { (self.hi_dword.fields.error_type_status & rx_desc_consts::HBO_BIT) != 0 } + } + + /// 检查是否为VLAN包 + pub fn is_vlan_packet(&self) -> bool { + unsafe { (self.hi_dword.fields.error_type_status & rx_desc_consts::VP_BIT) != 0 } + } + + /// 检查是否为回环包 + pub fn is_loopback_packet(&self) -> bool { + unsafe { (self.hi_dword.fields.error_type_status & rx_desc_consts::LB_BIT) != 0 } + } + + /// 检查是否为时间戳包 + pub fn is_timestamped(&self) -> bool { + unsafe { (self.hi_dword.fields.error_type_status & rx_desc_consts::TS_BIT) != 0 } + } + + /// 获取片段校验和(当不使用RSS时) + pub fn fragment_checksum(&self) -> u16 { + unsafe { + ((self.lo_dword.fields.rss_hash_or_csum_ip & rx_desc_consts::FRAG_CSUM_MASK) + >> rx_desc_consts::FRAG_CSUM_SHIFT) as u16 + } + } + + /// 获取IP标识符(当不使用RSS时) + pub fn ip_identification(&self) -> u16 { + unsafe { (self.lo_dword.fields.rss_hash_or_csum_ip & rx_desc_consts::IP_ID_MASK) as u16 } + } +} diff --git a/igb/src/err.rs b/igb/src/err.rs index b0fb06d..9842f0a 100644 --- a/igb/src/err.rs +++ b/igb/src/err.rs @@ -4,4 +4,8 @@ pub enum DError { Unknown(&'static str), #[error("Operation timed out")] Timeout, + #[error("No memory available")] + NoMemory, + #[error("Invalid parameter")] + InvalidParameter, } diff --git a/igb/src/lib.rs b/igb/src/lib.rs index f55b688..0ec8ca8 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -1,13 +1,13 @@ #![no_std] -use core::{cell::RefCell, ptr::NonNull}; +use core::ptr::NonNull; use log::debug; pub use mac::{MacAddr6, MacStatus}; -use tock_registers::interfaces::*; pub use trait_ffi::impl_extern_trait; pub use crate::err::DError; +use crate::{descriptor::AdvRxDesc, ring::DEFAULT_RING_SIZE}; extern crate alloc; @@ -15,36 +15,49 @@ mod err; mod mac; #[macro_use] pub mod osal; +mod descriptor; mod phy; +mod ring; + +pub use futures::{Stream, StreamExt}; +pub use ring::{RxBuff, RxRing, TxRing}; pub struct Igb { - mac: RefCell, + mac: mac::Mac, phy: phy::Phy, + rx_ring_addrs: [usize; 16], + tx_ring_addrs: [usize; 16], } impl Igb { - pub fn new(iobase: NonNull) -> Self { - let mac = RefCell::new(mac::Mac::new(iobase)); - let phy = phy::Phy::new(mac.clone()); - Self { mac, phy } + pub fn new(iobase: NonNull) -> Result { + let mac = mac::Mac::new(iobase); + let phy = phy::Phy::new(mac); + + Ok(Self { + mac, + phy, + rx_ring_addrs: [0; 16], + tx_ring_addrs: [0; 16], + }) } pub fn open(&mut self) -> Result<(), DError> { - self.mac.borrow_mut().disable_interrupts(); + self.mac.disable_interrupts(); - self.mac.borrow_mut().reset()?; + self.mac.reset()?; - self.mac.borrow_mut().disable_interrupts(); + self.mac.disable_interrupts(); debug!("reset done"); - let link_mode = self.mac.borrow().link_mode().unwrap(); + let link_mode = self.mac.link_mode().unwrap(); debug!("link mode: {link_mode:?}"); self.phy.power_up()?; self.setup_phy_and_the_link()?; - self.mac.borrow_mut().set_link_up(); + self.mac.set_link_up(); self.phy.wait_for_auto_negotiation_complete()?; debug!("Auto-negotiation complete"); @@ -52,14 +65,21 @@ impl Igb { self.init_stat(); - self.init_rx(); - self.init_tx(); + self.mac.enable_interrupts(); - self.mac.borrow_mut().enable_interrupts(); + self.mac.enable_rx(); + self.mac.enable_tx(); Ok(()) } + pub fn new_ring(&mut self) -> Result<(TxRing, RxRing), DError> { + let tx_ring = TxRing::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; + let rx_ring = RxRing::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; + + Ok((tx_ring, rx_ring)) + } + fn config_fc_after_link_up(&mut self) -> Result<(), DError> { // TODO 参考 drivers/net/ethernet/intel/igb/e1000_mac.c // igb_config_fc_after_link_up @@ -75,7 +95,7 @@ impl Igb { } pub fn read_mac(&self) -> MacAddr6 { - self.mac.borrow().read_mac().into() + self.mac.read_mac().into() } pub fn check_vid_did(vid: u16, did: u16) -> bool { @@ -86,33 +106,35 @@ impl Igb { } pub fn status(&self) -> MacStatus { - self.mac.borrow().status() + self.mac.status() } - fn init_stat(&mut self) { - //TODO + pub fn enable_loopback(&mut self) { + self.mac.enable_loopback(); } - /// 4.5.9 Receive Initialization - fn init_rx(&mut self) { - // disable rx when configing. - self.mac.borrow_mut().disable_rx(); - - // self.rx_ring.init(); - - // self.reg.write_reg(RCTL::RXEN | RCTL::SZ_4096); - self.mac - .borrow_mut() - .reg_mut() - .rctl - .modify(mac::RCTL::RXEN::Enabled); + + pub fn disable_loopback(&mut self) { + self.mac.disable_loopback(); } - fn init_tx(&mut self) { - // self.reg.write_reg(TCTL::empty()); + fn init_stat(&mut self) { + //TODO + } - // self.tx_ring.init(); + /// # Safety + /// This function should only be called from the interrupt handler. + /// It will handle the interrupt by acknowledging + pub unsafe fn handle_interrupt(&mut self) { + let msg = self.mac.interrupts_ack(); + debug!("Interrupt message: {msg:?}"); + if msg.queue_idx & 0x1 != 0 { + // let rx_ring = unsafe { &mut *(self.rx_ring_addrs[0] as *mut Ring) }; + // rx_ring.clean(); + } + } - // self.reg.write_reg(TCTL::EN); + pub fn irq_mode_legacy(&mut self) { + self.mac.configure_legacy_mode(); } } diff --git a/igb/src/mac.rs b/igb/src/mac.rs index 02cbf9d..ebf5757 100644 --- a/igb/src/mac.rs +++ b/igb/src/mac.rs @@ -16,17 +16,25 @@ register_structs! { (0x1c => _rsv3), (0x20 => mdic: ReadWrite), (0x24 => _rsv4), + (0xc0 => icr: ReadWrite), + (0xc4 => _rsv13), + (0xd0 => ims: ReadWrite), + (0xd4 => _rsv14), + (0xd8 => imc: ReadWrite), + (0xdc => _rsv15), (0x100 => pub rctl: ReadWrite), (0x104 => _rsv7), - (0x400 => tctl: ReadWrite), + (0x400 => tctl: ReadWrite), (0x404 => _rsv12), - (0x01524 => eims: ReadWrite), - (0x01528 => eimc: ReadWrite), - (0x0152c => eiac: ReadWrite), - (0x01530 => eiam: ReadWrite), - (0x01534 => _rsv5), - (0x01580 => eicr: ReadWrite), - (0x01584 => _rsv6), + (0x1514 => gpie: ReadWrite), + (0x1518 => _rsv16), + (0x1524 => eims: ReadWrite), + (0x1528 => eimc: ReadWrite), + (0x152c => eiac: ReadWrite), + (0x1530 => eiam: ReadWrite), + (0x1534 => _rsv5), + (0x1580 => eicr: ReadWrite), + (0x1584 => _rsv6), (0x5400 => ralh_0_15: [ReadWrite; 32]), (0x5480 => _rsv8), (0x54e0 => ralh_16_23: [ReadWrite;32]), @@ -38,7 +46,7 @@ register_structs! { (0x5B60 => _rsv11), // The end of the struct is marked as follows. - (0xBFFF => @END), + (0xEFFF => @END), } } @@ -193,7 +201,145 @@ register_bitfields! [ DoNotStrip = 0, Strip = 1, ], - ] + ], + + // Transmit Control Register - TCTL (0x400) + TCTL [ + EN OFFSET(1) NUMBITS(1)[ + Disabled = 0, + Enabled = 1, + ], + PSP OFFSET(3) NUMBITS(1)[ + Disabled = 0, + Enabled = 1, + ], + CT OFFSET(4) NUMBITS(8)[], + COLD OFFSET(12) NUMBITS(10)[], + SWXOFF OFFSET(22) NUMBITS(1)[], + RTLC OFFSET(24) NUMBITS(1)[], + NRTU OFFSET(25) NUMBITS(1)[], + MULR OFFSET(28) NUMBITS(1)[], + ], + + // Extended Interrupt Cause Register - EICR (0x01580) + EICR [ + // Non MSI-X mode (GPIE.Multiple_MSIX = 0) + RxTxQ OFFSET(0) NUMBITS(16)[], + Reserved1 OFFSET(16) NUMBITS(14)[], + TCP_Timer OFFSET(30) NUMBITS(1)[], + Other_Cause OFFSET(31) NUMBITS(1)[], + ], + + // Extended Interrupt Cause Register - EICR MSI-X mode + EICR_MSIX [ + // MSI-X mode (GPIE.Multiple_MSIX = 1) + MSIX OFFSET(0) NUMBITS(25)[], + Reserved OFFSET(25) NUMBITS(7)[], + ], + + // Extended Interrupt Mask Set/Read - EIMS (0x01524) + EIMS [ + // Non MSI-X mode (GPIE.Multiple_MSIX = 0) + RxTxQ OFFSET(0) NUMBITS(16)[], + Reserved1 OFFSET(16) NUMBITS(14)[], + TCP_Timer OFFSET(30) NUMBITS(1)[], + Other_Cause OFFSET(31) NUMBITS(1)[], + ], + + // Extended Interrupt Mask Set/Read - EIMS MSI-X mode + EIMS_MSIX [ + // MSI-X mode (GPIE.Multiple_MSIX = 1) + MSIX OFFSET(0) NUMBITS(25)[], + Reserved OFFSET(25) NUMBITS(7)[], + ], + + // Legacy Interrupt Cause Register - ICR (0x000C0) + ICR [ + TXDW OFFSET(0) NUMBITS(1)[], // Transmit Descriptor Written Back + TXQE OFFSET(1) NUMBITS(1)[], // Transmit Queue Empty + LSC OFFSET(2) NUMBITS(1)[], // Link Status Change + RXSEQ OFFSET(3) NUMBITS(1)[], // Receive Sequence Error + RXDMT0 OFFSET(4) NUMBITS(1)[], // Receive Descriptor Minimum Threshold Reached + RXO OFFSET(6) NUMBITS(1)[], // Receiver Overrun + RXT0 OFFSET(7) NUMBITS(1)[], // Receiver Timer Interrupt + MDAC OFFSET(9) NUMBITS(1)[], // MDI/O Access Complete + RXCFG OFFSET(10) NUMBITS(1)[], // Receiving /C/ ordered sets + GPI_EN0 OFFSET(11) NUMBITS(1)[], // General Purpose Interrupt Enable 0 + GPI_EN1 OFFSET(12) NUMBITS(1)[], // General Purpose Interrupt Enable 1 + GPI_EN2 OFFSET(13) NUMBITS(1)[], // General Purpose Interrupt Enable 2 + GPI_EN3 OFFSET(14) NUMBITS(1)[], // General Purpose Interrupt Enable 3 + TXD_LOW OFFSET(15) NUMBITS(1)[], // Transmit Descriptor Low Threshold Hit + SRPD OFFSET(16) NUMBITS(1)[], // Small Receive Packet Detected + ACK OFFSET(17) NUMBITS(1)[], // Receive ACK Frame + MNG OFFSET(18) NUMBITS(1)[], // Management Bus Interrupt + DOCK OFFSET(19) NUMBITS(1)[], // Dock/Undock Status Change + INT_ASSERTED OFFSET(31) NUMBITS(1)[], // Interrupt Asserted + ], + + // Legacy Interrupt Mask Set/Read - IMS (0x000D0) + IMS [ + TXDW OFFSET(0) NUMBITS(1)[], // Transmit Descriptor Written Back + TXQE OFFSET(1) NUMBITS(1)[], // Transmit Queue Empty + LSC OFFSET(2) NUMBITS(1)[], // Link Status Change + RXSEQ OFFSET(3) NUMBITS(1)[], // Receive Sequence Error + RXDMT0 OFFSET(4) NUMBITS(1)[], // Receive Descriptor Minimum Threshold Reached + RXO OFFSET(6) NUMBITS(1)[], // Receiver Overrun + RXT0 OFFSET(7) NUMBITS(1)[], // Receiver Timer Interrupt + MDAC OFFSET(9) NUMBITS(1)[], // MDI/O Access Complete + RXCFG OFFSET(10) NUMBITS(1)[], // Receiving /C/ ordered sets + GPI_EN0 OFFSET(11) NUMBITS(1)[], // General Purpose Interrupt Enable 0 + GPI_EN1 OFFSET(12) NUMBITS(1)[], // General Purpose Interrupt Enable 1 + GPI_EN2 OFFSET(13) NUMBITS(1)[], // General Purpose Interrupt Enable 2 + GPI_EN3 OFFSET(14) NUMBITS(1)[], // General Purpose Interrupt Enable 3 + TXD_LOW OFFSET(15) NUMBITS(1)[], // Transmit Descriptor Low Threshold Hit + SRPD OFFSET(16) NUMBITS(1)[], // Small Receive Packet Detected + ACK OFFSET(17) NUMBITS(1)[], // Receive ACK Frame + MNG OFFSET(18) NUMBITS(1)[], // Management Bus Interrupt + DOCK OFFSET(19) NUMBITS(1)[], // Dock/Undock Status Change + ], + + // Legacy Interrupt Mask Clear - IMC (0x000D8) + IMC [ + TXDW OFFSET(0) NUMBITS(1)[], // Transmit Descriptor Written Back + TXQE OFFSET(1) NUMBITS(1)[], // Transmit Queue Empty + LSC OFFSET(2) NUMBITS(1)[], // Link Status Change + RXSEQ OFFSET(3) NUMBITS(1)[], // Receive Sequence Error + RXDMT0 OFFSET(4) NUMBITS(1)[], // Receive Descriptor Minimum Threshold Reached + RXO OFFSET(6) NUMBITS(1)[], // Receiver Overrun + RXT0 OFFSET(7) NUMBITS(1)[], // Receiver Timer Interrupt + MDAC OFFSET(9) NUMBITS(1)[], // MDI/O Access Complete + RXCFG OFFSET(10) NUMBITS(1)[], // Receiving /C/ ordered sets + GPI_EN0 OFFSET(11) NUMBITS(1)[], // General Purpose Interrupt Enable 0 + GPI_EN1 OFFSET(12) NUMBITS(1)[], // General Purpose Interrupt Enable 1 + GPI_EN2 OFFSET(13) NUMBITS(1)[], // General Purpose Interrupt Enable 2 + GPI_EN3 OFFSET(14) NUMBITS(1)[], // General Purpose Interrupt Enable 3 + TXD_LOW OFFSET(15) NUMBITS(1)[], // Transmit Descriptor Low Threshold Hit + SRPD OFFSET(16) NUMBITS(1)[], // Small Receive Packet Detected + ACK OFFSET(17) NUMBITS(1)[], // Receive ACK Frame + MNG OFFSET(18) NUMBITS(1)[], // Management Bus Interrupt + DOCK OFFSET(19) NUMBITS(1)[], // Dock/Undock Status Change + ], + + // General Purpose Interrupt Enable - GPIE (0x1514) + GPIE [ + NSICR OFFSET(0) NUMBITS(1)[ + Normal = 0, + ClearOnRead = 1, + ], + Multiple_MSIX OFFSET(4) NUMBITS(1)[ + SingleVector = 0, + MultipleVectors = 1, + ], + LL_Interval OFFSET(7) NUMBITS(5)[], // Low Latency Credits Increment Rate (bits 11:7) + EIAME OFFSET(30) NUMBITS(1)[ + Disabled = 0, + Enabled = 1, + ], + PBA_Support OFFSET(31) NUMBITS(1)[ + Legacy = 0, + MSIX = 1, + ], + ], ]; #[derive(Clone, Copy)] @@ -206,6 +352,10 @@ impl Mac { Self { reg: iobase.cast() } } + pub fn iobase(&self) -> NonNull { + self.reg.cast() + } + pub fn write_mdic(&self, phys_addr: u32, offset: u32, data: u16) -> Result<(), DError> { self.reg().mdic.write( MDIC::REGADDR.val(offset) @@ -248,12 +398,85 @@ impl Mac { } pub fn disable_interrupts(&mut self) { - self.reg_mut().eims.set(0); + self.reg_mut().eimc.set(u32::MAX); self.clear_interrupts(); } pub fn enable_interrupts(&mut self) { - //TODO + self.reg_mut().eims.set(u32::MAX); + } + + /// Enable legacy interrupts + pub fn enable_legacy_interrupts(&mut self) { + // Enable common legacy interrupts + self.reg_mut().ims.write( + IMS::TXDW::SET + + IMS::TXQE::SET + + IMS::LSC::SET + + IMS::RXDMT0::SET + + IMS::RXO::SET + + IMS::RXT0::SET + + IMS::MDAC::SET, + ); + } + + /// Disable legacy interrupts + pub fn disable_legacy_interrupts(&mut self) { + // Disable all legacy interrupts + self.reg_mut().imc.write( + IMC::TXDW::SET + + IMC::TXQE::SET + + IMC::LSC::SET + + IMC::RXSEQ::SET + + IMC::RXDMT0::SET + + IMC::RXO::SET + + IMC::RXT0::SET + + IMC::MDAC::SET + + IMC::RXCFG::SET + + IMC::GPI_EN0::SET + + IMC::GPI_EN1::SET + + IMC::GPI_EN2::SET + + IMC::GPI_EN3::SET + + IMC::TXD_LOW::SET + + IMC::SRPD::SET + + IMC::ACK::SET + + IMC::MNG::SET + + IMC::DOCK::SET, + ); + } + + /// Read and clear legacy interrupt cause + pub fn legacy_interrupts_ack(&mut self) -> LegacyIrqMsg { + let icr = self.reg().icr.get(); + let ims = self.reg().ims.get(); + let status = icr & ims; + + LegacyIrqMsg { + txdw: status & ICR::TXDW.mask != 0, + txqe: status & ICR::TXQE.mask != 0, + lsc: status & ICR::LSC.mask != 0, + rxseq: status & ICR::RXSEQ.mask != 0, + rxdmt0: status & ICR::RXDMT0.mask != 0, + rxo: status & ICR::RXO.mask != 0, + rxt0: status & ICR::RXT0.mask != 0, + mdac: status & ICR::MDAC.mask != 0, + rxcfg: status & ICR::RXCFG.mask != 0, + asserted: status & ICR::INT_ASSERTED.mask != 0, + } + } + + pub fn interrupts_ack(&mut self) -> IrqMsg { + let eicr = self.reg().eicr.get(); + let eims = self.reg().eims.get(); + let status = eicr & eims; + let tcp_timer = status & EICR::TCP_Timer.mask != 0; + let other = status & EICR::Other_Cause.mask != 0; + let queue_idx = (status & EICR::RxTxQ.mask) as u16; + IrqMsg { + queue_idx, + tcp_timer, + other, + } } pub fn link_mode(&self) -> Option { @@ -286,11 +509,7 @@ impl Mac { } pub fn set_link_up(&mut self) { - self.reg_mut().ctrl.modify( - CTRL::SLU::SET + CTRL::FD::SET, // + CTRL::SPEED::Speed1000 - // + CTRL::FRCSPD::SET - // + CTRL::FRCDPLX::SET, - ); + self.reg_mut().ctrl.modify(CTRL::SLU::SET + CTRL::FD::SET); } pub fn reg(&self) -> &MacRegister { @@ -318,6 +537,52 @@ impl Mac { self.reg_mut().rctl.modify(RCTL::RXEN::Disabled); } + pub fn enable_rx(&mut self) { + self.reg_mut().rctl.modify(RCTL::RXEN::Enabled); + } + + pub fn enable_tx(&mut self) { + self.reg_mut().tctl.modify(TCTL::EN::Enabled); + } + + pub fn enable_loopback(&mut self) { + self.reg_mut().rctl.modify(RCTL::LBM::MacLoopback); + } + + pub fn disable_loopback(&mut self) { + self.reg_mut().rctl.modify(RCTL::LBM::Normal); + } + + /// Configure GPIE register for MSI-X mode + pub fn configure_msix_mode(&mut self) { + self.reg_mut().gpie.write( + GPIE::Multiple_MSIX::MultipleVectors + GPIE::EIAME::Enabled + GPIE::PBA_Support::MSIX, + ); + } + + /// Configure GPIE register for legacy/MSI mode + pub fn configure_legacy_mode(&mut self) { + self.reg_mut().gpie.write( + GPIE::Multiple_MSIX::SingleVector + GPIE::EIAME::Disabled + GPIE::PBA_Support::Legacy, + ); + } + + /// Set non-selective interrupt clear on read + pub fn set_nsicr(&mut self, enable: bool) { + if enable { + self.reg_mut().gpie.modify(GPIE::NSICR::ClearOnRead); + } else { + self.reg_mut().gpie.modify(GPIE::NSICR::Normal); + } + } + + /// Set Low Latency Credits Increment Rate + pub fn set_ll_interval(&mut self, interval: u8) { + // interval is in 4μs increments, valid values 0-31 + let val = (interval as u32) & 0x1F; + self.reg_mut().gpie.modify(GPIE::LL_Interval.val(val)); + } + fn ral(&self, i: usize) -> u32 { if i <= 15 { self.reg().ralh_0_15[i * 2].get() @@ -354,6 +619,27 @@ impl Mac { } } +#[derive(Debug, Clone)] +pub struct IrqMsg { + pub queue_idx: u16, + pub tcp_timer: bool, + pub other: bool, +} + +#[derive(Debug, Clone)] +pub struct LegacyIrqMsg { + pub txdw: bool, // Transmit Descriptor Written Back + pub txqe: bool, // Transmit Queue Empty + pub lsc: bool, // Link Status Change + pub rxseq: bool, // Receive Sequence Error + pub rxdmt0: bool, // Receive Descriptor Minimum Threshold Reached + pub rxo: bool, // Receiver Overrun + pub rxt0: bool, // Receiver Timer Interrupt + pub mdac: bool, // MDI/O Access Complete + pub rxcfg: bool, // Receiving /C/ ordered sets + pub asserted: bool, // Interrupt Asserted +} + #[derive(Clone, Copy, PartialEq, Eq)] #[repr(transparent)] pub struct MacAddr6([u8; 6]); diff --git a/igb/src/phy.rs b/igb/src/phy.rs index 5234433..25a44f0 100644 --- a/igb/src/phy.rs +++ b/igb/src/phy.rs @@ -1,5 +1,3 @@ -use core::cell::RefCell; - use log::debug; use tock_registers::register_bitfields; @@ -248,21 +246,21 @@ register_bitfields! { } pub struct Phy { - mac: RefCell, + mac: Mac, addr: u32, } impl Phy { - pub fn new(mac: RefCell) -> Self { + pub fn new(mac: Mac) -> Self { Self { mac, addr: 1 } } pub fn read_mdic(&mut self, offset: u32) -> Result { - self.mac.borrow_mut().read_mdic(self.addr, offset) + self.mac.read_mdic(self.addr, offset) } pub fn write_mdic(&mut self, offset: u32, data: u16) -> Result<(), DError> { - self.mac.borrow_mut().write_mdic(self.addr, offset, data) + self.mac.write_mdic(self.addr, offset, data) } // pub fn aquire_sync(&self, flags: SyncFlags) -> Result { diff --git a/igb/src/ring/mod.rs b/igb/src/ring/mod.rs new file mode 100644 index 0000000..f1eb06b --- /dev/null +++ b/igb/src/ring/mod.rs @@ -0,0 +1,170 @@ +use core::{cell::UnsafeCell, ptr::NonNull, time::Duration}; + +use alloc::vec::Vec; +use dma_api::{DSlice, DVec, Direction}; +use futures::task::AtomicWaker; +use log::debug; +use mbarrier::mb; +use tock_registers::register_bitfields; + +use crate::{ + descriptor::{AdvTxDesc, Descriptor}, + err::DError, + osal::wait_for, +}; + +mod rx; +mod tx; +pub use rx::{RxBuff, RxRing}; +pub use tx::TxRing; + +pub const DEFAULT_RING_SIZE: usize = 256; +const RDBAL: usize = 0xC000; // RX Descriptor Base Address Low +const RDBAH: usize = 0xC004; // RX Descriptor Base Address High +const RDLEN: usize = 0xC008; // RX Descriptor Length +const SRRCTL: usize = 0xC00C; // RX Descriptor Control +const RDH: usize = 0xC010; // RX Descriptor Head +const RDT: usize = 0xC018; // RX Descriptor Tail +const RXDCTL: usize = 0xC028; // RX Descriptor Control +// const RXCTL: usize = 0xC014; // RX Control +// const RQDPC: usize = 0xC030; // RX Descriptor Polling Control + +// TX descriptor registers +const TDBAL: usize = 0xE000; // TX Descriptor Base Address Low +const TDBAH: usize = 0xE004; // TX Descriptor Base Address High +const TDLEN: usize = 0xE008; // TX Descriptor Length +const TDH: usize = 0xE010; // TX Descriptor Head +const TDT: usize = 0xE018; // TX Descriptor Tail +const TXDCTL: usize = 0xE028; // TX Descriptor Control +// const TDWBAL: usize = 0xE038; // TX Descriptor Write Back Address Low +// const TDWBAH: usize = 0xE03C; // TX Descriptor Write Back Address High + +const PACKET_SIZE_KB: u32 = 2; +const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; + +register_bitfields! [ + // First parameter is the register width. Can be u8, u16, u32, or u64. + u32, + + RDLEN [ + LEN OFFSET(7) NUMBITS(13)[], + ], + + pub SRRCTL [ + BSIZEPACKET OFFSET(0) NUMBITS(7)[], + BSIZEHEADER OFFSET(8) NUMBITS(4)[], + RDMTS OFFSET(20) NUMBITS(5)[], + DESCTYPE OFFSET(25) NUMBITS(3)[ + Legacy = 0b000, + AdvancedOneBuffer = 0b001, + AdvancedHeaderSplitting = 0b010, + AdvancedHeaderReplicationAlways = 0b011, + AdvancedHeaderReplicationLargePacket = 0b100, + ], + SECRC OFFSET(26) NUMBITS(1)[ + DoNotStrip = 0, + Strip = 1, + ], + DROP_EN OFFSET(31) NUMBITS(1)[ + Disabled = 0, + Enabled = 1, + ], + ], + + pub RXDCTL [ + PTHRESH OFFSET(0) NUMBITS(5)[], + HTHRESH OFFSET(8) NUMBITS(5)[], + WTHRESH OFFSET(16) NUMBITS(5)[], + ENABLE OFFSET(25) NUMBITS(1)[ + Disabled = 0, + Enabled = 1, + ], + SWFLUSH OFFSET(26) NUMBITS(1)[], + ], + + pub TXDCTL [ + PTHRESH OFFSET(0) NUMBITS(5)[], + HTHRESH OFFSET(8) NUMBITS(5)[], + WTHRESH OFFSET(16) NUMBITS(5)[], + ENABLE OFFSET(25) NUMBITS(1)[ + Disabled = 0, + Enabled = 1, + ], + SWFLUSH OFFSET(26) NUMBITS(1)[], + ], + + +]; + +#[derive(Default, Clone)] +struct RingElemMeta { + buff_ptr: usize, +} + +struct Ring { + pub descriptors: DVec, + ring_base: NonNull, + current_head: usize, + hw_head: usize, + waker: AtomicWaker, + meta_ls: Vec, + pkts: Vec>, + pkt_size: usize, +} + +impl Ring { + pub fn new( + idx: usize, + mmio_base: NonNull, + size: usize, + pkt_size: usize, + dir: Direction, + ) -> Result { + let descriptors = + DVec::zeros(size, 0x1000, Direction::Bidirectional).ok_or(DError::NoMemory)?; + + let ring_base = unsafe { mmio_base.add(idx * 0x40) }; + let mut pkts = Vec::with_capacity(size); + for _ in 0..size { + pkts.push(DVec::zeros(pkt_size, pkt_size, dir).ok_or(DError::NoMemory)?); + } + + Ok(Self { + descriptors, + ring_base, + waker: AtomicWaker::new(), + current_head: 0, + hw_head: 0, + meta_ls: alloc::vec![RingElemMeta::default(); size], + pkts, + pkt_size, + }) + } + + pub fn bus_addr(&self) -> u64 { + // 获取 DMA 物理地址 + // 暂时返回虚拟地址,这里需要根据实际的 DMA API 实现 + self.descriptors.bus_addr() + } + + pub fn size_bytes(&self) -> usize { + self.descriptors.len() * core::mem::size_of::() + } + + pub fn count(&self) -> usize { + self.descriptors.len() + } + + fn reg_addr(&self, reg: usize) -> NonNull { + unsafe { self.ring_base.add(reg).cast() } + } + + fn reg_write(&mut self, reg: usize, value: u32) { + unsafe { + self.reg_addr(reg).write_volatile(value); + } + } + fn reg_read(&self, reg: usize) -> u32 { + unsafe { self.reg_addr(reg).read_volatile() } + } +} diff --git a/igb/src/ring/rx.rs b/igb/src/ring/rx.rs new file mode 100644 index 0000000..1625d94 --- /dev/null +++ b/igb/src/ring/rx.rs @@ -0,0 +1,250 @@ +use core::ops::{Deref, DerefMut}; + +use super::*; +use crate::{ + DError, + descriptor::{AdvRxDesc, AdvRxDescRead}, +}; +use alloc::sync::Arc; +use log::trace; + +struct RingInner { + base: Ring, +} + +impl RingInner { + fn new(ring: Ring) -> Result { + Ok(Self { base: ring }) + } + + fn init(&mut self) -> Result<(), DError> { + let bus_addr = self.bus_addr(); + let size_bytes = self.size_bytes(); + + for i in 0..self.descriptors.len() { + let pkt_addr = self.pkts[i].bus_addr(); + let desc = AdvRxDesc { + read: AdvRxDescRead { + pkt_addr, + hdr_addr: 0, + }, + }; + self.descriptors.set(i, desc); + } + + // Program the descriptor base address with the address of the region. + self.reg_write(RDBAL, (bus_addr & 0xFFFFFFFF) as u32); + self.reg_write(RDBAH, (bus_addr >> 32) as u32); + + // Set the length register to the size of the descriptor ring. + self.reg_write(RDLEN, size_bytes as u32); + + let pkt_size_kb = self.pkt_size / 1024; + + // Program SRRCTL of the queue according to the size of the buffers and the required header handling. + self.reg_write( + SRRCTL, + (SRRCTL::DESCTYPE::AdvancedOneBuffer + SRRCTL::BSIZEPACKET.val(pkt_size_kb as _)).value, + ); + + // If header split or header replication is required for this queue, + // program the PSRTYPE register according to the required headers. + // 暂时不需要头部分割 + + self.reg_write(RDH, 0); + self.reg_write(RDT, 0); + + // Enable the queue by setting RXDCTL.ENABLE. In the case of queue zero, + // the enable bit is set by default - so the ring parameters should be set before RCTL.RXEN is set. + // 使用推荐的阈值:PTHRESH=8, HTHRESH=8, WTHRESH=1 + self.enable_queue(); + + // Poll the RXDCTL register until the ENABLE bit is set. + // The tail should not be bumped before this bit was read as one. + + wait_for( + || self.reg_read(RXDCTL) & RXDCTL::ENABLE::Enabled.value > 0, + Duration::from_millis(1), + Some(1000), + )?; + + // Program the direction of packets to this queue according to the mode select in MRQC. + // Packets directed to a disabled queue is dropped. + // 暂时不配置 MRQC + + // Note: The tail register of the queue (RDT[n]) should not be bumped until the queue is enabled. + self.update_tail(self.descriptors.len() - 1); + Ok(()) + } + + pub fn enable_queue(&mut self) { + // 启用队列 + self.reg_write( + RXDCTL, + (RXDCTL::PTHRESH.val(8) + + RXDCTL::HTHRESH.val(8) + + RXDCTL::WTHRESH.val(1) + + RXDCTL::ENABLE::Enabled) + .value, + ); + } + + pub fn disable_queue(&mut self) { + // 禁用队列 + self.reg_write( + RXDCTL, + (RXDCTL::PTHRESH.val(8) + + RXDCTL::HTHRESH.val(8) + + RXDCTL::WTHRESH.val(1) + + RXDCTL::ENABLE::Disabled) + .value, + ); + } + + pub fn flush_descriptors(&mut self) { + // 触发描述符写回刷新 + self.reg_write( + RXDCTL, + (RXDCTL::PTHRESH.val(8) + + RXDCTL::HTHRESH.val(8) + + RXDCTL::WTHRESH.val(1) + + RXDCTL::ENABLE::Enabled + + RXDCTL::SWFLUSH.val(1)) + .value, + ); + } + + /// 检查描述符是否已完成(DD位) + /// + /// # 参数 + /// - `desc_index`: 描述符索引 + /// + /// # 返回 + /// 如果描述符已完成则返回 true,否则返回 false + pub fn is_descriptor_done(&self, desc_index: usize) -> bool { + if desc_index >= self.descriptors.len() { + return false; + } + + // 检查写回格式中的DD位 + let desc = &self.descriptors[desc_index]; + unsafe { + let wb = desc.write; + wb.is_done() + } + } + + /// 获取当前头部指针值 + pub fn get_head(&self) -> u32 { + self.reg_read(RDH) + } + + /// 获取当前尾部指针值 + pub fn get_tail(&self) -> u32 { + self.reg_read(RDT) + } + + /// 更新尾部指针 + pub fn update_tail(&mut self, mut tail: usize) { + if tail == self.descriptors.len() { + tail = 0; + } + self.reg_write(RDT, tail as u32); + } + + pub fn clean(&mut self) { + // 清理环形缓冲区 + self.hw_head = self.get_head() as usize; + } +} +impl Deref for RingInner { + type Target = super::Ring; + + fn deref(&self) -> &Self::Target { + &self.base + } +} + +impl DerefMut for RingInner { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.base + } +} + +pub struct RxRing(Arc>); + +unsafe impl Send for RxRing {} + +impl RxRing { + pub(crate) fn new(idx: usize, mmio_base: NonNull, size: usize) -> Result { + let base = Ring::new( + idx, + mmio_base, + size, + PACKET_SIZE as usize, + Direction::FromDevice, + )?; + let mut ring_inner = RingInner::new(base)?; + ring_inner.init()?; + let ring = Arc::new(UnsafeCell::new(ring_inner)); + Ok(Self(ring)) + } + + fn this(&self) -> &RingInner { + unsafe { &*self.0.get() } + } + fn this_mut(&mut self) -> &mut RingInner { + unsafe { &mut *self.0.get() } + } + + pub fn packet_size(&self) -> usize { + self.this().pkt_size + } + + pub fn next_pkt(&mut self) -> Option> { + let ring = self.this_mut(); + let head = ring.get_head() as usize; + let tail = ring.get_tail() as usize; + trace!("RxRing: next_pkt head: {head}, tail: {tail}"); + let index = (tail + 1) % ring.count(); + if head == index { + return None; // 没有可用的缓冲区 + } + + // 检查描述符是否已完成 + if !ring.is_descriptor_done(index) { + trace!("RxRing: next_pkt descriptor not done at index: {index}"); + return None; // 描述符未完成,无法获取数据 + } + trace!("RxRing: next_pkt index: {index}"); + // 返回 RxBuff 实例 + Some(RxBuff { ring: self, index }) + } +} + +impl Drop for RxRing { + fn drop(&mut self) { + // 在释放时禁用队列 + self.this_mut().disable_queue(); + } +} + +pub struct RxBuff<'a> { + ring: &'a mut RxRing, + index: usize, +} + +impl Deref for RxBuff<'_> { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.ring.this().pkts[self.index].deref() + } +} + +impl Drop for RxBuff<'_> { + fn drop(&mut self) { + // 在释放时更新尾部指针 + self.ring.this_mut().update_tail(self.index); + } +} diff --git a/igb/src/ring/tx.rs b/igb/src/ring/tx.rs new file mode 100644 index 0000000..bbb4d22 --- /dev/null +++ b/igb/src/ring/tx.rs @@ -0,0 +1,175 @@ +use core::ops::Deref; + +use alloc::sync::Arc; +use log::trace; + +use super::*; + +type RingInner = Ring; + +impl RingInner { + pub fn init(&mut self) -> Result<(), DError> { + debug!("init tx"); + // Step 1: Allocate a region of memory for the transmit descriptor list + // (Already done in Ring::new()) + + // Step 2: Program the descriptor base address with the address of the region + self.reg_write(TDBAL, (self.bus_addr() & 0xFFFFFFFF) as u32); + self.reg_write(TDBAH, (self.bus_addr() >> 32) as u32); + + // Step 3: Set the length register to the size of the descriptor ring + self.reg_write(TDLEN, self.size_bytes() as u32); + + // Step 4: Program the TXDCTL register with the desired TX descriptor write back policy + // Suggested values: WTHRESH = 1, all other fields 0 + self.reg_write(TXDCTL, TXDCTL::WTHRESH.val(1).value); + + self.reg_write(TDH, 0); + self.reg_write(TDT, 0); + + // Step 5: If needed, set the TDWBAL/TWDBAH to enable head write back + // (Not implemented in this basic version) + + // Step 6: Enable the queue using TXDCTL.ENABLE (queue zero is enabled by default) + self.reg_write( + TXDCTL, + (TXDCTL::WTHRESH.val(1) + TXDCTL::ENABLE::Enabled).value, + ); + + // Step 7: Poll the TXDCTL register until the ENABLE bit is set + wait_for( + || self.reg_read(TXDCTL) & TXDCTL::ENABLE::Enabled.value > 0, + Duration::from_millis(1), + Some(1000), + )?; + + // Note: The tail register of the queue (TDT[n]) should not be bumped until the queue is enabled + // Step 8: Enable transmit path by setting TCTL.EN should be done only after all other settings are done + // This is handled by the MAC layer through mac.enable_tx() + debug!("TX ring initialized successfully"); + Ok(()) + } + + /// 检查描述符是否已完成(DD位) + pub fn is_tx_descriptor_done(&self, desc_index: usize) -> bool { + if desc_index >= self.descriptors.len() { + return false; + } + + // 检查写回格式中的DD位 + let desc = &self.descriptors[desc_index]; + unsafe { + let wb = desc.write; + (wb.status & crate::descriptor::tx_desc_consts::DD_BIT) != 0 + } + } + + /// 获取当前头部指针值 + pub fn get_tx_head(&self) -> u32 { + self.reg_read(TDH) + } + + /// 获取当前尾部指针值 + pub fn get_tx_tail(&self) -> u32 { + self.reg_read(TDT) + } + + /// 发送单个数据包 + pub fn send_packet(&mut self, buff: &[u8]) -> Result<(), DError> { + if buff.len() > PACKET_SIZE as usize { + return Err(DError::InvalidParameter); + } + trace!("send {}", buff.len()); + let tail = self.get_tx_tail() as usize; + let next_tail = (tail + 1) % self.count(); + let head = self.get_tx_head() as usize; + + // 检查是否有空间 + if next_tail == head { + return Err(DError::NoMemory); // 环形缓冲区已满 + } + + for (i, &v) in buff.iter().enumerate() { + self.pkts[next_tail].set(i, v); + } + + let buffer_addr = self.pkts[next_tail].bus_addr(); + + // 设置描述符 + let desc = AdvTxDesc { + read: crate::descriptor::AdvTxDescRead { + buffer_addr, + cmd_type_len: crate::descriptor::tx_desc_consts::CMD_EOP + | crate::descriptor::tx_desc_consts::CMD_IFCS + | crate::descriptor::tx_desc_consts::CMD_RS + | crate::descriptor::tx_desc_consts::CMD_DEXT + | crate::descriptor::tx_desc_consts::DTYPE_DATA + | (buff.len() as u32 & crate::descriptor::tx_desc_consts::LEN_MASK), + olinfo_status: 0, + }, + }; + + self.descriptors.set(tail, desc); + + // 内存屏障确保描述符写入完成 + mb(); + + // 更新尾部指针 + self.reg_write(TDT, next_tail as u32); + + Ok(()) + } +} + +pub struct TxRing(Arc>); + +unsafe impl Send for TxRing {} + +impl TxRing { + pub(crate) fn new(idx: usize, mmio_base: NonNull, size: usize) -> Result { + let mut ring_inner = Ring::new( + idx, + mmio_base, + size, + PACKET_SIZE as usize, + Direction::ToDevice, + )?; + ring_inner.init()?; + let ring = Arc::new(UnsafeCell::new(ring_inner)); + Ok(Self(ring)) + } + + fn this(&self) -> &RingInner { + unsafe { &*self.0.get() } + } + fn this_mut(&mut self) -> &mut RingInner { + unsafe { &mut *self.0.get() } + } + + pub fn send(&mut self, buff: &[u8]) -> Result<(), DError> { + self.this_mut().send_packet(buff) + } + + pub fn next_pkt(&mut self) -> Option> { + let ring = self.this_mut(); + let next_tail = (ring.get_tx_tail() + 1) % ring.count() as u32; + if next_tail == ring.get_tx_head() { + return None; // 没有可用的包 + } + + Some(TxBuff { ring: self }) + } +} + +pub struct TxBuff<'a> { + ring: &'a mut TxRing, +} + +impl TxBuff<'_> { + pub fn send(self, buff: &[u8]) -> Result<(), DError> { + if buff.len() > PACKET_SIZE as usize { + return Err(DError::InvalidParameter); + } + self.ring.send(buff) + } +} diff --git a/igb/tests/test.rs b/igb/tests/test.rs index d302ffb..8531552 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -8,44 +8,290 @@ use bare_test::time::spin_delay; use eth_igb::{impl_trait, osal::Kernel}; extern crate alloc; -extern crate bare_test; #[bare_test::tests] mod tests { - use core::time::Duration; + use core::{ + cell::UnsafeCell, + ops::{Deref, DerefMut}, + time::Duration, + }; use bare_test::{ fdt_parser::PciSpace, globals::{PlatformInfoKind, global_val}, + irq::{IrqHandleResult, IrqInfo, IrqParam}, mem::iomap, + platform::fdt::GetPciIrqConfig, println, time::spin_delay, }; - use eth_igb::Igb; - use log::info; - use pcie::{CommandRegister, RootComplexGeneric, SimpleBarAllocator}; + use eth_igb::{Igb, RxBuff}; + use log::*; + use pcie::{CommandRegister, PciCapability, RootComplexGeneric, SimpleBarAllocator}; + use smoltcp::socket::icmp::{self, Socket as IcmpSocket}; + use smoltcp::time::Instant; + use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; + use smoltcp::{ + iface::{Config, Interface, SocketSet}, + wire::HardwareAddress, + }; + use smoltcp::{ + phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken}, + wire::{Icmpv4Packet, Icmpv4Repr}, + }; + + const IP: IpAddress = IpAddress::v4(10, 0, 2, 15); + const GATEWAY: Ipv4Address = Ipv4Address::new(10, 0, 2, 2); + + struct Driver(UnsafeCell); + impl Deref for Driver { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.0.get() } + } + } + impl DerefMut for Driver { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.0.get() } + } + } + unsafe impl Send for Driver {} + unsafe impl Sync for Driver {} + + impl Driver { + pub fn new(inner: T) -> Self { + Self(UnsafeCell::new(inner)) + } + } + + // SmolTCP device adapter for IGB + struct IgbDevice { + rx_ring: eth_igb::RxRing, + tx_ring: eth_igb::TxRing, + } + + impl IgbDevice { + fn new(rx_ring: eth_igb::RxRing, tx_ring: eth_igb::TxRing) -> Self { + Self { rx_ring, tx_ring } + } + } + + impl Device for IgbDevice { + type RxToken<'a> = IgbRxToken<'a>; + type TxToken<'a> = IgbTxToken<'a>; + + fn receive( + &mut self, + _timestamp: Instant, + ) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { + self.rx_ring.next_pkt().map(|buff| { + let rx_token = IgbRxToken { buff }; + let tx_token = IgbTxToken { + tx_ring: &mut self.tx_ring, + }; + (rx_token, tx_token) + }) + } + + fn transmit(&mut self, _timestamp: Instant) -> Option> { + Some(IgbTxToken { + tx_ring: &mut self.tx_ring, + }) + } + + fn capabilities(&self) -> DeviceCapabilities { + let mut caps = DeviceCapabilities::default(); + caps.max_transmission_unit = 1500; + caps.max_burst_size = Some(1); + caps.medium = Medium::Ethernet; + caps + } + } + + struct IgbRxToken<'a> { + buff: RxBuff<'a>, + } + + impl<'a> RxToken for IgbRxToken<'a> { + fn consume(self, f: F) -> R + where + F: FnOnce(&[u8]) -> R, + { + debug!("rcv one"); + f(&self.buff) + } + } + + struct IgbTxToken<'a> { + tx_ring: &'a mut eth_igb::TxRing, + } + + impl<'a> TxToken for IgbTxToken<'a> { + fn consume(self, len: usize, f: F) -> R + where + F: FnOnce(&mut [u8]) -> R, + { + let mut buffer = alloc::vec![0u8; len]; + let result = f(&mut buffer); + self.tx_ring.send(&buffer).unwrap(); + result + } + } + + fn now() -> Instant { + let ms = bare_test::time::since_boot().as_millis() as u64; + Instant::from_millis(ms as i64) + } #[test] - fn it_works() { - let mut igb = get_igb().unwrap(); + fn ping_test() { + let (igb, irq) = get_igb().unwrap(); info!("igb: {:#?}", igb.status()); + + let mut igb = Driver::new(igb); + let igb_ptr = igb.0.get(); + + for one in &irq.cfgs { + IrqParam { + intc: irq.irq_parent, + cfg: one.clone(), + } + .register_builder({ + move |_irq| { + unsafe { + (*igb_ptr).handle_interrupt(); + } + IrqHandleResult::Handled + } + }) + .register(); + } + igb.irq_mode_legacy(); igb.open().unwrap(); - info!("igb opened: {:#?}", igb.status()); + info!("igb opened for ping test: {:#?}", igb.status()); - info!("mac: {:#?}", igb.read_mac()); + let mac = igb.read_mac(); + info!("mac: {mac:#?}"); info!("waiting for link up..."); while !igb.status().link_up { spin_delay(Duration::from_secs(1)); - info!("status: {:#?}", igb.status()); } - println!("test passed!"); + let (tx_ring, rx_ring) = igb.new_ring().unwrap(); + + // 创建 smoltcp 设备适配器 + let mut device = IgbDevice::new(rx_ring, tx_ring); + + // 设置网络配置 + let config = Config::new(HardwareAddress::Ethernet(EthernetAddress::from_bytes( + &mac.bytes(), + ))); + let mut iface = Interface::new(config, &mut device, now()); + + // 配置 IP 地址 + let ip_addr = IpCidr::new(IP, 8); + iface.update_ip_addrs(|ip_addrs| { + ip_addrs.push(ip_addr).unwrap(); + }); + iface.routes_mut().add_default_ipv4_route(GATEWAY).unwrap(); + + // 创建 ICMP socket + let icmp_rx_buffer = icmp::PacketBuffer::new( + alloc::vec![icmp::PacketMetadata::EMPTY], + alloc::vec![0; 256], + ); + let icmp_tx_buffer = icmp::PacketBuffer::new( + alloc::vec![icmp::PacketMetadata::EMPTY], + alloc::vec![0; 256], + ); + + let icmp_socket = icmp::Socket::new(icmp_rx_buffer, icmp_tx_buffer); + + let mut socket_set = SocketSet::new(alloc::vec![]); + let icmp_handle = socket_set.add(icmp_socket); + + info!("Starting ping to 127.0.0.1..."); + + // 执行 ping 测试 + let ping_result = ping_127_0_0_1(&mut iface, &mut device, &mut socket_set, icmp_handle); + + if ping_result { + info!("✓ Ping test passed! Successfully pinged 127.0.0.1"); + } else { + info!("✗ Ping test failed!"); + } + + println!("ping test completed!"); + } + + fn ping_127_0_0_1( + iface: &mut Interface, + device: &mut IgbDevice, + socket_set: &mut SocketSet, + icmp_handle: smoltcp::iface::SocketHandle, + ) -> bool { + let target_addr = Ipv4Address::new(127, 0, 0, 1); + let mut ping_sent = false; + let mut ping_received = false; + let mut attempts = 0; + const MAX_ATTEMPTS: usize = 1000; + let ident = 0x22b; + + while attempts < MAX_ATTEMPTS && !ping_received { + iface.poll(now(), device, socket_set); + // 获取 ICMP socket + let socket = socket_set.get_mut::(icmp_handle); + + if !socket.is_open() { + socket.bind(icmp::Endpoint::Ident(ident)).unwrap(); + } + + if !ping_sent && socket.can_send() { + let icmp_repr = Icmpv4Repr::EchoRequest { + ident, + seq_no: attempts as u16, + data: b"ping test", + }; + let icmp_payload = socket + .send(icmp_repr.buffer_len(), target_addr.into()) + .unwrap(); + let mut icmp_packet = Icmpv4Packet::new_unchecked(icmp_payload); + + // 发送 ping + icmp_repr.emit(&mut icmp_packet, &device.capabilities().checksum); + ping_sent = true; + } + + if ping_sent && socket.can_recv() { + // 接收 ping 响应 + match socket.recv() { + Ok((data, addr)) => { + info!( + "Ping response received from {:?}: {:?}", + addr, + core::str::from_utf8(data) + ); + ping_received = true; + } + Err(e) => { + info!("Failed to receive ping response: {e:?}"); + } + } + } + + attempts += 1; + spin_delay(Duration::from_millis(100)); + } + + ping_received } - fn get_igb() -> Option { + fn get_igb() -> Option<(Igb, IrqInfo)> { let PlatformInfoKind::DeviceTree(fdt) = &global_val().platform_info; let fdt = fdt.get(); @@ -83,7 +329,7 @@ mod tests { } for header in root.enumerate_keep_bar(None) { - if let pcie::Header::Endpoint(endpoint) = header.header { + if let pcie::Header::Endpoint(mut endpoint) = header.header { if !Igb::check_vid_did(endpoint.vendor_id, endpoint.device_id) { continue; } @@ -94,6 +340,23 @@ mod tests { | CommandRegister::BUS_MASTER_ENABLE }); + for cap in &mut endpoint.capabilities { + match cap { + PciCapability::Msi(msi_capability) => { + msi_capability.set_enabled(false, &mut *header.root); + } + PciCapability::MsiX(msix_capability) => { + msix_capability.set_enabled(false, &mut *header.root); + } + _ => {} + } + } + + println!( + "irq_pin {:?}, {:?}", + endpoint.interrupt_pin, endpoint.interrupt_line + ); + let bar_addr; let bar_size; match endpoint.bar { @@ -114,13 +377,23 @@ mod tests { let addr = iomap(bar_addr.into(), bar_size); - let igb = Igb::new(addr); - return Some(igb); + let igb = Igb::new(addr).unwrap(); + + let irq = pcie + .child_irq_info( + endpoint.address.bus(), + endpoint.address.device(), + endpoint.address.function(), + endpoint.interrupt_pin, + ) + .unwrap(); + return Some((igb, irq)); } } None } } + struct KernelImpl; impl_trait! {