#![allow(dead_code)]
use tock_registers::register_bitfields;
pub trait Descriptor {}
register_bitfields! [
u64,
RX_DESC_READ_PKT_ADDR [
ADDR OFFSET(1) NUMBITS(63)[], NSE OFFSET(0) NUMBITS(1)[], ],
RX_DESC_READ_HDR_ADDR [
ADDR OFFSET(1) NUMBITS(63)[], DD OFFSET(0) NUMBITS(1)[], ],
];
register_bitfields! [
u32,
RX_DESC_WB_LO_RSS_HASH [
RSS_HASH OFFSET(0) NUMBITS(32)[], ],
RX_DESC_WB_LO_FRAG_CSUM [
FRAG_CSUM OFFSET(16) NUMBITS(16)[], IP_ID OFFSET(0) NUMBITS(16)[], ],
RX_DESC_WB_LO_HDR_STATUS [
HDR_LEN OFFSET(22) NUMBITS(10)[], SPH OFFSET(21) NUMBITS(1)[], EXT_STATUS_LO OFFSET(0) NUMBITS(21)[], ],
RX_DESC_WB_HI_VLAN_LEN [
VLAN_TAG OFFSET(16) NUMBITS(16)[], PKT_LEN OFFSET(0) NUMBITS(16)[], ],
RX_DESC_WB_HI_ERROR_STATUS [
EXT_ERROR OFFSET(20) NUMBITS(12)[], RSS_TYPE OFFSET(17) NUMBITS(3)[], PKT_TYPE OFFSET(4) NUMBITS(13)[], EXT_STATUS_HI OFFSET(0) NUMBITS(4)[], ],
RX_DESC_EXT_STATUS [
DD OFFSET(0) NUMBITS(1)[], EOP OFFSET(1) NUMBITS(1)[], VP OFFSET(3) NUMBITS(1)[], UDPCS OFFSET(4) NUMBITS(1)[], L4I OFFSET(5) NUMBITS(1)[], IPCS OFFSET(6) NUMBITS(1)[], PIF OFFSET(7) NUMBITS(1)[], VEXT OFFSET(9) NUMBITS(1)[], UDPV OFFSET(10) NUMBITS(1)[], LLINT OFFSET(11) NUMBITS(1)[], TS OFFSET(16) NUMBITS(1)[], SECP OFFSET(17) NUMBITS(1)[], LB OFFSET(18) NUMBITS(1)[], ],
RX_DESC_EXT_ERROR [
HBO OFFSET(3) NUMBITS(1)[], SECERR OFFSET(7) NUMBITS(2)[], L4E OFFSET(9) NUMBITS(1)[], IPE OFFSET(10) NUMBITS(1)[], RXE OFFSET(11) NUMBITS(1)[], ],
pub TX_DESC_CMD_TYPE_LEN [
LEN OFFSET(0) NUMBITS(20)[], DTYPE OFFSET(20) NUMBITS(4)[
Data = 0b11, Context = 0b10, ],
CMD_EOP OFFSET(24) NUMBITS(1)[], CMD_IFCS OFFSET(25) NUMBITS(1)[], CMD_IC OFFSET(26) NUMBITS(1)[], CMD_RS OFFSET(27) NUMBITS(1)[], CMD_DEXT OFFSET(29) NUMBITS(1)[], CMD_VLE OFFSET(30) NUMBITS(1)[], CMD_IDE OFFSET(31) NUMBITS(1)[], ],
pub TX_DESC_STATUS [
DD OFFSET(0) NUMBITS(1)[], ],
];
#[derive(Debug, Clone, Copy)]
pub enum TxAdvDescType {
Data,
Context,
}
#[allow(clippy::upper_case_acronyms)]
pub enum TxAdvDescCmd {
EOP,
IFCS,
IC,
RS,
DEXT,
VLE,
IDE,
}
#[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<u8> 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<u8> for SecurityError {
fn from(val: u8) -> Self {
match val & 0b11 {
0b00 => SecurityError::None,
0b01 => SecurityError::NoSaMatch,
0b10 => SecurityError::ReplayError,
0b11 => SecurityError::BadSignature,
_ => unreachable!(),
}
}
}
#[derive(Clone, Copy)]
pub union AdvTxDesc {
pub read: AdvTxDescRead,
pub write: AdvTxDescWB,
}
impl Descriptor for AdvTxDesc {}
impl AdvTxDesc {
pub fn new(
buffer_addr: u64,
buffer_len: usize,
kind: TxAdvDescType,
cmd_ls: &[TxAdvDescCmd],
) -> Self {
let mut cmd_type_len = TX_DESC_CMD_TYPE_LEN::LEN.val(buffer_len as _);
match kind {
TxAdvDescType::Data => {
cmd_type_len += TX_DESC_CMD_TYPE_LEN::DTYPE::Data;
}
TxAdvDescType::Context => {
cmd_type_len += TX_DESC_CMD_TYPE_LEN::DTYPE::Context;
}
}
for c in cmd_ls {
match c {
TxAdvDescCmd::EOP => cmd_type_len += TX_DESC_CMD_TYPE_LEN::CMD_EOP::SET,
TxAdvDescCmd::IFCS => cmd_type_len += TX_DESC_CMD_TYPE_LEN::CMD_IFCS::SET,
TxAdvDescCmd::IC => cmd_type_len += TX_DESC_CMD_TYPE_LEN::CMD_IC::SET,
TxAdvDescCmd::RS => cmd_type_len += TX_DESC_CMD_TYPE_LEN::CMD_RS::SET,
TxAdvDescCmd::DEXT => cmd_type_len += TX_DESC_CMD_TYPE_LEN::CMD_DEXT::SET,
TxAdvDescCmd::VLE => cmd_type_len += TX_DESC_CMD_TYPE_LEN::CMD_VLE::SET,
TxAdvDescCmd::IDE => cmd_type_len += TX_DESC_CMD_TYPE_LEN::CMD_IDE::SET,
}
}
Self {
read: AdvTxDescRead {
buffer_addr,
cmd_type_len: cmd_type_len.value,
olinfo_status: 0,
},
}
}
}
#[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,
}
impl AdvTxDescWB {
pub fn is_done(&self) -> bool {
self.status & TX_DESC_STATUS::DD.mask != 0
}
}
#[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,
}
#[derive(Clone, Copy)]
pub union LoDword {
pub data: u64,
pub fields: LoFields,
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct LoFields {
pub rss_hash_or_csum_ip: u32,
pub hdr_status: u32,
}
#[derive(Clone, Copy)]
#[repr(C)]
pub union HiDword {
pub data: u64,
pub fields: HiFields,
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct HiFields {
pub error_type_status: u32,
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_READ_PKT_ADDR::NSE.mask
} else {
pkt_addr & !RX_DESC_READ_PKT_ADDR::NSE.mask
};
Self {
pkt_addr,
hdr_addr: hdr_addr & !RX_DESC_READ_HDR_ADDR::DD.mask, }
}
}
impl AdvRxDescWB {
pub fn is_done(&self) -> bool {
unsafe { self.hi_dword.fields.error_type_status & RX_DESC_EXT_STATUS::DD.mask != 0 }
}
pub fn is_end_of_packet(&self) -> bool {
unsafe { self.hi_dword.fields.error_type_status & RX_DESC_EXT_STATUS::EOP.mask != 0 }
}
pub fn packet_length(&self) -> u16 {
unsafe { (self.hi_dword.fields.vlan_length & RX_DESC_WB_HI_VLAN_LEN::PKT_LEN.mask) as u16 }
}
pub fn vlan_tag(&self) -> u16 {
unsafe {
((self.hi_dword.fields.vlan_length & RX_DESC_WB_HI_VLAN_LEN::VLAN_TAG.mask)
>> RX_DESC_WB_HI_VLAN_LEN::VLAN_TAG.shift) as u16
}
}
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_WB_LO_HDR_STATUS::HDR_LEN.mask)
>> RX_DESC_WB_LO_HDR_STATUS::HDR_LEN.shift) as u16
}
}
pub fn is_split_header(&self) -> bool {
unsafe { self.lo_dword.fields.hdr_status & RX_DESC_WB_LO_HDR_STATUS::SPH.mask != 0 }
}
pub fn packet_type(&self) -> u16 {
unsafe {
((self.hi_dword.fields.error_type_status & RX_DESC_WB_HI_ERROR_STATUS::PKT_TYPE.mask)
>> RX_DESC_WB_HI_ERROR_STATUS::PKT_TYPE.shift) as u16
}
}
pub fn rss_type(&self) -> u8 {
unsafe {
((self.hi_dword.fields.error_type_status & RX_DESC_WB_HI_ERROR_STATUS::RSS_TYPE.mask)
>> RX_DESC_WB_HI_ERROR_STATUS::RSS_TYPE.shift) as u8
}
}
pub fn has_errors(&self) -> bool {
unsafe {
(self.hi_dword.fields.error_type_status & RX_DESC_WB_HI_ERROR_STATUS::EXT_ERROR.mask)
!= 0
|| (self.hi_dword.fields.error_type_status
& (RX_DESC_EXT_ERROR::L4E.mask
| RX_DESC_EXT_ERROR::IPE.mask
| RX_DESC_EXT_ERROR::RXE.mask))
!= 0
}
}
pub fn ip_checksum_valid(&self) -> bool {
unsafe {
(self.hi_dword.fields.error_type_status & RX_DESC_EXT_STATUS::IPCS.mask) != 0
&& (self.hi_dword.fields.error_type_status & RX_DESC_EXT_ERROR::IPE.mask) == 0
}
}
pub fn l4_checksum_valid(&self) -> bool {
unsafe {
(self.hi_dword.fields.error_type_status & RX_DESC_EXT_STATUS::L4I.mask) != 0
&& (self.hi_dword.fields.error_type_status & RX_DESC_EXT_ERROR::L4E.mask) == 0
}
}
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_EXT_ERROR::SECERR.mask)
>> RX_DESC_EXT_ERROR::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_EXT_ERROR::HBO.mask) != 0 }
}
pub fn is_vlan_packet(&self) -> bool {
unsafe { (self.hi_dword.fields.error_type_status & RX_DESC_EXT_STATUS::VP.mask) != 0 }
}
pub fn is_loopback_packet(&self) -> bool {
unsafe { (self.hi_dword.fields.error_type_status & RX_DESC_EXT_STATUS::LB.mask) != 0 }
}
pub fn is_timestamped(&self) -> bool {
unsafe { (self.hi_dword.fields.error_type_status & RX_DESC_EXT_STATUS::TS.mask) != 0 }
}
pub fn fragment_checksum(&self) -> u16 {
unsafe {
((self.lo_dword.fields.rss_hash_or_csum_ip & RX_DESC_WB_LO_FRAG_CSUM::FRAG_CSUM.mask)
>> RX_DESC_WB_LO_FRAG_CSUM::FRAG_CSUM.shift) as u16
}
}
pub fn ip_identification(&self) -> u16 {
unsafe {
(self.lo_dword.fields.rss_hash_or_csum_ip & RX_DESC_WB_LO_FRAG_CSUM::IP_ID.mask) as u16
}
}
}