From e9d249ef11b1f1fb3c8fc393feb0ff7bc528a053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 16 Jul 2025 15:35:34 +0800 Subject: [PATCH 01/13] update --- igb/src/descriptor.rs | 76 +++++++++++++++++++++++++++++++++++++++++++ igb/src/err.rs | 2 ++ igb/src/lib.rs | 47 ++++++++++++++++++++++---- igb/src/ring.rs | 24 ++++++++++++++ 4 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 igb/src/descriptor.rs create mode 100644 igb/src/ring.rs diff --git a/igb/src/descriptor.rs b/igb/src/descriptor.rs new file mode 100644 index 0000000..1044c40 --- /dev/null +++ b/igb/src/descriptor.rs @@ -0,0 +1,76 @@ +pub trait Descriptor {} + +#[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, +} + +#[derive(Clone, Copy)] +pub union AdvRxDesc { + pub read: AdvRxDescRead, + pub write: AdvRxDescWB, +} + +impl Descriptor for AdvRxDesc {} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct AdvRxDescRead { + pub pkt_addr: u64, + pub hdr_addr: u64, +} +#[derive(Clone, Copy)] +#[repr(C)] +pub struct AdvRxDescWB { + pub lo_dword: LoDword, + pub hi_dword: HiDword, + pub status_error: u32, + pub length: u16, + pub vlan: u16, +} + +#[derive(Clone, Copy)] +pub union LoDword { + pub data: u32, + pub hs_rss: HsRss, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct HsRss { + pub pkt_info: u16, + pub hdr_info: u16, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub union HiDword { + pub rss: u32, // RSS Hash + pub csum_ip: CsumIp, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct CsumIp { + pub ip_id: u16, // IP id + pub csum: u16, // Packet Checksum +} diff --git a/igb/src/err.rs b/igb/src/err.rs index b0fb06d..6b34093 100644 --- a/igb/src/err.rs +++ b/igb/src/err.rs @@ -4,4 +4,6 @@ pub enum DError { Unknown(&'static str), #[error("Operation timed out")] Timeout, + #[error("No memory available")] + NoMemory, } diff --git a/igb/src/lib.rs b/igb/src/lib.rs index f55b688..01e3b1c 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -8,6 +8,10 @@ use tock_registers::interfaces::*; pub use trait_ffi::impl_extern_trait; pub use crate::err::DError; +use crate::{ + descriptor::{AdvRxDesc, AdvTxDesc}, + ring::Ring, +}; extern crate alloc; @@ -15,18 +19,33 @@ mod err; mod mac; #[macro_use] pub mod osal; +mod descriptor; mod phy; +mod ring; + +const DEFAULT_RING_SIZE: usize = 256; pub struct Igb { mac: RefCell, phy: phy::Phy, + tx_ring: Ring, + rx_ring: Ring, } impl Igb { - pub fn new(iobase: NonNull) -> Self { + pub fn new(iobase: NonNull) -> Result { let mac = RefCell::new(mac::Mac::new(iobase)); let phy = phy::Phy::new(mac.clone()); - Self { mac, phy } + + let tx_ring = Ring::new(DEFAULT_RING_SIZE)?; + let rx_ring = Ring::new(DEFAULT_RING_SIZE)?; + + Ok(Self { + mac, + phy, + tx_ring, + rx_ring, + }) } pub fn open(&mut self) -> Result<(), DError> { @@ -97,7 +116,23 @@ impl Igb { // disable rx when configing. self.mac.borrow_mut().disable_rx(); - // self.rx_ring.init(); + // Program the descriptor base address with the address of the region. + + // Set the length register to the size of the descriptor ring. + + // Program SRRCTL of the queue according to the size of the buffers and the required header handling. + + // If header split or header replication is required for this queue, program the PSRTYPE register according to the required headers. + + // 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. + + // Poll the RXDCTL register until the ENABLE bit is set. The tail should not be bumped before this bit was read as one. + + // Program the direction of packets to this queue according to the mode select in MRQC. Packets directed to a disabled queue is dropped. + + // Note: The tail register of the queue (RDT[n]) should not be bumped until the queue is enabled. + + self.rx_ring.init(); // self.reg.write_reg(RCTL::RXEN | RCTL::SZ_4096); self.mac @@ -108,11 +143,11 @@ impl Igb { } fn init_tx(&mut self) { - // self.reg.write_reg(TCTL::empty()); + // self.mac.borrow_mut().reg_mut().tctl.write(mac::TCTL::empty()); - // self.tx_ring.init(); + self.tx_ring.init(); - // self.reg.write_reg(TCTL::EN); + // self.mac.borrow_mut().write_reg(TCTL::EN); } } diff --git a/igb/src/ring.rs b/igb/src/ring.rs new file mode 100644 index 0000000..3ba62ba --- /dev/null +++ b/igb/src/ring.rs @@ -0,0 +1,24 @@ +use core::cell::RefCell; + +use dma_api::{DVec, Direction}; + +use crate::{descriptor::Descriptor, err::DError, mac::Mac}; + +pub const DEFAULT_RING_SIZE: usize = 256; + +pub struct Ring { + pub descriptors: DVec, +} + +impl Ring { + pub fn new(size: usize) -> Result { + let descriptors = + DVec::zeros(size, 0x1000, Direction::Bidirectional).ok_or(DError::NoMemory)?; + + Ok(Self { descriptors }) + } + + pub fn init(&mut self) { + + } +} From dcc9b572c288445fc29df582b647439cb1de894b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 16 Jul 2025 17:09:16 +0800 Subject: [PATCH 02/13] desc --- igb/src/lib.rs | 33 +++------ igb/src/mac.rs | 28 ++++--- igb/src/ring.rs | 183 ++++++++++++++++++++++++++++++++++++++++++++-- igb/tests/test.rs | 2 +- 4 files changed, 206 insertions(+), 40 deletions(-) diff --git a/igb/src/lib.rs b/igb/src/lib.rs index 01e3b1c..86b7166 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -37,8 +37,8 @@ impl Igb { let mac = RefCell::new(mac::Mac::new(iobase)); let phy = phy::Phy::new(mac.clone()); - let tx_ring = Ring::new(DEFAULT_RING_SIZE)?; - let rx_ring = Ring::new(DEFAULT_RING_SIZE)?; + let tx_ring = Ring::new(0, iobase, DEFAULT_RING_SIZE)?; + let rx_ring = Ring::new(0, iobase, DEFAULT_RING_SIZE)?; Ok(Self { mac, @@ -71,7 +71,7 @@ impl Igb { self.init_stat(); - self.init_rx(); + self.init_rx()?; self.init_tx(); self.mac.borrow_mut().enable_interrupts(); @@ -112,40 +112,27 @@ impl Igb { //TODO } /// 4.5.9 Receive Initialization - fn init_rx(&mut self) { + fn init_rx(&mut self) -> Result<(), DError> { // disable rx when configing. self.mac.borrow_mut().disable_rx(); - // Program the descriptor base address with the address of the region. + // 初始化 ring + self.rx_ring.init()?; - // Set the length register to the size of the descriptor ring. - - // Program SRRCTL of the queue according to the size of the buffers and the required header handling. - - // If header split or header replication is required for this queue, program the PSRTYPE register according to the required headers. - - // 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. - - // Poll the RXDCTL register until the ENABLE bit is set. The tail should not be bumped before this bit was read as one. - - // Program the direction of packets to this queue according to the mode select in MRQC. Packets directed to a disabled queue is dropped. - - // Note: The tail register of the queue (RDT[n]) should not be bumped until the queue is enabled. - - self.rx_ring.init(); - - // self.reg.write_reg(RCTL::RXEN | RCTL::SZ_4096); + // 最后启用 RX self.mac .borrow_mut() .reg_mut() .rctl .modify(mac::RCTL::RXEN::Enabled); + + Ok(()) } fn init_tx(&mut self) { // self.mac.borrow_mut().reg_mut().tctl.write(mac::TCTL::empty()); - self.tx_ring.init(); + // self.tx_ring.init(); // self.mac.borrow_mut().write_reg(TCTL::EN); } diff --git a/igb/src/mac.rs b/igb/src/mac.rs index 02cbf9d..b7317c6 100644 --- a/igb/src/mac.rs +++ b/igb/src/mac.rs @@ -2,7 +2,9 @@ use core::{fmt::Debug, ptr::NonNull, time::Duration}; use log::error; use mbarrier::mb; -use tock_registers::{interfaces::*, register_bitfields, register_structs, registers::*}; +use tock_registers::{ + fields::FieldValue, interfaces::*, register_bitfields, register_structs, registers::*, +}; use crate::{DError, Speed, osal::wait_for}; @@ -20,13 +22,13 @@ register_structs! { (0x104 => _rsv7), (0x400 => tctl: ReadWrite), (0x404 => _rsv12), - (0x01524 => eims: ReadWrite), - (0x01528 => eimc: ReadWrite), - (0x0152c => eiac: ReadWrite), - (0x01530 => eiam: ReadWrite), - (0x01534 => _rsv5), - (0x01580 => eicr: ReadWrite), - (0x01584 => _rsv6), + (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 +40,7 @@ register_structs! { (0x5B60 => _rsv11), // The end of the struct is marked as follows. - (0xBFFF => @END), + (0xEFFF => @END), } } @@ -193,7 +195,9 @@ register_bitfields! [ DoNotStrip = 0, Strip = 1, ], - ] + ], + + ]; #[derive(Clone, Copy)] @@ -318,6 +322,10 @@ impl Mac { self.reg_mut().rctl.modify(RCTL::RXEN::Disabled); } + pub fn enable_rx(&mut self) { + self.reg_mut().rctl.modify(RCTL::RXEN::Enabled); + } + fn ral(&self, i: usize) -> u32 { if i <= 15 { self.reg().ralh_0_15[i * 2].get() diff --git a/igb/src/ring.rs b/igb/src/ring.rs index 3ba62ba..c383b33 100644 --- a/igb/src/ring.rs +++ b/igb/src/ring.rs @@ -1,24 +1,195 @@ -use core::cell::RefCell; +use core::{ptr::NonNull, time::Duration}; use dma_api::{DVec, Direction}; +use tock_registers::register_bitfields; -use crate::{descriptor::Descriptor, err::DError, mac::Mac}; +use crate::{ + descriptor::{AdvRxDesc, Descriptor}, + err::DError, + osal::wait_for, +}; 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 + +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 struct Ring { pub descriptors: DVec, + ring_base: NonNull, } impl Ring { - pub fn new(size: usize) -> Result { + pub fn new(idx: usize, mmio_base: NonNull, size: usize) -> Result { let descriptors = DVec::zeros(size, 0x1000, Direction::Bidirectional).ok_or(DError::NoMemory)?; - Ok(Self { descriptors }) + let ring_base = + unsafe { NonNull::new_unchecked(mmio_base.as_ptr().add(idx * 0x40) as *mut u8) }; + + Ok(Self { + descriptors, + ring_base, + }) + } + + 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() } + } +} + +impl Ring { + pub fn init(&mut self) -> Result<(), DError> { + // Program the descriptor base address with the address of the region. + self.reg_write(RDBAL, (self.bus_addr() & 0xFFFFFFFF) as u32); + self.reg_write(RDBAH, (self.bus_addr() >> 32) as u32); + + // Set the length register to the size of the descriptor ring. + self.reg_write(RDLEN, self.size_bytes() as u32); + + // 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(2)).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. + // 队列启用后,更新尾指针 + let ring_count = self.count() as u32; + self.reg_write(RDT, ring_count - 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 init(&mut self) { - + 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, + ); } } diff --git a/igb/tests/test.rs b/igb/tests/test.rs index d302ffb..1e894f5 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -114,7 +114,7 @@ mod tests { let addr = iomap(bar_addr.into(), bar_size); - let igb = Igb::new(addr); + let igb = Igb::new(addr).unwrap(); return Some(igb); } } From 09c508a22340734aafce44430a6cce748303c65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 16 Jul 2025 17:16:29 +0800 Subject: [PATCH 03/13] update --- igb/src/lib.rs | 11 ++--------- igb/src/mac.rs | 4 +--- igb/src/ring.rs | 7 +++---- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/igb/src/lib.rs b/igb/src/lib.rs index 86b7166..8213c70 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -4,13 +4,12 @@ use core::{cell::RefCell, 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, AdvTxDesc}, - ring::Ring, + ring::{DEFAULT_RING_SIZE, Ring}, }; extern crate alloc; @@ -23,8 +22,6 @@ mod descriptor; mod phy; mod ring; -const DEFAULT_RING_SIZE: usize = 256; - pub struct Igb { mac: RefCell, phy: phy::Phy, @@ -120,11 +117,7 @@ impl Igb { self.rx_ring.init()?; // 最后启用 RX - self.mac - .borrow_mut() - .reg_mut() - .rctl - .modify(mac::RCTL::RXEN::Enabled); + self.mac.borrow_mut().enable_rx(); Ok(()) } diff --git a/igb/src/mac.rs b/igb/src/mac.rs index b7317c6..f728951 100644 --- a/igb/src/mac.rs +++ b/igb/src/mac.rs @@ -2,9 +2,7 @@ use core::{fmt::Debug, ptr::NonNull, time::Duration}; use log::error; use mbarrier::mb; -use tock_registers::{ - fields::FieldValue, interfaces::*, register_bitfields, register_structs, registers::*, -}; +use tock_registers::{interfaces::*, register_bitfields, register_structs, registers::*}; use crate::{DError, Speed, osal::wait_for}; diff --git a/igb/src/ring.rs b/igb/src/ring.rs index c383b33..ebea418 100644 --- a/igb/src/ring.rs +++ b/igb/src/ring.rs @@ -17,8 +17,8 @@ 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 +// const RXCTL: usize = 0xC014; // RX Control +// const RQDPC: usize = 0xC030; // RX Descriptor Polling Control register_bitfields! [ // First parameter is the register width. Can be u8, u16, u32, or u64. @@ -71,8 +71,7 @@ impl Ring { let descriptors = DVec::zeros(size, 0x1000, Direction::Bidirectional).ok_or(DError::NoMemory)?; - let ring_base = - unsafe { NonNull::new_unchecked(mmio_base.as_ptr().add(idx * 0x40) as *mut u8) }; + let ring_base = unsafe { mmio_base.add(idx * 0x40) }; Ok(Self { descriptors, From c210a819d8104710d752f71fa58f57f645aecc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 16 Jul 2025 17:31:56 +0800 Subject: [PATCH 04/13] fix: desc --- igb/src/descriptor.rs | 390 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 377 insertions(+), 13 deletions(-) diff --git a/igb/src/descriptor.rs b/igb/src/descriptor.rs index 1044c40..634eaa4 100644 --- a/igb/src/descriptor.rs +++ b/igb/src/descriptor.rs @@ -1,5 +1,130 @@ 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 +} + +/// 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, @@ -24,53 +149,292 @@ pub struct AdvTxDescWB { 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, - pub status_error: u32, - pub length: u16, - pub vlan: u16, } #[derive(Clone, Copy)] pub union LoDword { - pub data: u32, - pub hs_rss: HsRss, + /// 完整的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 HsRss { - pub pkt_info: u16, - pub hdr_info: u16, +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 { - pub rss: u32, // RSS Hash - pub csum_ip: CsumIp, + /// 完整的64位数据 + pub data: u64, + /// 分解的字段 + pub fields: HiFields, } #[derive(Clone, Copy)] #[repr(C)] -pub struct CsumIp { - pub ip_id: u16, // IP id - pub csum: u16, // Packet Checksum +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 } + } } From 32cd193eaabbbade5c66f86787953007d337182d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 16 Jul 2025 17:50:28 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=EF=BC=8C=E6=B7=BB=E5=8A=A0=20InvalidParamete?= =?UTF-8?q?r=20=E5=8F=98=E4=BD=93=EF=BC=9B=E5=9C=A8=20Ring=20=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=B8=AD=E6=B7=BB=E5=8A=A0=E6=95=B0=E6=8D=AE=E5=8C=85?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- igb/src/err.rs | 2 ++ igb/src/ring.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/igb/src/err.rs b/igb/src/err.rs index 6b34093..9842f0a 100644 --- a/igb/src/err.rs +++ b/igb/src/err.rs @@ -6,4 +6,6 @@ pub enum DError { Timeout, #[error("No memory available")] NoMemory, + #[error("Invalid parameter")] + InvalidParameter, } diff --git a/igb/src/ring.rs b/igb/src/ring.rs index ebea418..dd68724 100644 --- a/igb/src/ring.rs +++ b/igb/src/ring.rs @@ -4,7 +4,7 @@ use dma_api::{DVec, Direction}; use tock_registers::register_bitfields; use crate::{ - descriptor::{AdvRxDesc, Descriptor}, + descriptor::{AdvRxDesc, AdvRxDescRead, Descriptor}, err::DError, osal::wait_for, }; @@ -20,6 +20,9 @@ const RXDCTL: usize = 0xC028; // RX Descriptor Control // const RXCTL: usize = 0xC014; // RX Control // const RQDPC: usize = 0xC030; // RX Descriptor Polling Control +const PACKET_SIZE_KB: u32 = 4; // 4KB packet size +const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; // 4KB in bytes + register_bitfields! [ // First parameter is the register width. Can be u8, u16, u32, or u64. u32, @@ -63,6 +66,7 @@ register_bitfields! [ pub struct Ring { pub descriptors: DVec, + packets: DVec, ring_base: NonNull, } @@ -72,10 +76,13 @@ impl Ring { DVec::zeros(size, 0x1000, Direction::Bidirectional).ok_or(DError::NoMemory)?; let ring_base = unsafe { mmio_base.add(idx * 0x40) }; + let packets = DVec::zeros(size * PACKET_SIZE as usize, 0x1000, Direction::Bidirectional) + .ok_or(DError::NoMemory)?; Ok(Self { descriptors, ring_base, + packets, }) } @@ -119,7 +126,9 @@ impl Ring { // 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(2)).value, + (SRRCTL::DESCTYPE::AdvancedOneBuffer + // 4kB 包大小 + + SRRCTL::BSIZEPACKET.val(PACKET_SIZE_KB)).value, ); // If header split or header replication is required for this queue, @@ -143,6 +152,12 @@ impl Ring { Some(1000), )?; + for i in 0..self.count() { + let paddr = self.packets.bus_addr() + i as u64 * PACKET_SIZE as u64; + let read_desc = AdvRxDescRead::new(paddr, 0, false); + self.descriptors.set(i, AdvRxDesc { read: read_desc }); + } + // Program the direction of packets to this queue according to the mode select in MRQC. // Packets directed to a disabled queue is dropped. // 暂时不配置 MRQC @@ -191,4 +206,39 @@ impl Ring { .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.lo_dword.fields.hdr_status & crate::descriptor::rx_desc_consts::DD_BIT) != 0 + } + } + + /// 获取当前头部指针值 + 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, tail: u32) { + self.reg_write(RDT, tail); + } } From d10061279ddeeaa0212e7d87bb5013bd2c6c8526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 14:28:21 +0800 Subject: [PATCH 06/13] rx --- Cargo.toml | 3 +- igb/Cargo.toml | 2 + igb/src/lib.rs | 74 ++++++++++---------- igb/src/mac.rs | 65 ++++++++++++++++-- igb/src/phy.rs | 10 ++- igb/src/ring.rs | 169 ++++++++++++++++++++++++++++++++++++++++------ igb/tests/test.rs | 95 ++++++++++++++++++++++++-- 7 files changed, 341 insertions(+), 77 deletions(-) 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..fb20ba6 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,7 @@ trait-ffi = "0.1" [dev-dependencies] bare-test = "0.4" pcie = "0.3" +spin_on = "0.1" [build-dependencies] bare-test-macros = "0.2" diff --git a/igb/src/lib.rs b/igb/src/lib.rs index 8213c70..467a066 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use core::{cell::RefCell, ptr::NonNull}; +use core::ptr::NonNull; use log::debug; pub use mac::{MacAddr6, MacStatus}; @@ -8,7 +8,7 @@ pub use trait_ffi::impl_extern_trait; pub use crate::err::DError; use crate::{ - descriptor::{AdvRxDesc, AdvTxDesc}, + descriptor::AdvRxDesc, ring::{DEFAULT_RING_SIZE, Ring}, }; @@ -22,45 +22,43 @@ mod descriptor; mod phy; mod ring; +pub use futures::{Stream, StreamExt}; +pub use ring::RxRing; + pub struct Igb { - mac: RefCell, + mac: mac::Mac, phy: phy::Phy, - tx_ring: Ring, - rx_ring: Ring, + rx_ring_addrs: [usize; 16], } impl Igb { pub fn new(iobase: NonNull) -> Result { - let mac = RefCell::new(mac::Mac::new(iobase)); - let phy = phy::Phy::new(mac.clone()); - - let tx_ring = Ring::new(0, iobase, DEFAULT_RING_SIZE)?; - let rx_ring = Ring::new(0, iobase, DEFAULT_RING_SIZE)?; + let mac = mac::Mac::new(iobase); + let phy = phy::Phy::new(mac); Ok(Self { mac, phy, - tx_ring, - rx_ring, + rx_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"); @@ -68,14 +66,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(); Ok(()) } + pub fn new_rx_ring(&mut self) -> Result { + let mut ring = Ring::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; + ring.init()?; + let mut ring = RxRing::new(ring); + self.rx_ring_addrs[0] = ring.addr().as_ptr() as usize; + Ok(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 @@ -91,7 +96,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 { @@ -102,25 +107,12 @@ impl Igb { } pub fn status(&self) -> MacStatus { - self.mac.borrow().status() + self.mac.status() } fn init_stat(&mut self) { //TODO } - /// 4.5.9 Receive Initialization - fn init_rx(&mut self) -> Result<(), DError> { - // disable rx when configing. - self.mac.borrow_mut().disable_rx(); - - // 初始化 ring - self.rx_ring.init()?; - - // 最后启用 RX - self.mac.borrow_mut().enable_rx(); - - Ok(()) - } fn init_tx(&mut self) { // self.mac.borrow_mut().reg_mut().tctl.write(mac::TCTL::empty()); @@ -129,6 +121,18 @@ impl Igb { // self.mac.borrow_mut().write_reg(TCTL::EN); } + + /// # 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(); + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/igb/src/mac.rs b/igb/src/mac.rs index f728951..93dbd7e 100644 --- a/igb/src/mac.rs +++ b/igb/src/mac.rs @@ -195,7 +195,37 @@ register_bitfields! [ ], ], + // 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)[], + ], ]; #[derive(Clone, Copy)] @@ -208,6 +238,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) @@ -250,12 +284,26 @@ 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); + } + + 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 { @@ -288,11 +336,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 { @@ -360,6 +404,13 @@ impl Mac { } } +#[derive(Debug, Clone)] +pub struct IrqMsg { + pub queue_idx: u16, + pub tcp_timer: bool, + pub other: bool, +} + #[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.rs b/igb/src/ring.rs index dd68724..2380dfe 100644 --- a/igb/src/ring.rs +++ b/igb/src/ring.rs @@ -1,7 +1,10 @@ -use core::{ptr::NonNull, time::Duration}; +use core::{cell::UnsafeCell, ops::Deref, pin::Pin, ptr::NonNull, time::Duration}; -use dma_api::{DVec, Direction}; +use alloc::{boxed::Box, vec::Vec}; +use dma_api::{DSlice, DSliceMut, DVec, Direction}; +use mbarrier::mb; use tock_registers::register_bitfields; +use futures::{stream::Stream, task::AtomicWaker}; use crate::{ descriptor::{AdvRxDesc, AdvRxDescRead, Descriptor}, @@ -20,8 +23,8 @@ const RXDCTL: usize = 0xC028; // RX Descriptor Control // const RXCTL: usize = 0xC014; // RX Control // const RQDPC: usize = 0xC030; // RX Descriptor Polling Control -const PACKET_SIZE_KB: u32 = 4; // 4KB packet size -const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; // 4KB in bytes +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. @@ -64,10 +67,20 @@ register_bitfields! [ ] ]; +#[derive(Default, Clone)] +struct RingElemMeta{ + // waker: AtomicWaker, + // is_done: bool, + buff_ptr: usize, +} + pub struct Ring { pub descriptors: DVec, - packets: DVec, ring_base: NonNull, + current_head: usize, + ring_head: usize, + waker: AtomicWaker, + meta_ls: Vec, } impl Ring { @@ -76,13 +89,14 @@ impl Ring { DVec::zeros(size, 0x1000, Direction::Bidirectional).ok_or(DError::NoMemory)?; let ring_base = unsafe { mmio_base.add(idx * 0x40) }; - let packets = DVec::zeros(size * PACKET_SIZE as usize, 0x1000, Direction::Bidirectional) - .ok_or(DError::NoMemory)?; - + Ok(Self { descriptors, ring_base, - packets, + waker: AtomicWaker::new(), + current_head: 0, + ring_head: 0, + meta_ls: alloc::vec![RingElemMeta::default(); size], }) } @@ -151,21 +165,12 @@ impl Ring { Duration::from_millis(1), Some(1000), )?; - - for i in 0..self.count() { - let paddr = self.packets.bus_addr() + i as u64 * PACKET_SIZE as u64; - let read_desc = AdvRxDescRead::new(paddr, 0, false); - self.descriptors.set(i, AdvRxDesc { read: read_desc }); - } - + // 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. - // 队列启用后,更新尾指针 - let ring_count = self.count() as u32; - self.reg_write(RDT, ring_count - 1); Ok(()) } @@ -238,7 +243,129 @@ impl Ring { } /// 更新尾部指针 - pub fn update_tail(&mut self, tail: u32) { - self.reg_write(RDT, tail); + pub fn update_tail(&mut self) { + self.reg_write(RDT, self.current_head as u32); + } + + pub fn clean(&mut self) { + // 清理环形缓冲区 + self.ring_head = self.get_head() as usize; + } + + fn packet_buff(&mut self, index: usize) -> &mut [u8] { + let ptr = self.meta_ls[index].buff_ptr; + let buff = unsafe{ + core::slice::from_raw_parts_mut(ptr as *mut u8, PACKET_SIZE as usize) + }; + { + let sl = DSliceMut::from(buff, Direction::FromDevice); + sl.preper_read_all(); + } + buff + } + + fn rcv_buff(&mut self, buff: &mut [u8]) -> Result<(), DError> { + assert!(buff.len() >= PACKET_SIZE as usize, "Buffer too small for packet"); + assert!(buff.len().is_multiple_of(PACKET_SIZE as usize), "Buffer size must be a multiple of packet size"); + let mut bus_addr = { + let sl = DSliceMut::from(buff, Direction::FromDevice); + sl.bus_addr() + }; + + let mut i = self.reg_read(RDT); + + let mut buff_left = buff; + while !buff_left.is_empty() { + let desc = AdvRxDesc{read: AdvRxDescRead { pkt_addr: bus_addr, hdr_addr: 0 }}; + self.descriptors.set(i as usize, desc); + self.meta_ls[i as usize].buff_ptr = buff_left.as_mut_ptr() as usize; + + i += 1; + if i >= self.count() as u32{ + i = 0; + } + bus_addr += PACKET_SIZE as u64; + buff_left = &mut buff_left[PACKET_SIZE as usize..]; + } + mb(); + self.reg_write(RDT, i); + + Ok(()) } } + +pub struct RxRing(UnsafeCell>>); + +impl RxRing{ + pub(crate) fn new(ring: Ring) -> Self { + Self(UnsafeCell::new( Box::new(ring))) + } + + pub(crate) fn addr(&mut self) -> NonNull> { + unsafe{ NonNull::from( (*self.0.get()).as_mut())} + } + + pub async fn recv(&mut self, buff: &mut [u8])->Result<(), DError> { + self.this_mut().rcv_buff(buff)?; + + RcvFuture::new(self, buff).await?; + + DSliceMut::from(buff, Direction::FromDevice) + .preper_read_all(); + + Ok(()) + } + + fn this(&self) -> &Ring { + unsafe { &*self.0.get() } + } + fn this_mut(&mut self) -> &mut Ring { + unsafe { &mut *self.0.get() } + } + + pub fn packet_size(&self) -> usize { + PACKET_SIZE as usize + } +} + +pub struct RcvFuture<'a> { + ring: &'a mut RxRing, + buffer: &'a mut [u8], + n: usize, +} + +impl<'a> RcvFuture<'a> { + pub fn new(ring: &'a mut RxRing, buffer: &'a mut [u8]) -> Self { + Self { ring, buffer, n: 0 } + } +} + +impl <'a> Future for RcvFuture<'a> { + type Output = Result<(), DError>; + + fn poll(self: Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll { + let this = self.get_mut(); + let ring = unsafe { &mut *this.ring.0.get() }; + + while this.n < this.buffer.len() && ring.current_head != ring.ring_head { + if !ring.is_descriptor_done(ring.current_head){ + break; + } + ring.current_head += 1; + if ring.current_head >= ring.count() { + ring.current_head = 0; + } + this.n += PACKET_SIZE as usize; + } + + if this.n == this.buffer.len() { + // 已经接收完所有数据 + return core::task::Poll::Ready(Ok(())); + } + + // 没有可用的描述符,注册唤醒器 + ring.waker.register(cx.waker()); + core::task::Poll::Pending + } + +} \ No newline at end of file diff --git a/igb/tests/test.rs b/igb/tests/test.rs index 1e894f5..f4d99ba 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -5,31 +5,79 @@ use core::time::Duration; use bare_test::time::spin_delay; -use eth_igb::{impl_trait, osal::Kernel}; +use eth_igb::{Stream, StreamExt, 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 futures::StreamExt; use log::info; - use pcie::{CommandRegister, RootComplexGeneric, SimpleBarAllocator}; + use pcie::{CommandRegister, PciCapability, RootComplexGeneric, SimpleBarAllocator}; + + 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() } + } + } + impl Driver { + pub fn new(inner: T) -> Self { + Self(UnsafeCell::new(inner)) + } + } #[test] fn it_works() { - let mut igb = get_igb().unwrap(); + let (mut 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(); + } + + let mut rx = igb.new_rx_ring().unwrap(); + igb.open().unwrap(); info!("igb opened: {:#?}", igb.status()); @@ -42,10 +90,17 @@ mod tests { info!("status: {:#?}", igb.status()); } + spin_on::spin_on(async move { + info!("link up, starting to receive packets..."); + let mut buff = alloc::vec![0u8; rx.packet_size() * 10]; + rx.recv(&mut buff).await.unwrap(); + info!("Received {} bytes", buff.len()); + }); + println!("test passed!"); } - fn get_igb() -> Option { + fn get_igb() -> Option<(Igb, IrqInfo)> { let PlatformInfoKind::DeviceTree(fdt) = &global_val().platform_info; let fdt = fdt.get(); @@ -83,7 +138,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 +149,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 { @@ -115,7 +187,16 @@ mod tests { let addr = iomap(bar_addr.into(), bar_size); let igb = Igb::new(addr).unwrap(); - return Some(igb); + + let irq = pcie + .child_irq_info( + endpoint.address.bus(), + endpoint.address.device(), + endpoint.address.function(), + endpoint.interrupt_pin, + ) + .unwrap(); + return Some((igb, irq)); } } None From 53fc62f375f7b0b0a145daa510d804fc4b5b8037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 14:34:49 +0800 Subject: [PATCH 07/13] tx not impl --- igb/src/lib.rs | 16 +++++++++++++--- igb/src/ring.rs | 39 ++++++++++++++++++++++++++++++++++++++- igb/tests/test.rs | 1 + 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/igb/src/lib.rs b/igb/src/lib.rs index 467a066..62d30b7 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -8,8 +8,8 @@ pub use trait_ffi::impl_extern_trait; pub use crate::err::DError; use crate::{ - descriptor::AdvRxDesc, - ring::{DEFAULT_RING_SIZE, Ring}, + descriptor::{AdvRxDesc, AdvTxDesc}, + ring::{DEFAULT_RING_SIZE, Ring, TxRing}, }; extern crate alloc; @@ -29,6 +29,7 @@ pub struct Igb { mac: mac::Mac, phy: phy::Phy, rx_ring_addrs: [usize; 16], + tx_ring_addrs: [usize; 16], } impl Igb { @@ -40,6 +41,7 @@ impl Igb { mac, phy, rx_ring_addrs: [0; 16], + tx_ring_addrs: [0; 16], }) } @@ -74,13 +76,21 @@ impl Igb { } pub fn new_rx_ring(&mut self) -> Result { - let mut ring = Ring::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; + let mut ring: Ring = Ring::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; ring.init()?; let mut ring = RxRing::new(ring); self.rx_ring_addrs[0] = ring.addr().as_ptr() as usize; Ok(ring) } + pub fn new_tx_ring(&mut self) -> Result { + let mut ring: Ring = Ring::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; + ring.init()?; + let mut ring = TxRing::new(ring); + self.tx_ring_addrs[0] = ring.addr().as_ptr() as usize; + Ok(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 diff --git a/igb/src/ring.rs b/igb/src/ring.rs index 2380dfe..c1c9814 100644 --- a/igb/src/ring.rs +++ b/igb/src/ring.rs @@ -7,7 +7,7 @@ use tock_registers::register_bitfields; use futures::{stream::Stream, task::AtomicWaker}; use crate::{ - descriptor::{AdvRxDesc, AdvRxDescRead, Descriptor}, + descriptor::{AdvRxDesc, AdvRxDescRead, AdvTxDesc, Descriptor}, err::DError, osal::wait_for, }; @@ -368,4 +368,41 @@ impl <'a> Future for RcvFuture<'a> { core::task::Poll::Pending } +} + + +impl Ring { + + pub fn init(&mut self) -> Result<(), DError> { + + // 初始化 TX 描述符环 + // 这里可以添加 TX 描述符的初始化逻辑 + Ok(()) + } +} + +pub struct TxRing(UnsafeCell>>); + +impl TxRing { + pub(crate) fn new(ring: Ring) -> Self { + Self(UnsafeCell::new(Box::new(ring))) + } + + pub(crate) fn addr(&mut self) -> NonNull> { + unsafe { NonNull::from((*self.0.get()).as_mut()) } + } + + pub fn this(&self) -> &Ring { + unsafe { &*self.0.get() } + } + + pub fn this_mut(&mut self) -> &mut Ring { + unsafe { &mut *self.0.get() } + } + + pub async fn send(&mut self, buff: &[u8]) -> Result<(), DError> { + // 发送数据包 + // 这里可以添加发送逻辑 + Ok(()) + } } \ No newline at end of file diff --git a/igb/tests/test.rs b/igb/tests/test.rs index f4d99ba..eea2198 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -77,6 +77,7 @@ mod tests { } let mut rx = igb.new_rx_ring().unwrap(); + let mut tx = igb.new_tx_ring().unwrap(); igb.open().unwrap(); info!("igb opened: {:#?}", igb.status()); From 8f6db5a57a81218427f7be067bfd2b596a2f7113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 16:00:52 +0800 Subject: [PATCH 08/13] tx --- igb/src/descriptor.rs | 22 ++++++ igb/src/lib.rs | 15 ++-- igb/src/mac.rs | 32 +++++++- igb/src/ring.rs | 150 ++++++++++++++++++++++++++++++++++--- igb/tests/test.rs | 168 ++++++++++++++++++++++++++++++++++++++---- 5 files changed, 353 insertions(+), 34 deletions(-) diff --git a/igb/src/descriptor.rs b/igb/src/descriptor.rs index 634eaa4..4c97dc0 100644 --- a/igb/src/descriptor.rs +++ b/igb/src/descriptor.rs @@ -69,6 +69,28 @@ pub mod rx_desc_consts { 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 = 0 << 20; // Data descriptor + pub const DTYPE_CONTEXT: u32 = 1 << 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)] diff --git a/igb/src/lib.rs b/igb/src/lib.rs index 62d30b7..4c10178 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -71,6 +71,7 @@ impl Igb { self.mac.enable_interrupts(); self.mac.enable_rx(); + self.mac.enable_tx(); Ok(()) } @@ -120,16 +121,16 @@ impl Igb { self.mac.status() } - fn init_stat(&mut self) { - //TODO + pub fn enable_loopback(&mut self) { + self.mac.enable_loopback(); } - fn init_tx(&mut self) { - // self.mac.borrow_mut().reg_mut().tctl.write(mac::TCTL::empty()); - - // self.tx_ring.init(); + pub fn disable_loopback(&mut self) { + self.mac.disable_loopback(); + } - // self.mac.borrow_mut().write_reg(TCTL::EN); + fn init_stat(&mut self) { + //TODO } /// # Safety diff --git a/igb/src/mac.rs b/igb/src/mac.rs index 93dbd7e..d1a362d 100644 --- a/igb/src/mac.rs +++ b/igb/src/mac.rs @@ -18,7 +18,7 @@ register_structs! { (0x24 => _rsv4), (0x100 => pub rctl: ReadWrite), (0x104 => _rsv7), - (0x400 => tctl: ReadWrite), + (0x400 => tctl: ReadWrite), (0x404 => _rsv12), (0x1524 => eims: ReadWrite), (0x1528 => eimc: ReadWrite), @@ -195,6 +195,24 @@ register_bitfields! [ ], ], + // 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) @@ -368,6 +386,18 @@ impl Mac { 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); + } + fn ral(&self, i: usize) -> u32 { if i <= 15 { self.reg().ralh_0_15[i * 2].get() diff --git a/igb/src/ring.rs b/igb/src/ring.rs index c1c9814..675ac34 100644 --- a/igb/src/ring.rs +++ b/igb/src/ring.rs @@ -1,10 +1,11 @@ -use core::{cell::UnsafeCell, ops::Deref, pin::Pin, ptr::NonNull, time::Duration}; +use core::{cell::UnsafeCell, pin::Pin, ptr::NonNull, time::Duration}; use alloc::{boxed::Box, vec::Vec}; use dma_api::{DSlice, DSliceMut, DVec, Direction}; +use log::debug; use mbarrier::mb; use tock_registers::register_bitfields; -use futures::{stream::Stream, task::AtomicWaker}; +use futures::task::AtomicWaker; use crate::{ descriptor::{AdvRxDesc, AdvRxDescRead, AdvTxDesc, Descriptor}, @@ -23,6 +24,16 @@ 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 TWDBAH: usize = 0xE03C; // TX Descriptor Write Back Address High + const PACKET_SIZE_KB: u32 = 2; const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; @@ -64,7 +75,20 @@ register_bitfields! [ 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)] @@ -228,7 +252,7 @@ impl Ring { let desc = &self.descriptors[desc_index]; unsafe { let wb = desc.write; - (wb.lo_dword.fields.hdr_status & crate::descriptor::rx_desc_consts::DD_BIT) != 0 + (wb.hi_dword.fields.error_type_status & crate::descriptor::rx_desc_consts::DD_BIT) != 0 } } @@ -372,11 +396,118 @@ impl <'a> Future for RcvFuture<'a> { impl Ring { - 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); + } + + 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); // 环形缓冲区已满 + } + + // 准备DMA缓冲区 + let dma_buff = { + let sl = DSlice::from(buff); + sl.bus_addr() + }; + + // 设置描述符 + let desc = AdvTxDesc { + read: crate::descriptor::AdvTxDescRead { + buffer_addr: dma_buff, + 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); - // 初始化 TX 描述符环 - // 这里可以添加 TX 描述符的初始化逻辑 Ok(()) } } @@ -401,8 +532,7 @@ impl TxRing { } pub async fn send(&mut self, buff: &[u8]) -> Result<(), DError> { - // 发送数据包 - // 这里可以添加发送逻辑 - Ok(()) + self.this_mut().send_packet(buff) } + } \ No newline at end of file diff --git a/igb/tests/test.rs b/igb/tests/test.rs index eea2198..f93bc4c 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -5,7 +5,7 @@ use core::time::Duration; use bare_test::time::spin_delay; -use eth_igb::{Stream, StreamExt, impl_trait, osal::Kernel}; +use eth_igb::{impl_trait, osal::Kernel}; extern crate alloc; extern crate bare_test; @@ -28,7 +28,6 @@ mod tests { time::spin_delay, }; use eth_igb::Igb; - use futures::StreamExt; use log::info; use pcie::{CommandRegister, PciCapability, RootComplexGeneric, SimpleBarAllocator}; @@ -51,9 +50,59 @@ mod tests { } } + // #[test] + // fn it_works() { + // 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(); + // } + + // let mut rx = igb.new_rx_ring().unwrap(); + // let _tx = igb.new_tx_ring().unwrap(); + + // igb.open().unwrap(); + // info!("igb opened: {:#?}", igb.status()); + + // info!("mac: {:#?}", igb.read_mac()); + + // info!("waiting for link up..."); + // while !igb.status().link_up { + // spin_delay(Duration::from_secs(1)); + + // info!("status: {:#?}", igb.status()); + // } + + // spin_on::spin_on(async move { + // info!("link up, starting to receive packets..."); + // let mut buff = alloc::vec![0u8; rx.packet_size() * 10]; + // rx.recv(&mut buff).await.unwrap(); + // info!("Received {} bytes", buff.len()); + // }); + + // println!("test passed!"); + // } + #[test] - fn it_works() { - let (mut igb, irq) = get_igb().unwrap(); + fn loopback_test() { + let (igb, irq) = get_igb().unwrap(); info!("igb: {:#?}", igb.status()); @@ -76,29 +125,48 @@ mod tests { .register(); } - let mut rx = igb.new_rx_ring().unwrap(); - let mut tx = igb.new_tx_ring().unwrap(); - igb.open().unwrap(); - info!("igb opened: {:#?}", igb.status()); - - info!("mac: {:#?}", igb.read_mac()); + info!("igb opened for loopback test: {:#?}", igb.status()); + // igb.enable_loopback(); + // info!("Loopback mode enabled"); + 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()); } + let mut rx = igb.new_rx_ring().unwrap(); + let mut tx = igb.new_tx_ring().unwrap(); spin_on::spin_on(async move { - info!("link up, starting to receive packets..."); - let mut buff = alloc::vec![0u8; rx.packet_size() * 10]; - rx.recv(&mut buff).await.unwrap(); - info!("Received {} bytes", buff.len()); + info!("link up, starting loopback test..."); + + // 创建测试数据包 + let test_packet = create_test_packet(&mac.bytes()); + info!("Created test packet with {} bytes", test_packet.len()); + + // 发送测试数据包 + info!("Sending test packet..."); + tx.send(&test_packet).await.unwrap(); + info!("Test packet sent"); + + // 接收数据包 + let mut rx_buff = alloc::vec![0u8; rx.packet_size() * 2]; + info!("Waiting to receive packet..."); + rx.recv(&mut rx_buff).await.unwrap(); + info!("Received {} bytes", rx_buff.len()); + + // 验证收到的数据包 + if verify_loopback_packet(&test_packet, &rx_buff) { + info!("✓ Loopback test passed! Packet correctly received"); + } else { + info!("✗ Loopback test failed! Received packet doesn't match sent packet"); + } }); - println!("test passed!"); + println!("loopback test completed!"); } fn get_igb() -> Option<(Igb, IrqInfo)> { @@ -202,6 +270,74 @@ mod tests { } None } + + fn create_test_packet(mac_src: &[u8]) -> alloc::vec::Vec { + // 创建一个简单的以太网帧用于回环测试 + let mut packet = alloc::vec::Vec::new(); + + // 目标MAC地址 (广播地址) + packet.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); + + // 源MAC地址 (测试地址) + packet.extend_from_slice(mac_src); + + // 以太网类型 (IPv4) + packet.extend_from_slice(&[0x08, 0x00]); + + // 简单的IPv4头部 + packet.extend_from_slice(&[ + 0x45, 0x00, 0x00, 0x2E, // Version, IHL, Type of Service, Total Length + 0x00, 0x00, 0x40, 0x00, // Identification, Flags, Fragment Offset + 0x40, 0x01, 0x00, 0x00, // TTL, Protocol (ICMP), Header Checksum + 0xC0, 0xA8, 0x01, 0x01, // Source IP (192.168.1.1) + 0xC0, 0xA8, 0x01, 0x02, // Destination IP (192.168.1.2) + ]); + + // ICMP 头部和数据 + packet.extend_from_slice(&[ + 0x08, 0x00, 0x00, 0x00, // Type (Echo Request), Code, Checksum + 0x12, 0x34, 0x56, 0x78, // Identifier, Sequence Number + ]); + + // 测试数据 + packet.extend_from_slice(b"Hello, Loopback Test!"); + + // 填充到最小以太网帧大小 + while packet.len() < 60 { + packet.push(0x00); + } + packet + } + + fn verify_loopback_packet(sent_packet: &[u8], received_buffer: &[u8]) -> bool { + // 在接收缓冲区中查找发送的数据包 + let packet_size = sent_packet.len(); + + // 搜索缓冲区中是否包含我们发送的数据包 + for i in 0..received_buffer.len() { + if i + packet_size <= received_buffer.len() { + let chunk = &received_buffer[i..i + packet_size]; + if chunk == sent_packet { + info!("Found matching packet at offset {i}"); + return true; + } + } + } + + // 如果没有找到完全匹配的数据包,至少检查一下是否接收到了数据 + let non_zero_bytes = received_buffer.iter().filter(|&&b| b != 0).count(); + info!( + "Received {non_zero_bytes} non-zero bytes out of {}", + received_buffer.len() + ); + + // 检查接收到的数据包的前几个字节 + if received_buffer.len() >= 14 { + info!("Received packet header: {:02x?}", &received_buffer[0..14]); + } + + false + } } struct KernelImpl; From f4ef903c3b046cc2e29a6301948dcf2075ad074a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 17:53:14 +0800 Subject: [PATCH 09/13] update --- igb/Cargo.toml | 1 + igb/bare-test.toml | 2 +- igb/src/lib.rs | 4 +- igb/src/{ring.rs => ring/mod.rs} | 238 +++------------------- igb/src/ring/rx.rs | 247 ++++++++++++++++++++++ igb/tests/test.rs | 340 ++++++++++++++++++------------- 6 files changed, 483 insertions(+), 349 deletions(-) rename igb/src/{ring.rs => ring/mod.rs} (62%) create mode 100644 igb/src/ring/rx.rs diff --git a/igb/Cargo.toml b/igb/Cargo.toml index fb20ba6..b1e532f 100644 --- a/igb/Cargo.toml +++ b/igb/Cargo.toml @@ -15,6 +15,7 @@ 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] diff --git a/igb/bare-test.toml b/igb/bare-test.toml index aa7228a..2d1d254 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/lib.rs b/igb/src/lib.rs index 4c10178..a65490c 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -9,7 +9,7 @@ pub use trait_ffi::impl_extern_trait; pub use crate::err::DError; use crate::{ descriptor::{AdvRxDesc, AdvTxDesc}, - ring::{DEFAULT_RING_SIZE, Ring, TxRing}, + ring::{DEFAULT_RING_SIZE, Ring}, }; extern crate alloc; @@ -23,7 +23,7 @@ mod phy; mod ring; pub use futures::{Stream, StreamExt}; -pub use ring::RxRing; +pub use ring::{RxRing, TxRing}; pub struct Igb { mac: mac::Mac, diff --git a/igb/src/ring.rs b/igb/src/ring/mod.rs similarity index 62% rename from igb/src/ring.rs rename to igb/src/ring/mod.rs index 675ac34..e77b383 100644 --- a/igb/src/ring.rs +++ b/igb/src/ring/mod.rs @@ -13,6 +13,8 @@ use crate::{ osal::wait_for, }; +mod rx; + 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 @@ -93,20 +95,19 @@ register_bitfields! [ #[derive(Default, Clone)] struct RingElemMeta{ - // waker: AtomicWaker, - // is_done: bool, buff_ptr: usize, } -pub struct Ring { +struct Ring { pub descriptors: DVec, ring_base: NonNull, current_head: usize, - ring_head: usize, + hw_head: usize, waker: AtomicWaker, - meta_ls: Vec, + meta_ls: Vec, } + impl Ring { pub fn new(idx: usize, mmio_base: NonNull, size: usize) -> Result { let descriptors = @@ -119,7 +120,7 @@ impl Ring { ring_base, waker: AtomicWaker::new(), current_head: 0, - ring_head: 0, + hw_head: 0, meta_ls: alloc::vec![RingElemMeta::default(); size], }) } @@ -153,128 +154,7 @@ impl Ring { } impl Ring { - pub fn init(&mut self) -> Result<(), DError> { - // Program the descriptor base address with the address of the region. - self.reg_write(RDBAL, (self.bus_addr() & 0xFFFFFFFF) as u32); - self.reg_write(RDBAH, (self.bus_addr() >> 32) as u32); - - // Set the length register to the size of the descriptor ring. - self.reg_write(RDLEN, self.size_bytes() as u32); - - // Program SRRCTL of the queue according to the size of the buffers and the required header handling. - self.reg_write( - SRRCTL, - (SRRCTL::DESCTYPE::AdvancedOneBuffer - // 4kB 包大小 - + SRRCTL::BSIZEPACKET.val(PACKET_SIZE_KB)).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. - - 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.hi_dword.fields.error_type_status & crate::descriptor::rx_desc_consts::DD_BIT) != 0 - } - } - - /// 获取当前头部指针值 - 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) { - self.reg_write(RDT, self.current_head as u32); - } - - pub fn clean(&mut self) { - // 清理环形缓冲区 - self.ring_head = self.get_head() as usize; - } + fn packet_buff(&mut self, index: usize) -> &mut [u8] { let ptr = self.meta_ls[index].buff_ptr; @@ -296,6 +176,7 @@ impl Ring { sl.bus_addr() }; + self.buffer.set(buff); let mut i = self.reg_read(RDT); let mut buff_left = buff; @@ -311,6 +192,7 @@ impl Ring { bus_addr += PACKET_SIZE as u64; buff_left = &mut buff_left[PACKET_SIZE as usize..]; } + mb(); self.reg_write(RDT, i); @@ -318,82 +200,6 @@ impl Ring { } } -pub struct RxRing(UnsafeCell>>); - -impl RxRing{ - pub(crate) fn new(ring: Ring) -> Self { - Self(UnsafeCell::new( Box::new(ring))) - } - - pub(crate) fn addr(&mut self) -> NonNull> { - unsafe{ NonNull::from( (*self.0.get()).as_mut())} - } - - pub async fn recv(&mut self, buff: &mut [u8])->Result<(), DError> { - self.this_mut().rcv_buff(buff)?; - - RcvFuture::new(self, buff).await?; - - DSliceMut::from(buff, Direction::FromDevice) - .preper_read_all(); - - Ok(()) - } - - fn this(&self) -> &Ring { - unsafe { &*self.0.get() } - } - fn this_mut(&mut self) -> &mut Ring { - unsafe { &mut *self.0.get() } - } - - pub fn packet_size(&self) -> usize { - PACKET_SIZE as usize - } -} - -pub struct RcvFuture<'a> { - ring: &'a mut RxRing, - buffer: &'a mut [u8], - n: usize, -} - -impl<'a> RcvFuture<'a> { - pub fn new(ring: &'a mut RxRing, buffer: &'a mut [u8]) -> Self { - Self { ring, buffer, n: 0 } - } -} - -impl <'a> Future for RcvFuture<'a> { - type Output = Result<(), DError>; - - fn poll(self: Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll { - let this = self.get_mut(); - let ring = unsafe { &mut *this.ring.0.get() }; - - while this.n < this.buffer.len() && ring.current_head != ring.ring_head { - if !ring.is_descriptor_done(ring.current_head){ - break; - } - ring.current_head += 1; - if ring.current_head >= ring.count() { - ring.current_head = 0; - } - this.n += PACKET_SIZE as usize; - } - - if this.n == this.buffer.len() { - // 已经接收完所有数据 - return core::task::Poll::Ready(Ok(())); - } - - // 没有可用的描述符,注册唤醒器 - ring.waker.register(cx.waker()); - core::task::Poll::Pending - } - -} - impl Ring { pub fn init(&mut self) -> Result<(), DError> { @@ -470,7 +276,7 @@ impl Ring { if buff.len() > PACKET_SIZE as usize { return Err(DError::InvalidParameter); } - + let tail = self.get_tx_tail() as usize; let next_tail = (tail + 1) % self.count(); let head = self.get_tx_head() as usize; @@ -532,7 +338,27 @@ impl TxRing { } pub async fn send(&mut self, buff: &[u8]) -> Result<(), DError> { - self.this_mut().send_packet(buff) + debug!("tx send {}", buff.len()); + for chuck in buff.chunks(PACKET_SIZE as usize) { + self.this_mut().send_packet(chuck)?; + } + Ok(()) } +} + + +#[derive(Default)] +struct Buffer{ + ptr: usize, + len: usize, + n: usize, +} + +impl Buffer { + fn set(&mut self, buff: &[u8]) { + self.ptr = buff.as_ptr() as usize; + self.len = buff.len(); + self.n = 0; + } } \ No newline at end of file diff --git a/igb/src/ring/rx.rs b/igb/src/ring/rx.rs new file mode 100644 index 0000000..3a1dbba --- /dev/null +++ b/igb/src/ring/rx.rs @@ -0,0 +1,247 @@ +use core::ops::{Deref, DerefMut}; + +use alloc::{sync::Arc, vec::Vec}; +use dma_api::DVec; +use super::*; +use crate::{descriptor::AdvRxDesc, DError}; + +struct RingInner { + base: Ring, + pkts: Vec>, +} + +impl RingInner { + fn new(ring: Ring, pkt_size: usize) -> Result< Self, DError> { + let mut pkts = Vec::with_capacity(ring.count()); + for _ in 0..ring.count() { + pkts.push(DVec::zeros(pkt_size, pkt_size, Direction::FromDevice).ok_or(DError::NoMemory)?); + } + Ok( Self { base:ring, pkts }) + } + + 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); + + // Program SRRCTL of the queue according to the size of the buffers and the required header handling. + self.reg_write( + SRRCTL, + (SRRCTL::DESCTYPE::AdvancedOneBuffer + // 4kB 包大小 + + SRRCTL::BSIZEPACKET.val(PACKET_SIZE_KB)).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. + + 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.hi_dword.fields.error_type_status & crate::descriptor::rx_desc_consts::DD_BIT) != 0 + } + } + + /// 获取当前头部指针值 + 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) { + let tail = self.current_head; + 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)?; + let ring_inner = RingInner::new(base, PACKET_SIZE as usize)?; + let ring = Arc::new(UnsafeCell::new(ring_inner)); + Ok(Self(ring)) + } + + pub(crate) fn addr(&mut self) -> NonNull> { + unsafe{ NonNull::from( (*self.0.get()).as_mut())} + } + + pub async fn recv(&mut self, buff: &mut [u8])->Result<(), DError> { + self.this_mut().rcv_buff(buff)?; + + RcvFuture::new(self).await?; + + DSliceMut::from(buff, Direction::FromDevice) + .preper_read_all(); + + Ok(()) + } + + fn this(&self) -> &Ring { + unsafe { &*self.0.get() } + } + fn this_mut(&mut self) -> &mut Ring { + unsafe { &mut *self.0.get() } + } + + pub fn packet_size(&self) -> usize { + PACKET_SIZE as usize + } +} + +pub struct RcvFuture<'a> { + ring: &'a mut RxRing, +} + +impl<'a> RcvFuture<'a> { + pub fn new(ring: &'a mut RxRing) -> Self { + Self { ring } + } +} + +impl <'a> Future for RcvFuture<'a> { + type Output = Result<(), DError>; + + fn poll(self: Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll { + let this = self.get_mut(); + let ring = unsafe { &mut *this.ring.0.get() }; + + while this.n < this.buffer.len() && ring.current_head != ring.hw_head { + if !ring.is_descriptor_done(ring.current_head){ + break; + } + ring.current_head += 1; + if ring.current_head >= ring.count() { + ring.current_head = 0; + } + this.n += PACKET_SIZE as usize; + } + + if this.n == this.buffer.len() { + // 已经接收完所有数据 + return core::task::Poll::Ready(Ok(())); + } + + // 没有可用的描述符,注册唤醒器 + ring.waker.register(cx.waker()); + core::task::Poll::Pending + } +} + diff --git a/igb/tests/test.rs b/igb/tests/test.rs index f93bc4c..089f3e5 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -2,13 +2,13 @@ #![no_main] #![feature(used_with_arg)] +use core::future::Future; use core::time::Duration; 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 { @@ -28,8 +28,17 @@ mod tests { time::spin_delay, }; use eth_igb::Igb; - use log::info; + use log::{debug, info}; use pcie::{CommandRegister, PciCapability, RootComplexGeneric, SimpleBarAllocator}; + use smoltcp::phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken}; + use smoltcp::socket::icmp::{self, Socket as IcmpSocket}; + use smoltcp::storage::PacketMetadata; + use smoltcp::time::Instant; + use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; + use smoltcp::{ + iface::{Config, Interface, SocketSet}, + wire::HardwareAddress, + }; struct Driver(UnsafeCell); impl Deref for Driver { @@ -44,64 +53,114 @@ mod tests { 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)) } } - // #[test] - // fn it_works() { - // let (igb, irq) = get_igb().unwrap(); + // SmolTCP device adapter for IGB + struct IgbDevice { + rx_ring: eth_igb::RxRing, + tx_ring: eth_igb::TxRing, + rx_buffer: alloc::vec::Vec, + } - // info!("igb: {:#?}", igb.status()); + impl IgbDevice { + fn new(rx_ring: eth_igb::RxRing, tx_ring: eth_igb::TxRing) -> Self { + let rx_buffer = alloc::vec![0u8; rx_ring.packet_size() * 2]; + Self { + rx_ring, + tx_ring, + rx_buffer, + } + } + } - // let mut igb = Driver::new(igb); - // let igb_ptr = igb.0.get(); + 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<'_>)> { + // // 尝试接收数据包 + // let rx_token = IgbRxToken { + // rx_ring: &mut self.rx_ring, + // buffer: &mut self.rx_buffer, + // }; + // let tx_token = IgbTxToken { + // tx_ring: &mut self.tx_ring, + // }; + // Some((rx_token, tx_token)) + None + } - // 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(); - // } + fn transmit(&mut self, _timestamp: Instant) -> Option> { + Some(IgbTxToken { + tx_ring: &mut self.tx_ring, + }) + } - // let mut rx = igb.new_rx_ring().unwrap(); - // let _tx = igb.new_tx_ring().unwrap(); + 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> { + rx_ring: &'a mut eth_igb::RxRing, + buffer: &'a mut [u8], + } - // igb.open().unwrap(); - // info!("igb opened: {:#?}", igb.status()); + impl<'a> RxToken for IgbRxToken<'a> { + fn consume(self, f: F) -> R + where + F: FnOnce(&[u8]) -> R, + { + // 异步接收数据包 + spin_on::spin_on(async { + self.rx_ring.recv(self.buffer).await.unwrap(); + f(self.buffer) + }) + } + } - // info!("mac: {:#?}", igb.read_mac()); + struct IgbTxToken<'a> { + tx_ring: &'a mut eth_igb::TxRing, + } - // info!("waiting for link up..."); - // while !igb.status().link_up { - // spin_delay(Duration::from_secs(1)); + 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); - // info!("status: {:#?}", igb.status()); - // } + // 异步发送数据包 + spin_on::spin_on(async { + self.tx_ring.send(&buffer).await.unwrap(); + }); - // spin_on::spin_on(async move { - // info!("link up, starting to receive packets..."); - // let mut buff = alloc::vec![0u8; rx.packet_size() * 10]; - // rx.recv(&mut buff).await.unwrap(); - // info!("Received {} bytes", buff.len()); - // }); + result + } + } - // println!("test passed!"); - // } + fn now() -> Instant { + let ms = bare_test::time::since_boot().as_millis() as u64; + Instant::from_millis(ms as i64) + } #[test] - fn loopback_test() { + fn ping_test() { let (igb, irq) = get_igb().unwrap(); info!("igb: {:#?}", igb.status()); @@ -126,9 +185,8 @@ mod tests { } igb.open().unwrap(); - info!("igb opened for loopback test: {:#?}", igb.status()); - // igb.enable_loopback(); - // info!("Loopback mode enabled"); + info!("igb opened for ping test: {:#?}", igb.status()); + let mac = igb.read_mac(); info!("mac: {mac:#?}"); @@ -138,35 +196,104 @@ mod tests { info!("status: {:#?}", igb.status()); } - let mut rx = igb.new_rx_ring().unwrap(); - let mut tx = igb.new_tx_ring().unwrap(); - spin_on::spin_on(async move { - info!("link up, starting loopback test..."); - - // 创建测试数据包 - let test_packet = create_test_packet(&mac.bytes()); - info!("Created test packet with {} bytes", test_packet.len()); - - // 发送测试数据包 - info!("Sending test packet..."); - tx.send(&test_packet).await.unwrap(); - info!("Test packet sent"); - - // 接收数据包 - let mut rx_buff = alloc::vec![0u8; rx.packet_size() * 2]; - info!("Waiting to receive packet..."); - rx.recv(&mut rx_buff).await.unwrap(); - info!("Received {} bytes", rx_buff.len()); - - // 验证收到的数据包 - if verify_loopback_packet(&test_packet, &rx_buff) { - info!("✓ Loopback test passed! Packet correctly received"); - } else { - info!("✗ Loopback test failed! Received packet doesn't match sent packet"); - } + let rx_ring = igb.new_rx_ring().unwrap(); + let tx_ring = igb.new_tx_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(IpAddress::v4(127, 0, 0, 1), 8); + iface.update_ip_addrs(|ip_addrs| { + ip_addrs.push(ip_addr).unwrap(); }); - println!("loopback test completed!"); + // 创建 ICMP socket + let mut rx_meta = [PacketMetadata::EMPTY; 16]; + let mut rx_buffer = [0u8; 1024]; + let mut tx_meta = [PacketMetadata::EMPTY; 16]; + let mut tx_buffer = [0u8; 1024]; + + let icmp_socket = IcmpSocket::new( + icmp::PacketBuffer::new(&mut rx_meta[..], &mut rx_buffer[..]), + icmp::PacketBuffer::new(&mut tx_meta[..], &mut 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 = 10; + + while attempts < MAX_ATTEMPTS && !ping_received { + iface.poll(now(), device, socket_set); + // 获取 ICMP socket + let socket = socket_set.get_mut::(icmp_handle); + + if !ping_sent && socket.can_send() { + // 发送 ping + let ping_payload = b"ping test"; + match socket.send_slice(ping_payload, target_addr.into()) { + Ok(()) => { + info!("Ping sent to 127.0.0.1"); + ping_sent = true; + } + Err(e) => { + info!("Failed to send ping: {e:?}"); + } + } + } + + 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<(Igb, IrqInfo)> { @@ -270,75 +397,8 @@ mod tests { } None } - - fn create_test_packet(mac_src: &[u8]) -> alloc::vec::Vec { - // 创建一个简单的以太网帧用于回环测试 - let mut packet = alloc::vec::Vec::new(); - - // 目标MAC地址 (广播地址) - packet.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); - - // 源MAC地址 (测试地址) - packet.extend_from_slice(mac_src); - - // 以太网类型 (IPv4) - packet.extend_from_slice(&[0x08, 0x00]); - - // 简单的IPv4头部 - packet.extend_from_slice(&[ - 0x45, 0x00, 0x00, 0x2E, // Version, IHL, Type of Service, Total Length - 0x00, 0x00, 0x40, 0x00, // Identification, Flags, Fragment Offset - 0x40, 0x01, 0x00, 0x00, // TTL, Protocol (ICMP), Header Checksum - 0xC0, 0xA8, 0x01, 0x01, // Source IP (192.168.1.1) - 0xC0, 0xA8, 0x01, 0x02, // Destination IP (192.168.1.2) - ]); - - // ICMP 头部和数据 - packet.extend_from_slice(&[ - 0x08, 0x00, 0x00, 0x00, // Type (Echo Request), Code, Checksum - 0x12, 0x34, 0x56, 0x78, // Identifier, Sequence Number - ]); - - // 测试数据 - packet.extend_from_slice(b"Hello, Loopback Test!"); - - // 填充到最小以太网帧大小 - while packet.len() < 60 { - packet.push(0x00); - } - packet - } - - fn verify_loopback_packet(sent_packet: &[u8], received_buffer: &[u8]) -> bool { - // 在接收缓冲区中查找发送的数据包 - let packet_size = sent_packet.len(); - - // 搜索缓冲区中是否包含我们发送的数据包 - for i in 0..received_buffer.len() { - if i + packet_size <= received_buffer.len() { - let chunk = &received_buffer[i..i + packet_size]; - if chunk == sent_packet { - info!("Found matching packet at offset {i}"); - return true; - } - } - } - - // 如果没有找到完全匹配的数据包,至少检查一下是否接收到了数据 - let non_zero_bytes = received_buffer.iter().filter(|&&b| b != 0).count(); - info!( - "Received {non_zero_bytes} non-zero bytes out of {}", - received_buffer.len() - ); - - // 检查接收到的数据包的前几个字节 - if received_buffer.len() >= 14 { - info!("Received packet header: {:02x?}", &received_buffer[0..14]); - } - - false - } } + struct KernelImpl; impl_trait! { From 4cb1c9e4891dea5b14605c57bbdde0958249a364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 20:45:42 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E9=87=8D=E6=9E=84=20RxRing=20=E5=92=8C?= =?UTF-8?q?=20TxRing=EF=BC=8C=E5=90=88=E5=B9=B6=E6=96=B0=E5=BB=BA=E7=8E=AF?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91=EF=BC=8C=E7=AE=80=E5=8C=96=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0=E7=AC=A6=E7=AE=A1=E7=90=86=EF=BC=9B=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E4=BB=A5=E9=80=82=E5=BA=94?= =?UTF-8?q?=E6=96=B0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- igb/src/lib.rs | 28 ++---- igb/src/ring/mod.rs | 232 +++----------------------------------------- igb/src/ring/rx.rs | 139 +++++++++++++------------- igb/src/ring/tx.rs | 143 +++++++++++++++++++++++++++ igb/tests/test.rs | 93 ++++++++---------- 5 files changed, 277 insertions(+), 358 deletions(-) create mode 100644 igb/src/ring/tx.rs diff --git a/igb/src/lib.rs b/igb/src/lib.rs index a65490c..b250e3f 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -7,10 +7,7 @@ pub use mac::{MacAddr6, MacStatus}; pub use trait_ffi::impl_extern_trait; pub use crate::err::DError; -use crate::{ - descriptor::{AdvRxDesc, AdvTxDesc}, - ring::{DEFAULT_RING_SIZE, Ring}, -}; +use crate::{descriptor::AdvRxDesc, ring::DEFAULT_RING_SIZE}; extern crate alloc; @@ -23,7 +20,7 @@ mod phy; mod ring; pub use futures::{Stream, StreamExt}; -pub use ring::{RxRing, TxRing}; +pub use ring::{RxBuff, RxRing, TxRing}; pub struct Igb { mac: mac::Mac, @@ -76,20 +73,11 @@ impl Igb { Ok(()) } - pub fn new_rx_ring(&mut self) -> Result { - let mut ring: Ring = Ring::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; - ring.init()?; - let mut ring = RxRing::new(ring); - self.rx_ring_addrs[0] = ring.addr().as_ptr() as usize; - Ok(ring) - } + 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)?; - pub fn new_tx_ring(&mut self) -> Result { - let mut ring: Ring = Ring::new(0, self.mac.iobase(), DEFAULT_RING_SIZE)?; - ring.init()?; - let mut ring = TxRing::new(ring); - self.tx_ring_addrs[0] = ring.addr().as_ptr() as usize; - Ok(ring) + Ok((tx_ring, rx_ring)) } fn config_fc_after_link_up(&mut self) -> Result<(), DError> { @@ -140,8 +128,8 @@ impl Igb { 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(); + // let rx_ring = unsafe { &mut *(self.rx_ring_addrs[0] as *mut Ring) }; + // rx_ring.clean(); } } } diff --git a/igb/src/ring/mod.rs b/igb/src/ring/mod.rs index e77b383..68979e8 100644 --- a/igb/src/ring/mod.rs +++ b/igb/src/ring/mod.rs @@ -1,19 +1,22 @@ -use core::{cell::UnsafeCell, pin::Pin, ptr::NonNull, time::Duration}; +use core::{cell::UnsafeCell, ptr::NonNull, time::Duration}; -use alloc::{boxed::Box, vec::Vec}; -use dma_api::{DSlice, DSliceMut, DVec, Direction}; +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 futures::task::AtomicWaker; use crate::{ - descriptor::{AdvRxDesc, AdvRxDescRead, AdvTxDesc, Descriptor}, + 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 @@ -37,7 +40,7 @@ const TDWBAL: usize = 0xE038; // TX Descriptor Write Back Address Low const TWDBAH: usize = 0xE03C; // TX Descriptor Write Back Address High const PACKET_SIZE_KB: u32 = 2; -const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; +const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; register_bitfields! [ // First parameter is the register width. Can be u8, u16, u32, or u64. @@ -94,7 +97,7 @@ register_bitfields! [ ]; #[derive(Default, Clone)] -struct RingElemMeta{ +struct RingElemMeta { buff_ptr: usize, } @@ -104,17 +107,16 @@ struct Ring { current_head: usize, hw_head: usize, waker: AtomicWaker, - meta_ls: Vec, + meta_ls: Vec, } - impl Ring { pub fn new(idx: usize, mmio_base: NonNull, size: usize) -> Result { let descriptors = DVec::zeros(size, 0x1000, Direction::Bidirectional).ok_or(DError::NoMemory)?; let ring_base = unsafe { mmio_base.add(idx * 0x40) }; - + Ok(Self { descriptors, ring_base, @@ -152,213 +154,3 @@ impl Ring { unsafe { self.reg_addr(reg).read_volatile() } } } - -impl Ring { - - - fn packet_buff(&mut self, index: usize) -> &mut [u8] { - let ptr = self.meta_ls[index].buff_ptr; - let buff = unsafe{ - core::slice::from_raw_parts_mut(ptr as *mut u8, PACKET_SIZE as usize) - }; - { - let sl = DSliceMut::from(buff, Direction::FromDevice); - sl.preper_read_all(); - } - buff - } - - fn rcv_buff(&mut self, buff: &mut [u8]) -> Result<(), DError> { - assert!(buff.len() >= PACKET_SIZE as usize, "Buffer too small for packet"); - assert!(buff.len().is_multiple_of(PACKET_SIZE as usize), "Buffer size must be a multiple of packet size"); - let mut bus_addr = { - let sl = DSliceMut::from(buff, Direction::FromDevice); - sl.bus_addr() - }; - - self.buffer.set(buff); - let mut i = self.reg_read(RDT); - - let mut buff_left = buff; - while !buff_left.is_empty() { - let desc = AdvRxDesc{read: AdvRxDescRead { pkt_addr: bus_addr, hdr_addr: 0 }}; - self.descriptors.set(i as usize, desc); - self.meta_ls[i as usize].buff_ptr = buff_left.as_mut_ptr() as usize; - - i += 1; - if i >= self.count() as u32{ - i = 0; - } - bus_addr += PACKET_SIZE as u64; - buff_left = &mut buff_left[PACKET_SIZE as usize..]; - } - - mb(); - self.reg_write(RDT, i); - - Ok(()) - } -} - - -impl Ring { - 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); - } - - 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); // 环形缓冲区已满 - } - - // 准备DMA缓冲区 - let dma_buff = { - let sl = DSlice::from(buff); - sl.bus_addr() - }; - - // 设置描述符 - let desc = AdvTxDesc { - read: crate::descriptor::AdvTxDescRead { - buffer_addr: dma_buff, - 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(UnsafeCell>>); - -impl TxRing { - pub(crate) fn new(ring: Ring) -> Self { - Self(UnsafeCell::new(Box::new(ring))) - } - - pub(crate) fn addr(&mut self) -> NonNull> { - unsafe { NonNull::from((*self.0.get()).as_mut()) } - } - - pub fn this(&self) -> &Ring { - unsafe { &*self.0.get() } - } - - pub fn this_mut(&mut self) -> &mut Ring { - unsafe { &mut *self.0.get() } - } - - pub async fn send(&mut self, buff: &[u8]) -> Result<(), DError> { - debug!("tx send {}", buff.len()); - for chuck in buff.chunks(PACKET_SIZE as usize) { - self.this_mut().send_packet(chuck)?; - } - Ok(()) - } - -} - - -#[derive(Default)] -struct Buffer{ - ptr: usize, - len: usize, - n: usize, -} - -impl Buffer { - fn set(&mut self, buff: &[u8]) { - self.ptr = buff.as_ptr() as usize; - self.len = buff.len(); - self.n = 0; - } -} \ No newline at end of file diff --git a/igb/src/ring/rx.rs b/igb/src/ring/rx.rs index 3a1dbba..bb185e3 100644 --- a/igb/src/ring/rx.rs +++ b/igb/src/ring/rx.rs @@ -1,22 +1,32 @@ use core::ops::{Deref, DerefMut}; +use super::*; +use crate::{ + DError, + descriptor::{AdvRxDesc, AdvRxDescRead}, +}; use alloc::{sync::Arc, vec::Vec}; use dma_api::DVec; -use super::*; -use crate::{descriptor::AdvRxDesc, DError}; struct RingInner { base: Ring, pkts: Vec>, + pkt_size: usize, } impl RingInner { - fn new(ring: Ring, pkt_size: usize) -> Result< Self, DError> { + fn new(ring: Ring, pkt_size: usize) -> Result { let mut pkts = Vec::with_capacity(ring.count()); for _ in 0..ring.count() { - pkts.push(DVec::zeros(pkt_size, pkt_size, Direction::FromDevice).ok_or(DError::NoMemory)?); + pkts.push( + DVec::zeros(pkt_size, pkt_size, Direction::FromDevice).ok_or(DError::NoMemory)?, + ); } - Ok( Self { base:ring, pkts }) + Ok(Self { + base: ring, + pkts, + pkt_size, + }) } fn init(&mut self) -> Result<(), DError> { @@ -25,7 +35,12 @@ impl RingInner { 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 }}; + let desc = AdvRxDesc { + read: AdvRxDescRead { + pkt_addr, + hdr_addr: 0, + }, + }; self.descriptors.set(i, desc); } @@ -36,12 +51,12 @@ impl RingInner { // 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 - // 4kB 包大小 - + SRRCTL::BSIZEPACKET.val(PACKET_SIZE_KB)).value, + (SRRCTL::DESCTYPE::AdvancedOneBuffer + SRRCTL::BSIZEPACKET.val(pkt_size_kb as _)).value, ); // If header split or header replication is required for this queue, @@ -64,18 +79,17 @@ impl RingInner { 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) { + pub fn enable_queue(&mut self) { // 启用队列 self.reg_write( RXDCTL, @@ -128,7 +142,7 @@ impl RingInner { let desc = &self.descriptors[desc_index]; unsafe { let wb = desc.write; - (wb.hi_dword.fields.error_type_status & crate::descriptor::rx_desc_consts::DD_BIT) != 0 + wb.is_done() } } @@ -143,8 +157,10 @@ impl RingInner { } /// 更新尾部指针 - pub fn update_tail(&mut self) { - let tail = self.current_head; + pub fn update_tail(&mut self, mut tail: usize) { + if tail == self.descriptors.len() { + tail = 0; + } self.reg_write(RDT, tail as u32); } @@ -171,77 +187,64 @@ pub struct RxRing(Arc>); unsafe impl Send for RxRing {} -impl RxRing{ - pub(crate) fn new(idx: usize, mmio_base: NonNull, size: usize) ->Result { +impl RxRing { + pub(crate) fn new(idx: usize, mmio_base: NonNull, size: usize) -> Result { let base = Ring::new(idx, mmio_base, size)?; - let ring_inner = RingInner::new(base, PACKET_SIZE as usize)?; + let mut ring_inner = RingInner::new(base, PACKET_SIZE as usize)?; + ring_inner.init()?; let ring = Arc::new(UnsafeCell::new(ring_inner)); Ok(Self(ring)) } - - pub(crate) fn addr(&mut self) -> NonNull> { - unsafe{ NonNull::from( (*self.0.get()).as_mut())} - } - - pub async fn recv(&mut self, buff: &mut [u8])->Result<(), DError> { - self.this_mut().rcv_buff(buff)?; - - RcvFuture::new(self).await?; - - DSliceMut::from(buff, Direction::FromDevice) - .preper_read_all(); - - Ok(()) - } - fn this(&self) -> &Ring { + fn this(&self) -> &RingInner { unsafe { &*self.0.get() } } - fn this_mut(&mut self) -> &mut Ring { + fn this_mut(&mut self) -> &mut RingInner { unsafe { &mut *self.0.get() } } pub fn packet_size(&self) -> usize { - PACKET_SIZE as 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; + + if head == tail { + return None; // 没有可用的缓冲区 + } + + // 获取当前索引 + let index = head % ring.count(); + + // 检查描述符是否已完成 + if !ring.is_descriptor_done(index) { + return None; // 描述符未完成,无法获取数据 + } + + // 返回 RxBuff 实例 + Some(RxBuff { ring: self, index }) } } -pub struct RcvFuture<'a> { +pub struct RxBuff<'a> { ring: &'a mut RxRing, + index: usize, } -impl<'a> RcvFuture<'a> { - pub fn new(ring: &'a mut RxRing) -> Self { - Self { ring } +impl Deref for RxBuff<'_> { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.ring.this().pkts[self.index].deref() } } -impl <'a> Future for RcvFuture<'a> { - type Output = Result<(), DError>; - - fn poll(self: Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll { - let this = self.get_mut(); - let ring = unsafe { &mut *this.ring.0.get() }; - - while this.n < this.buffer.len() && ring.current_head != ring.hw_head { - if !ring.is_descriptor_done(ring.current_head){ - break; - } - ring.current_head += 1; - if ring.current_head >= ring.count() { - ring.current_head = 0; - } - this.n += PACKET_SIZE as usize; - } - - if this.n == this.buffer.len() { - // 已经接收完所有数据 - return core::task::Poll::Ready(Ok(())); - } - - // 没有可用的描述符,注册唤醒器 - ring.waker.register(cx.waker()); - core::task::Poll::Pending +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..182f5ef --- /dev/null +++ b/igb/src/ring/tx.rs @@ -0,0 +1,143 @@ +use alloc::sync::Arc; + +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); + } + + 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); // 环形缓冲区已满 + } + + // 准备DMA缓冲区 + let dma_buff = { + let sl = DSlice::from(buff); + sl.bus_addr() + }; + + // 设置描述符 + let desc = AdvTxDesc { + read: crate::descriptor::AdvTxDescRead { + buffer_addr: dma_buff, + 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)?; + 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) + } +} diff --git a/igb/tests/test.rs b/igb/tests/test.rs index 089f3e5..b970c73 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -27,10 +27,9 @@ mod tests { println, time::spin_delay, }; - use eth_igb::Igb; + use eth_igb::{Igb, RxBuff}; use log::{debug, info}; use pcie::{CommandRegister, PciCapability, RootComplexGeneric, SimpleBarAllocator}; - use smoltcp::phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken}; use smoltcp::socket::icmp::{self, Socket as IcmpSocket}; use smoltcp::storage::PacketMetadata; use smoltcp::time::Instant; @@ -39,6 +38,10 @@ mod tests { iface::{Config, Interface, SocketSet}, wire::HardwareAddress, }; + use smoltcp::{ + phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken}, + wire::{Icmpv4Packet, Icmpv4Repr}, + }; struct Driver(UnsafeCell); impl Deref for Driver { @@ -66,17 +69,11 @@ mod tests { struct IgbDevice { rx_ring: eth_igb::RxRing, tx_ring: eth_igb::TxRing, - rx_buffer: alloc::vec::Vec, } impl IgbDevice { fn new(rx_ring: eth_igb::RxRing, tx_ring: eth_igb::TxRing) -> Self { - let rx_buffer = alloc::vec![0u8; rx_ring.packet_size() * 2]; - Self { - rx_ring, - tx_ring, - rx_buffer, - } + Self { rx_ring, tx_ring } } } @@ -88,16 +85,13 @@ mod tests { &mut self, _timestamp: Instant, ) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - // // 尝试接收数据包 - // let rx_token = IgbRxToken { - // rx_ring: &mut self.rx_ring, - // buffer: &mut self.rx_buffer, - // }; - // let tx_token = IgbTxToken { - // tx_ring: &mut self.tx_ring, - // }; - // Some((rx_token, tx_token)) - None + 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> { @@ -116,8 +110,7 @@ mod tests { } struct IgbRxToken<'a> { - rx_ring: &'a mut eth_igb::RxRing, - buffer: &'a mut [u8], + buff: RxBuff<'a>, } impl<'a> RxToken for IgbRxToken<'a> { @@ -125,11 +118,7 @@ mod tests { where F: FnOnce(&[u8]) -> R, { - // 异步接收数据包 - spin_on::spin_on(async { - self.rx_ring.recv(self.buffer).await.unwrap(); - f(self.buffer) - }) + f(&self.buff) } } @@ -144,11 +133,8 @@ mod tests { { let mut buffer = alloc::vec![0u8; len]; let result = f(&mut buffer); - // 异步发送数据包 - spin_on::spin_on(async { - self.tx_ring.send(&buffer).await.unwrap(); - }); + self.tx_ring.send(&buffer).unwrap(); result } @@ -196,8 +182,7 @@ mod tests { info!("status: {:#?}", igb.status()); } - let rx_ring = igb.new_rx_ring().unwrap(); - let tx_ring = igb.new_tx_ring().unwrap(); + let (tx_ring, rx_ring) = igb.new_ring().unwrap(); // 创建 smoltcp 设备适配器 let mut device = IgbDevice::new(rx_ring, tx_ring); @@ -215,15 +200,17 @@ mod tests { }); // 创建 ICMP socket - let mut rx_meta = [PacketMetadata::EMPTY; 16]; - let mut rx_buffer = [0u8; 1024]; - let mut tx_meta = [PacketMetadata::EMPTY; 16]; - let mut tx_buffer = [0u8; 1024]; - - let icmp_socket = IcmpSocket::new( - icmp::PacketBuffer::new(&mut rx_meta[..], &mut rx_buffer[..]), - icmp::PacketBuffer::new(&mut tx_meta[..], &mut tx_buffer[..]), + 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); @@ -252,24 +239,30 @@ mod tests { let mut ping_received = false; let mut attempts = 0; const MAX_ATTEMPTS: usize = 10; + 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 - let ping_payload = b"ping test"; - match socket.send_slice(ping_payload, target_addr.into()) { - Ok(()) => { - info!("Ping sent to 127.0.0.1"); - ping_sent = true; - } - Err(e) => { - info!("Failed to send ping: {e:?}"); - } - } + icmp_repr.emit(&mut icmp_packet, &device.capabilities().checksum); } if ping_sent && socket.can_recv() { From 213707e491b05d528d4e36b26861a2379b2a3211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 20:52:32 +0800 Subject: [PATCH 11/13] update --- igb/src/ring/mod.rs | 4 ++-- igb/src/ring/rx.rs | 7 +++++++ igb/src/ring/tx.rs | 7 +++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/igb/src/ring/mod.rs b/igb/src/ring/mod.rs index 68979e8..cd02ac3 100644 --- a/igb/src/ring/mod.rs +++ b/igb/src/ring/mod.rs @@ -36,8 +36,8 @@ 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 TWDBAH: usize = 0xE03C; // TX Descriptor Write Back Address High +// const TDWBAL: usize = 0xE038; // TX Descriptor Write Back Address Low +// const TWDBAH: usize = 0xE03C; // TX Descriptor Write Back Address High const PACKET_SIZE_KB: u32 = 2; const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; diff --git a/igb/src/ring/rx.rs b/igb/src/ring/rx.rs index bb185e3..598b9c7 100644 --- a/igb/src/ring/rx.rs +++ b/igb/src/ring/rx.rs @@ -229,6 +229,13 @@ impl RxRing { } } +impl Drop for RxRing { + fn drop(&mut self) { + // 在释放时禁用队列 + self.this_mut().disable_queue(); + } +} + pub struct RxBuff<'a> { ring: &'a mut RxRing, index: usize, diff --git a/igb/src/ring/tx.rs b/igb/src/ring/tx.rs index 182f5ef..7b1e02d 100644 --- a/igb/src/ring/tx.rs +++ b/igb/src/ring/tx.rs @@ -114,6 +114,13 @@ impl RingInner { // 更新尾部指针 self.reg_write(TDT, next_tail as u32); + // 等待硬件发送完成 + wait_for( + || self.is_tx_descriptor_done(tail), + Duration::from_micros(100), + Some(1000), // 最多等待1000次检查,约100ms + )?; + Ok(()) } } From 1ab2889a618cc38e3ab86a9c3762d6f9d2dd3e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 22:09:49 +0800 Subject: [PATCH 12/13] tx,rx test ok --- igb/bare-test.toml | 2 +- igb/src/descriptor.rs | 4 ++-- igb/src/ring/mod.rs | 18 ++++++++++++-- igb/src/ring/rx.rs | 41 +++++++++++++------------------- igb/src/ring/tx.rs | 55 +++++++++++++++++++++++++++++++------------ igb/tests/test.rs | 16 +++++++------ 6 files changed, 85 insertions(+), 51 deletions(-) diff --git a/igb/bare-test.toml b/igb/bare-test.toml index 2d1d254..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*,trace:net*" +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 index 4c97dc0..4bf7406 100644 --- a/igb/src/descriptor.rs +++ b/igb/src/descriptor.rs @@ -81,8 +81,8 @@ pub mod tx_desc_consts { pub const CMD_IDE: u32 = 1 << 31; // Interrupt Delay Enable // Descriptor types - pub const DTYPE_DATA: u32 = 0 << 20; // Data descriptor - pub const DTYPE_CONTEXT: u32 = 1 << 20; // Context descriptor + 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] diff --git a/igb/src/ring/mod.rs b/igb/src/ring/mod.rs index cd02ac3..f1eb06b 100644 --- a/igb/src/ring/mod.rs +++ b/igb/src/ring/mod.rs @@ -37,7 +37,7 @@ 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 TWDBAH: usize = 0xE03C; // TX Descriptor Write Back Address High +// const TDWBAH: usize = 0xE03C; // TX Descriptor Write Back Address High const PACKET_SIZE_KB: u32 = 2; const PACKET_SIZE: u32 = PACKET_SIZE_KB * 1024; @@ -108,14 +108,26 @@ struct Ring { 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) -> Result { + 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, @@ -124,6 +136,8 @@ impl Ring { current_head: 0, hw_head: 0, meta_ls: alloc::vec![RingElemMeta::default(); size], + pkts, + pkt_size, }) } diff --git a/igb/src/ring/rx.rs b/igb/src/ring/rx.rs index 598b9c7..1625d94 100644 --- a/igb/src/ring/rx.rs +++ b/igb/src/ring/rx.rs @@ -5,28 +5,16 @@ use crate::{ DError, descriptor::{AdvRxDesc, AdvRxDescRead}, }; -use alloc::{sync::Arc, vec::Vec}; -use dma_api::DVec; +use alloc::sync::Arc; +use log::trace; struct RingInner { base: Ring, - pkts: Vec>, - pkt_size: usize, } impl RingInner { - fn new(ring: Ring, pkt_size: usize) -> Result { - let mut pkts = Vec::with_capacity(ring.count()); - for _ in 0..ring.count() { - pkts.push( - DVec::zeros(pkt_size, pkt_size, Direction::FromDevice).ok_or(DError::NoMemory)?, - ); - } - Ok(Self { - base: ring, - pkts, - pkt_size, - }) + fn new(ring: Ring) -> Result { + Ok(Self { base: ring }) } fn init(&mut self) -> Result<(), DError> { @@ -189,8 +177,14 @@ 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)?; - let mut ring_inner = RingInner::new(base, PACKET_SIZE as usize)?; + 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)) @@ -211,19 +205,18 @@ impl RxRing { let ring = self.this_mut(); let head = ring.get_head() as usize; let tail = ring.get_tail() as usize; - - if head == tail { + trace!("RxRing: next_pkt head: {head}, tail: {tail}"); + let index = (tail + 1) % ring.count(); + if head == index { return None; // 没有可用的缓冲区 } - // 获取当前索引 - let index = head % ring.count(); - // 检查描述符是否已完成 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 }) } diff --git a/igb/src/ring/tx.rs b/igb/src/ring/tx.rs index 7b1e02d..bbb4d22 100644 --- a/igb/src/ring/tx.rs +++ b/igb/src/ring/tx.rs @@ -1,4 +1,7 @@ +use core::ops::Deref; + use alloc::sync::Arc; +use log::trace; use super::*; @@ -76,7 +79,7 @@ impl RingInner { 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; @@ -86,16 +89,16 @@ impl RingInner { return Err(DError::NoMemory); // 环形缓冲区已满 } - // 准备DMA缓冲区 - let dma_buff = { - let sl = DSlice::from(buff); - sl.bus_addr() - }; + 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: dma_buff, + 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 @@ -114,13 +117,6 @@ impl RingInner { // 更新尾部指针 self.reg_write(TDT, next_tail as u32); - // 等待硬件发送完成 - wait_for( - || self.is_tx_descriptor_done(tail), - Duration::from_micros(100), - Some(1000), // 最多等待1000次检查,约100ms - )?; - Ok(()) } } @@ -131,7 +127,13 @@ 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)?; + 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)) @@ -147,4 +149,27 @@ impl TxRing { 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 b970c73..53c75e1 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -2,7 +2,6 @@ #![no_main] #![feature(used_with_arg)] -use core::future::Future; use core::time::Duration; use bare_test::time::spin_delay; @@ -28,10 +27,9 @@ mod tests { time::spin_delay, }; use eth_igb::{Igb, RxBuff}; - use log::{debug, info}; + use log::*; use pcie::{CommandRegister, PciCapability, RootComplexGeneric, SimpleBarAllocator}; use smoltcp::socket::icmp::{self, Socket as IcmpSocket}; - use smoltcp::storage::PacketMetadata; use smoltcp::time::Instant; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; use smoltcp::{ @@ -43,6 +41,9 @@ mod tests { 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; @@ -118,6 +119,7 @@ mod tests { where F: FnOnce(&[u8]) -> R, { + debug!("rcv one"); f(&self.buff) } } @@ -133,9 +135,7 @@ mod tests { { let mut buffer = alloc::vec![0u8; len]; let result = f(&mut buffer); - // 异步发送数据包 self.tx_ring.send(&buffer).unwrap(); - result } } @@ -194,10 +194,11 @@ mod tests { let mut iface = Interface::new(config, &mut device, now()); // 配置 IP 地址 - let ip_addr = IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8); + 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( @@ -238,7 +239,7 @@ mod tests { let mut ping_sent = false; let mut ping_received = false; let mut attempts = 0; - const MAX_ATTEMPTS: usize = 10; + const MAX_ATTEMPTS: usize = 1000; let ident = 0x22b; while attempts < MAX_ATTEMPTS && !ping_received { @@ -263,6 +264,7 @@ mod tests { // 发送 ping icmp_repr.emit(&mut icmp_packet, &device.capabilities().checksum); + ping_sent = true; } if ping_sent && socket.can_recv() { From b6d1fbd25ace1237f0a1e7d75d112d3685f2c25a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 17 Jul 2025 22:32:48 +0800 Subject: [PATCH 13/13] update --- igb/src/lib.rs | 4 + igb/src/mac.rs | 199 ++++++++++++++++++++++++++++++++++++++++++++++ igb/tests/test.rs | 2 +- 3 files changed, 204 insertions(+), 1 deletion(-) diff --git a/igb/src/lib.rs b/igb/src/lib.rs index b250e3f..0ec8ca8 100644 --- a/igb/src/lib.rs +++ b/igb/src/lib.rs @@ -132,6 +132,10 @@ impl Igb { // rx_ring.clean(); } } + + pub fn irq_mode_legacy(&mut self) { + self.mac.configure_legacy_mode(); + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/igb/src/mac.rs b/igb/src/mac.rs index d1a362d..ebf5757 100644 --- a/igb/src/mac.rs +++ b/igb/src/mac.rs @@ -16,10 +16,18 @@ 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), (0x404 => _rsv12), + (0x1514 => gpie: ReadWrite), + (0x1518 => _rsv16), (0x1524 => eims: ReadWrite), (0x1528 => eimc: ReadWrite), (0x152c => eiac: ReadWrite), @@ -244,6 +252,94 @@ register_bitfields! [ 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)] @@ -310,6 +406,65 @@ impl Mac { 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(); @@ -398,6 +553,36 @@ impl Mac { 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() @@ -441,6 +626,20 @@ pub struct IrqMsg { 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/tests/test.rs b/igb/tests/test.rs index 53c75e1..8531552 100644 --- a/igb/tests/test.rs +++ b/igb/tests/test.rs @@ -169,7 +169,7 @@ mod tests { }) .register(); } - + igb.irq_mode_legacy(); igb.open().unwrap(); info!("igb opened for ping test: {:#?}", igb.status());