【GMAC学习笔记】深入理解以太网DMA描述符机制

前言

分享记录以太网MAC控制器的验证,关于Synopsys DWC Ethernet QoS IP核。在学习和调试过程中,发现描述符(Descriptor)机制是整个DMA传输的核心,也是理解以太网控制器工作原理的关键。

刚开始接触时,面对几百页的Databook文档,各种寄存器位域、状态标志位,感觉非常抽象。经过反复阅读文档、查看波形、调试代码,终于对描述符机制有了一些理解。特此整理成文,分享给正在学习网络协议栈、以太网驱动开发或IC验证的同学。

本文基于**DWC Ethernet QoS Databook (Version 5.10a)**整理,结合实际工程经验,力求专业准确、通俗易懂。


.

一、描述符机制概述

1.1 什么是描述符?为什么需要它?

在深入技术细节之前,让我们先用一个生活中的例子来理解描述符的概念。

生活中的类比:快递配送单

想象一下快递配送的场景:

  • 传统方式:快递员每送一个包裹,都要打电话给收件人,等收件人下来取件,效率很低
  • 描述符方式 :快递员拿着一叠配送单,每张单子上写着:
    • 收件人地址(数据存放位置)
    • 包裹大小(数据长度)
    • 是否需要签收(是否产生中断)
    • 是否是最后一个包裹(包结束标志)

快递员可以按照配送单批量配送,不需要每次都联系收件人,效率大大提高。

技术层面的定义

在以太网控制器中,**描述符(Descriptor)**就是这样的"配送单":

描述符 = 数据传输的元数据结构

它告诉DMA控制器:

  • 数据在内存的哪个位置(缓冲区地址)
  • 数据有多少字节(长度)
  • 如何处理这些数据(控制标志)
  • 传输完成后做什么(中断、状态写回)

1.2 描述符机制的优势

传统的PIO(Programmed I/O)方式,CPU需要直接参与每次数据传输:

复制代码
CPU: 读取数据 → 写入寄存器 → 等待完成 → 读取下一个数据

这种方式CPU利用率低,无法满足高速网络的需求(10Gbps甚至更高)。

描述符机制的优势

零拷贝传输 :DMA直接访问内存,CPU只需配置描述符,无需搬运数据

批量处理 :一个描述符链可以传输多个数据包,减少CPU干预

异步操作 :CPU准备描述符后可做其他工作,DMA独立完成传输

分散/聚集I/O :支持数据分散在多个缓冲区,适应各种内存管理方案

硬件加速:支持TSO、checksum offload等功能

1.3 描述符在系统中的位置

复制代码
┌─────────────────────────────────────────────────────┐
│                    应用层                            │
├─────────────────────────────────────────────────────┤
│                    协议栈                            │
│                  (TCP/IP)                           │
├─────────────────────────────────────────────────────┤
│                   驱动层                             │
│              ┌──────────────┐                       │
│              │ 创建描述符链  │ ←── 配置描述符        │
│              │ 管理缓冲区    │                       │
│              └──────────────┘                       │
├─────────────────────────────────────────────────────┤
│                   硬件层                             │
│    ┌──────────────────────────────────┐            │
│    │         DMA控制器                 │            │
│    │  ┌────────────────────────┐     │            │
│    │  │  读取描述符 → 传输数据  │     │ ←── 硬件自动│
│    │  │  写回状态 → 产生中断    │     │            │
│    │  └────────────────────────┘     │            │
│    └──────────────────────────────────┘            │
│              ↓           ↑                          │
│         ┌────────┐  ┌────────┐                     │
│         │ 发送FIFO│  │接收FIFO│                     │
│         └────────┘  └────────┘                     │
└─────────────────────────────────────────────────────┘
              ↓           ↑
         ┌────────────────────┐
         │   物理层 (PHY)      │
         └────────────────────┘

关键点:驱动层在内存中创建描述符链,DMA控制器自动读取并执行数据传输,实现软硬件协同工作。


二、描述符类型与结构

2.1 两种描述符类型

DWC Ethernet QoS支持两种描述符类型,各有不同用途:

(1) Normal Descriptor(普通描述符)

用途:承载数据包的实际内容

特点

  • 包含数据缓冲区的地址和长度
  • 包含传输控制信息(中断、校验等)
  • 包含状态信息(错误、过滤结果等)

类比:就像快递的包裹本身,里面装着实际的货物。

(2) Context Descriptor(上下文描述符)

用途:传递控制参数,不承载数据

特点

  • 用于配置VLAN标签、TSO参数等
  • 用于IEEE 1588时间戳校正
  • 不占用数据缓冲区

类比:就像快递的特殊配送指令,比如"需要冷藏配送"、"易碎物品"等标签,本身不是货物,但影响配送方式。

2.2 描述符的组织结构

环形链表结构(Ring Structure)

DWC Ethernet QoS采用环形描述符链表,这是最常用的组织方式:

复制代码
内存布局:
┌────────────┐  ┌────────────┐  ┌────────────┐
│ Descriptor │  │ Descriptor │  │ Descriptor │
│     0      │─→│     1      │─→│     2      │─┐
└────────────┘  └────────────┘  └────────────┘ │
     ↑                                           │
     └───────────────────────────────────────────┘
              (循环回到Descriptor 0)

寄存器配置:
- DMA_CH0_TxDesc_ListAddr: 描述符链起始地址
- DMA_CH0_TxDesc_RingLen: 描述符数量

为什么用环形结构?

内存效率高 :无需频繁分配/释放内存

循环使用 :描述符处理完后可重新初始化使用

适合高速场景 :减少内存管理开销

实现简单:硬件只需维护当前指针

描述符大小
  • 标准描述符:16字节(4个32位字)
  • 增强描述符:32字节(用于时间敏感网络等高级特性)

每个描述符包含4个32位字段:

复制代码
┌─────────────────────────────────────┐
│  DES0 (Word 0) - 32 bits            │
├─────────────────────────────────────┤
│  DES1 (Word 1) - 32 bits            │
├─────────────────────────────────────┤
│  DES2 (Word 2) - 32 bits            │
├─────────────────────────────────────┤
│  DES3 (Word 3) - 32 bits            │
└─────────────────────────────────────┘

三、发送描述符详解

3.1 发送普通描述符 - 读格式(Read Format)

使用场景:驱动程序配置待发送的数据包时,设置此格式。

3.1.1 TDES0 - Buffer 1地址指针
复制代码
  31                              0
┌──────────────────────────────────┐
│   Buffer 1 Address Pointer       │
└──────────────────────────────────┘

说明

  • 存放数据缓冲区的物理地址(注意不是虚拟地址)
  • 无地址对齐限制,可以是任意地址
  • 通常指向数据包的起始位置

SystemVerilog定义

复制代码
// TDES0字段定义
typedef struct packed {
    logic [31:0] buffer1_addr;  // Buffer 1物理地址
} tdes0_t;
3.1.2 TDES1 - Buffer 2地址指针
复制代码
  31                              0
┌──────────────────────────────────┐
│   Buffer 2 Address Pointer       │
└──────────────────────────────────┘

说明

  • 用于双缓冲模式,指向第二个缓冲区
  • 在40/48位地址模式下,存放Buffer 1的高位地址
  • 单缓冲模式下可设为0

双缓冲模式的应用场景

复制代码
场景1:头部与数据分离
┌─────────────┐
│  Descriptor │
├─────────────┤
│ Buffer1 Addr│ ──→ [Ethernet Header (14B)]
│ Buffer2 Addr│ ──→ [IP + TCP + Payload]
└─────────────┘

场景2:大数据包分段
┌─────────────┐
│  Descriptor │
├─────────────┤
│ Buffer1 Addr│ ──→ [前半部分数据]
│ Buffer2 Addr│ ──→ [后半部分数据]
└─────────────┘
3.1.3 TDES2 - 控制字段

这是发送描述符的核心控制字段,包含多个重要标志位:

复制代码
  31  30   29        16 15  14    13          0
┌────┬────┬─────────────┬───────┬──────────────┐
│IOC │TTSE│    B2L      │ VTIR  │    B1L/HL    │
└────┴────┴─────────────┴───────┴──────────────┘

各字段详细说明

字段 位宽 名称 说明
IOC 1 bit Interrupt on Completion 传输完成产生中断
TTSE 1 bit Transmit Timestamp Enable 使能IEEE 1588时间戳
B2L 14 bits Buffer 2 Length Buffer 2的数据长度(字节)
VTIR 2 bits VLAN Tag Insert/Replace VLAN标签操作控制
B1L/HL 14 bits Buffer 1 Length / Header Length Buffer 1长度或头部长度

IOC位详解

复制代码
IOC = 1: 当此描述符传输完成时,DMA产生中断
IOC = 0: 不产生中断

应用场景:
- 通常只在数据包的最后一个描述符(LD=1)设置IOC=1
- 这样可以在整个包发送完成后得到通知
- 减少中断次数,提高性能

VTIR字段详解(VLAN标签操作):

复制代码
VTIR = 00: 不添加VLAN标签
VTIR = 01: 移除VLAN标签(仅对已标记的包有效)
VTIR = 10: 插入VLAN标签(从MAC_VLAN_Incl寄存器或上下文描述符获取)
VTIR = 11: 替换VLAN标签(仅对已标记的包有效)

SystemVerilog定义

复制代码
// TDES2字段定义
typedef struct packed {
    logic        ioc;              // [31] Interrupt on Completion
    logic        ttse;             // [30] Transmit Timestamp Enable
    logic [13:0] buffer2_len;      // [29:16] Buffer 2 Length
    logic [1:0]  vlan_tag_ctrl;    // [15:14] VLAN Tag Insert/Replace
    logic [13:0] buffer1_len;      // [13:0] Buffer 1 Length
} tdes2_t;

// VTIR枚举定义
typedef enum logic [1:0] {
    VLAN_NO_ACTION   = 2'b00,  // 不操作
    VLAN_REMOVE      = 2'b01,  // 移除标签
    VLAN_INSERT      = 2'b10,  // 插入标签
    VLAN_REPLACE     = 2'b11   // 替换标签
} vlan_tag_op_e;
3.1.4 TDES3 - 控制与状态字段

这是最重要的字段,包含所有权、包边界、帧长度等关键信息:

复制代码
  31  30  29  28  27  26  25   23 22    19 18 17  16 15     0
┌────┬────┬────┬────┬────┬────────┬────────┬────┬────┬─────────┐
│OWN │CTXT│ FD │ LD │ CPC│  SAIC  │SLOTNUM │ THL│ TSE│   FL    │
└────┴────┴────┴────┴────┴────────┴────────┴────┴────┴─────────┘

核心字段详解

(1) OWN位 - 所有权位(最关键!)
复制代码
OWN = 1: DMA控制器拥有此描述符,驱动程序不能修改
OWN = 0: 驱动程序拥有此描述符,DMA控制器不能访问

工作流程

复制代码
发送流程:
驱动程序: 配置描述符 → 设置OWN=1 → 通知DMA启动
DMA控制器: 检测OWN=1 → 读取描述符 → 传输数据 → 清除OWN=0 → 写回状态
驱动程序: 检测OWN=0 → 读取状态 → 释放缓冲区 → 重新配置描述符

重要提示:OWN位是驱动与DMA同步的核心机制,必须正确设置!

(2) FD位 - First Descriptor(首描述符)
复制代码
FD = 1: 这是数据包的第一个描述符
FD = 0: 不是第一个描述符

用途:标识一个完整数据包的起始位置
(3) LD位 - Last Descriptor(尾描述符)
复制代码
LD = 1: 这是数据包的最后一个描述符
LD = 0: 不是最后一个描述符

用途:
- 标识数据包的结束位置
- DMA只对LD=1的描述符写回状态和时间戳
- 通常在LD=1的描述符上设置IOC=1产生中断
(4) TSE位 - TCP Segmentation Enable(TCP分段使能)
复制代码
TSE = 1: 使能TCP Segmentation Offload (TSO)
TSE = 0: 正常传输

TSO功能:硬件自动将大TCP包分段,减轻CPU负担
(5) FL字段 - Frame Length(帧长度)
复制代码
FL [14:0]: 发送帧的总长度(字节)
范围:0 ~ 32767字节

注意:这是整个帧的长度,包括以太网头、IP头、TCP头、数据

SystemVerilog定义

复制代码
// TDES3字段定义
typedef struct packed {
    logic        own;              // [31] Own Bit
    logic        ctxt;             // [30] Context Type (0 for normal)
    logic        first_desc;       // [29] First Descriptor
    logic        last_desc;        // [28] Last Descriptor
    logic [1:0]  crc_pad_ctrl;     // [27:26] CRC Pad Control
    logic [2:0]  sa_ins_ctrl;      // [25:23] Source Address Insert Control
    logic [3:0]  slot_num;         // [22:19] Slot Number (for EST)
    logic        tcp_seg_en;       // [18] TCP Segmentation Enable
    logic [1:0]  checksum_ins;     // [17:16] Checksum Insert Control
    logic [14:0] frame_len;        // [14:0] Frame Length
} tdes3_t;

3.2 发送描述符 - 写回格式(Write-Back Format)

使用场景:DMA完成数据传输后,将状态信息写回描述符。

重要 :写回操作只对LD=1的描述符(最后一个描述符)进行。

复制代码
┌─────────────────────────────────────┐
│  TDES0: Timestamp Low  [31:0]       │ ← IEEE 1588时间戳低32位
├─────────────────────────────────────┤
│  TDES1: Timestamp High [31:0]       │ ← IEEE 1588时间戳高32位
├─────────────────────────────────────┤
│  TDES2: Reserved                    │
├─────────────────────────────────────┤
│  TDES3: OWN=0 + Status [30:0]       │ ← OWN清零,状态位有效
└─────────────────────────────────────┘

时间戳说明

  • 当TTSE=1时,DMA记录数据包发送的精确时间
  • 用于IEEE 1588 PTP协议,实现时钟同步
  • 时间戳精度通常为纳秒级

四、接收描述符详解

4.1 接收普通描述符 - 读格式(Read Format)

使用场景:驱动程序为接收数据包准备缓冲区时,设置此格式。

4.1.1 RDES0 - Buffer 1地址
复制代码
  31                              0
┌──────────────────────────────────┐
│   Buffer 1 Address Pointer       │
└──────────────────────────────────┘

说明

  • 存放接收缓冲区的物理地址
  • MAC接收的数据将写入此地址
  • 建议缓存行对齐(如64字节对齐)以提高性能
4.1.2 RDES1 - Buffer 2地址
复制代码
  31                              0
┌──────────────────────────────────┐
│   Buffer 2 Address Pointer       │
└──────────────────────────────────┘

说明

  • 用于双缓冲模式
  • 当Buffer 1满时,数据继续写入Buffer 2
  • 避免因缓冲区不足导致丢包
4.1.3 RDES2 - 控制字段
复制代码
  31                              0
┌──────────────────────────────────┐
│          Reserved                │
└──────────────────────────────────┘

说明:接收描述符的RDES2在读格式下保留,由DMA在写回时填充状态。

4.1.4 RDES3 - 控制字段
复制代码
  31  30  29                     0
┌────┬────┬────────────────────────┐
│OWN │IOC │      Reserved          │
└────┴────┴────────────────────────┘
字段 说明
OWN 所有权位:1=DMA拥有,0=驱动拥有
IOC Interrupt on Completion - 接收完成产生中断

SystemVerilog定义

复制代码
// RDES3读格式定义
typedef struct packed {
    logic        own;           // [31] Own Bit
    logic        ioc;           // [30] Interrupt on Completion
    logic [29:0] reserved;      // [29:0] Reserved
} rdes3_rd_t;

4.2 接收描述符 - 写回格式(Write-Back Format)

使用场景:DMA接收完数据包后,将状态信息写回描述符。

4.2.1 RDES3 - 状态字段(最重要)
复制代码
  31  30  29  28  27  26  25  24  23  22  21  20  19      0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐
│OWN │CTXT│ LD │ FD │ ERR│ B1L│ PL │ ES │ CE │ GP │RWT │  Length │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴─────────┘

核心状态位详解

字段 名称 说明
OWN 31 Own Bit 0表示DMA已完成,驱动可处理
CTXT 30 Context 1表示这是上下文描述符
LD 29 Last Descriptor 数据包的最后一个描述符
FD 28 First Descriptor 数据包的第一个描述符
ERR 27 Error Summary 错误汇总位
ES 24 Error Status 错误状态
CE 23 CRC Error CRC校验错误
GP 22 Giant Packet 巨型包(超过最大帧长)
RWT 21 Receive Watchdog Timeout 接收看门狗超时
Length 14:0 Frame Length 接收到的帧长度

错误状态位详解

复制代码
ES (Error Status) = 1 时,表示接收出错,可能原因:
- CE (CRC Error): CRC校验失败
- GP (Giant Packet): 包长度超过最大值
- RWT (Watchdog Timeout): 接收超时,包被截断
- OE (Overflow Error): FIFO溢出
- RE (Receive Error): GMII接收错误信号

SystemVerilog定义

复制代码
// RDES3写回格式定义
typedef struct packed {
    logic        own;              // [31] Own Bit (0 after write-back)
    logic        ctxt;             // [30] Context Descriptor
    logic        last_desc;        // [29] Last Descriptor
    logic        first_desc;       // [28] First Descriptor
    logic        error_summary;    // [27] Error Summary
    logic        buffer1_len_valid;// [26] Buffer 1 Length Valid
    logic        payload_len_valid;// [25] Payload Length Valid
    logic        error_status;     // [24] Error Status
    logic        crc_error;        // [23] CRC Error
    logic        giant_packet;     // [22] Giant Packet
    logic        rx_watchdog_tmo;  // [21] Receive Watchdog Timeout
    logic        overflow_error;   // [20] Overflow Error
    logic        rx_error;         // [19] Receive Error
    logic [18:0] reserved;         // [18:0] Reserved
    logic [14:0] frame_len;        // [14:0] Frame Length
} rdes3_wb_t;
4.2.2 RDES0 - 扩展状态字段
复制代码
  31  29  28  27  26      19 18 17  16 15      0
┌─────┬────┬────┬──────────┬────┬────┬────┬─────────┐
│FltID│L4FM│L3FM│  MADRM   │ HF │DAF │SAF │   HL    │
└─────┴────┴────┴──────────┴────┴────┴────┴─────────┘

过滤与匹配状态

字段 说明
L4FM Layer 4 Filter Match - L4端口过滤匹配
L3FM Layer 3 Filter Match - L3 IP地址过滤匹配
MADRM MAC Address Match or Hash Value - MAC地址匹配或哈希值
HF Hash Filter - 哈希过滤状态
DAF Destination Address Filter Fail - 目的地址过滤失败
SAF Source Address Filter Fail - 源地址过滤失败
HL L3/L4 Header Length - L3/L4头部长度

应用场景

  • 网络过滤:根据MAC/IP/端口过滤数据包
  • 哈希过滤:快速多播过滤
  • 分离解析:分离L2/L3/L4头部

五、描述符工作流程详解

5.1 发送流程完整解析

让我们通过一个完整的例子,理解发送描述符的工作流程。

场景:发送一个1500字节的IP数据包

步骤1:驱动程序准备数据

复制代码
// 假设数据包已准备好
byte packet_data[1500];  // IP数据包
logic [31:0] buffer_addr = 'h1000_0000;  // 缓冲区物理地址

步骤2:配置发送描述符

复制代码
// 创建发送描述符
tx_descriptor_t tx_desc;

// TDES0: Buffer 1地址
tx_desc.tdes0 = buffer_addr;  // 'h1000_0000

// TDES1: Buffer 2地址(不使用)
tx_desc.tdes1 = 32'h0;

// TDES2: 控制字段
tx_desc.tdes2 = {
    1'b1,              // IOC = 1 (传输完成产生中断)
    1'b0,              // TTSE = 0 (不使能时间戳)
    14'h0,             // B2L = 0 (无Buffer 2)
    2'b00,             // VTIR = 00 (不操作VLAN)
    14'd1500           // B1L = 1500 (Buffer 1长度)
};

// TDES3: 控制与状态
tx_desc.tdes3 = {
    1'b1,              // OWN = 1 (DMA拥有)
    1'b0,              // CTXT = 0 (普通描述符)
    1'b1,              // FD = 1 (首描述符)
    1'b1,              // LD = 1 (尾描述符)
    2'b00,             // CPC = 00 (CRC控制)
    3'b000,            // SAIC = 000 (不插入源地址)
    4'h0,              // SLOTNUM = 0
    1'b0,              // TSE = 0 (不使能TSO)
    2'b00,             // CIC = 00 (校验控制)
    15'd1514           // FL = 1514 (以太网头14B + IP数据1500B)
};

步骤3:通知DMA启动传输

复制代码
// 写入DMA寄存器,启动传输
write_register(DMA_CH0_TxDesc_ListAddr, desc_addr);
write_register(DMA_CH0_TxControl, 32'h1);  // ST = 1, 启动发送

步骤4:DMA控制器工作

复制代码
DMA控制器内部流程:
1. 读取描述符 (TDES0-TDES3)
2. 检查OWN位 (OWN=1, 可以处理)
3. 从Buffer地址读取数据 (1500字节)
4. 添加以太网头、CRC等
5. 通过MAC发送到PHY
6. 清除OWN位 (OWN=0)
7. 写回状态和时间戳
8. 产生中断 (因为IOC=1)

步骤5:驱动程序处理完成

复制代码
// 中断处理程序
task handle_tx_complete();
    // 检查OWN位
    if (tx_desc.tdes3[31] == 1'b0) begin  // OWN = 0
        // DMA已完成
        if (tx_desc.tdes3[30] == 1'b0) begin  // 不是上下文描述符
            // 读取时间戳(如果使能了TTSE)
            logic [63:0] timestamp = {tx_desc.tdes1, tx_desc.tdes0};
            
            // 释放缓冲区
            free_buffer(buffer_addr);
            
            // 重新初始化描述符,供下次使用
            init_tx_descriptor(tx_desc);
        end
    end
endtask

5.2 接收流程完整解析

场景:接收一个数据包

步骤1:驱动程序准备接收缓冲区

复制代码
// 分配接收缓冲区
logic [31:0] rx_buffer_addr = 'h2000_0000;
logic [31:0] rx_buffer_size = 2048;  // 2KB缓冲区

步骤2:配置接收描述符

复制代码
// 创建接收描述符
rx_descriptor_t rx_desc;

// RDES0: Buffer 1地址
rx_desc.rdes0 = rx_buffer_addr;  // 'h2000_0000

// RDES1: Buffer 2地址(可选)
rx_desc.rdes1 = 32'h0;  // 不使用双缓冲

// RDES2: 保留
rx_desc.rdes2 = 32'h0;

// RDES3: 控制字段
rx_desc.rdes3 = {
    1'b1,              // OWN = 1 (DMA拥有)
    1'b1,              // IOC = 1 (接收完成产生中断)
    30'h0              // Reserved
};

步骤3:DMA控制器接收数据

复制代码
DMA控制器内部流程:
1. MAC从PHY接收数据
2. 数据写入Rx FIFO
3. DMA读取描述符 (RDES0-RDES3)
4. 检查OWN位 (OWN=1, 可以写入)
5. 将数据从FIFO写入Buffer
6. 清除OWN位 (OWN=0)
7. 写回状态和长度
8. 设置FD/LD位
9. 产生中断 (因为IOC=1)

步骤4:驱动程序处理接收数据

复制代码
// 中断处理程序
task handle_rx_complete();
    // 检查OWN位
    if (rx_desc.rdes3[31] == 1'b0) begin  // OWN = 0
        // DMA已完成
        
        // 检查是否为完整包 (FD=1 and LD=1)
        if (rx_desc.rdes3[29] && rx_desc.rdes3[28]) begin
            // 获取接收长度
            logic [14:0] pkt_len = rx_desc.rdes3[14:0];
            
            // 检查错误
            if (rx_desc.rdes3[24]) begin  // ES = 1
                // 接收出错
                logic crc_err = rx_desc.rdes3[23];
                logic giant_pkt = rx_desc.rdes3[22];
                $display("RX Error: CRC=%0d, Giant=%0d", crc_err, giant_pkt);
            end else begin
                // 接收成功,处理数据
                process_rx_packet(rx_buffer_addr, pkt_len);
            end
            
            // 重新分配缓冲区,准备下次接收
            rx_desc.rdes3[31] = 1'b1;  // OWN = 1
        end
    end
endtask

5.3 多描述符传输(分散/聚集I/O)

当一个数据包分散在多个缓冲区时,需要使用多个描述符:

复制代码
场景:发送一个数据包,头部和数据分离

Buffer布局:
┌──────────────┐
│ Eth + IP + TCP│  54字节 (头部)
└──────────────┘
       ↓
  Buffer 1 (地址: 0x1000)

┌──────────────┐
│   Payload    │  1460字节 (数据)
└──────────────┘
       ↓
  Buffer 2 (地址: 0x2000)

描述符配置:
┌─────────────┐
│ Descriptor0 │  FD=1, LD=0
├─────────────┤
│ TDES0 = 0x1000│  (头部地址)
│ TDES2 = 54   │  (头部长度)
│ TDES3 = 0x80000000│ (OWN=1, FD=1, LD=0)
└─────────────┘
       ↓
┌─────────────┐
│ Descriptor1 │  FD=0, LD=1
├─────────────┤
│ TDES0 = 0x2000│  (数据地址)
│ TDES2 = 1460 │  (数据长度)
│ TDES3 = 0x90000000│ (OWN=1, FD=0, LD=1, IOC=1)
└─────────────┘

SystemVerilog示例

复制代码
// 配置分散/聚集I/O
task setup_scatter_gather_tx();
    // 第一个描述符:头部
    tx_desc[0].tdes0 = 'h1000;      // 头部地址
    tx_desc[0].tdes1 = 32'h0;
    tx_desc[0].tdes2 = {1'b0, 1'b0, 14'h0, 2'b00, 14'd54};
    tx_desc[0].tdes3 = {1'b1, 1'b0, 1'b1, 1'b0, 26'h0};  // OWN=1, FD=1, LD=0
    
    // 第二个描述符:数据
    tx_desc[1].tdes0 = 'h2000;      // 数据地址
    tx_desc[1].tdes1 = 32'h0;
    tx_desc[1].tdes2 = {1'b1, 1'b0, 14'h0, 2'b00, 14'd1460};  // IOC=1
    tx_desc[1].tdes3 = {1'b1, 1'b0, 1'b0, 1'b1, 26'h0};  // OWN=1, FD=0, LD=1
endtask

六、上下文描述符详解

6.1 发送上下文描述符

用途:传递控制参数,不承载数据。

应用场景
  1. VLAN标签配置:插入或替换VLAN标签
  2. TSO参数:设置TCP分段的最大段大小(MSS)
  3. IEEE 1588时间戳校正:单步时间戳校正
TDES2 - 上下文描述符
复制代码
  31          16 15  14    13          0
┌───────────────┬───────┬──────────────┐
│      IVT      │ Rsvd  │     MSS      │
└───────────────┴───────┴──────────────┘
字段 说明
IVT Inner VLAN Tag - 内层VLAN标签(用于Q-in-Q)
MSS Maximum Segment Size - TSO最大段大小
TDES3 - 上下文描述符
复制代码
  31  30  29  28  27  26  25  23 22  18 17  16 15   0
┌────┬────┬────┬────┬────┬────┬────┬─────┬────┬────┬───────┐
│OWN │CTXT│Rsvd│OSTC│TCMSV│Rsvd│CDE │Rsvd │IVLTV│VLTV│  VT   │
└────┴────┴────┴────┴────┴────┴────┴─────┴────┴────┴───────┘
字段 说明
OWN 所有权位
CTXT Context Type - 必须为1
OSTC One-Step Timestamp Correction - 单步时间戳校正
TCMSSV Timestamp Correction/MSS Valid
IVLTV Inner VLAN Tag Valid
VLTV VLAN Tag Valid
VT VLAN Tag - VLAN标签值

SystemVerilog示例

复制代码
// 配置TSO上下文描述符
task setup_tso_context(input logic [13:0] mss);
    tx_descriptor_t ctx_desc;
    
    ctx_desc.tdes0 = 32'h0;  // 时间戳低(用于单步校正)
    ctx_desc.tdes1 = 32'h0;  // 时间戳高
    ctx_desc.tdes2 = {16'h0, 2'b00, mss};  // MSS
    ctx_desc.tdes3 = {
        1'b1,              // OWN = 1
        1'b1,              // CTXT = 1 (上下文描述符)
        2'b00,             // Reserved
        1'b0,              // OSTC = 0
        1'b1,              // TCMSSV = 1 (MSS有效)
        2'b00,             // Reserved
        1'b0,              // CDE = 0
        5'b00000,          // Reserved
        1'b0,              // IVLTV = 0
        1'b0,              // VLTV = 0
        16'h0              // VT = 0
    };
endtask

6.2 接收上下文描述符

用途:当普通描述符的状态位不足以表示所有信息时,DMA写入上下文描述符。

应用场景

  • IEEE 1588时间戳(高精度)
  • 扩展过滤状态
  • 附加错误信息

七、增强描述符(Enhanced Descriptor)

7.1 概述

用途:用于时间敏感网络(TSN)、IEEE 802.1Qbv门控调度等高级特性。

大小:32字节(标准描述符的2倍)

7.2 结构

复制代码
┌─────────────────────────────────────┐
│  ETDESC4: Reserved                  │
├─────────────────────────────────────┤
│  ETDESC5: Launch Time [23:0]        │ ← 发送时间(纳秒)
├─────────────────────────────────────┤
│  ETDESC6: Reserved                  │
├─────────────────────────────────────┤
│  ETDESC7: GSN + Control             │ ← 门控调度槽号
├─────────────────────────────────────┤
│  TDESC0: Buffer 1 Address           │
├─────────────────────────────────────┤
│  TDESC1: Buffer 2 Address           │
├─────────────────────────────────────┤
│  TDESC2: Control                    │
├─────────────────────────────────────┤
│  TDESC3: OWN + Status               │
└─────────────────────────────────────┘

关键字段

字段 说明
Launch Time 数据包的计划发送时间
GSN Gate Control Schedule Number - 门控调度序号

7.3 应用场景

时间敏感网络(TSN)
复制代码
场景:工业控制网络,要求确定性延迟

配置:
1. 设置Launch Time = 目标发送时间
2. 设置GSN = 对应的门控调度槽
3. DMA在指定时间发送数据包

效果:
- 保证数据包在确定的时间窗口发送
- 避免冲突,实现零丢包
- 满足工业自动化的实时性要求

八、SystemVerilog完整实现示例

8.1 描述符结构体定义

复制代码
// 包:GMAC描述符定义
package gmac_descriptor_pkg;

    // ============================================
    // 发送描述符定义
    // ============================================
    
    // TDES0: Buffer 1地址
    typedef struct packed {
        logic [31:0] buffer1_addr;
    } tdes0_t;
    
    // TDES1: Buffer 2地址
    typedef struct packed {
        logic [31:0] buffer2_addr;
    } tdes1_t;
    
    // TDES2: 控制字段
    typedef struct packed {
        logic        ioc;              // [31] Interrupt on Completion
        logic        ttse;             // [30] Transmit Timestamp Enable
        logic [13:0] buffer2_len;      // [29:16] Buffer 2 Length
        logic [1:0]  vlan_tag_ctrl;    // [15:14] VLAN Tag Control
        logic [13:0] buffer1_len;      // [13:0] Buffer 1 Length
    } tdes2_t;
    
    // TDES3: 控制与状态
    typedef struct packed {
        logic        own;              // [31] Own Bit
        logic        ctxt;             // [30] Context Type
        logic        first_desc;       // [29] First Descriptor
        logic        last_desc;        // [28] Last Descriptor
        logic [1:0]  crc_pad_ctrl;     // [27:26] CRC Pad Control
        logic [2:0]  sa_ins_ctrl;      // [25:23] SA Insert Control
        logic [3:0]  slot_num;         // [22:19] Slot Number
        logic        tcp_seg_en;       // [18] TCP Segmentation Enable
        logic [1:0]  checksum_ins;     // [17:16] Checksum Insert
        logic [14:0] frame_len;        // [14:0] Frame Length
    } tdes3_t;
    
    // 完整的发送描述符
    typedef struct packed {
        tdes0_t tdes0;
        tdes1_t tdes1;
        tdes2_t tdes2;
        tdes3_t tdes3;
    } tx_descriptor_t;
    
    // ============================================
    // 接收描述符定义
    // ============================================
    
    // RDES0: Buffer 1地址(读格式)
    typedef struct packed {
        logic [31:0] buffer1_addr;
    } rdes0_rd_t;
    
    // RDES0: 扩展状态(写回格式)
    typedef struct packed {
        logic [2:0]  filter_id;        // [31:29] Filter ID
        logic        l4_filter_match;  // [28] L4 Filter Match
        logic        l3_filter_match;  // [27] L3 Filter Match
        logic [7:0]  mac_addr_match;   // [26:19] MAC Address Match
        logic        hash_filter;      // [18] Hash Filter
        logic        da_filter_fail;   // [17] DA Filter Fail
        logic        sa_filter_fail;   // [16] SA Filter Fail
        logic [15:0] reserved;         // [15:0] Reserved
    } rdes0_wb_t;
    
    // RDES3: 控制字段(读格式)
    typedef struct packed {
        logic        own;              // [31] Own Bit
        logic        ioc;              // [30] Interrupt on Completion
        logic [29:0] reserved;         // [29:0] Reserved
    } rdes3_rd_t;
    
    // RDES3: 状态字段(写回格式)
    typedef struct packed {
        logic        own;              // [31] Own Bit
        logic        ctxt;             // [30] Context Descriptor
        logic        last_desc;        // [29] Last Descriptor
        logic        first_desc;       // [28] First Descriptor
        logic        error_summary;    // [27] Error Summary
        logic        buffer1_len_valid;// [26] Buffer 1 Length Valid
        logic        payload_len_valid;// [25] Payload Length Valid
        logic        error_status;     // [24] Error Status
        logic        crc_error;        // [23] CRC Error
        logic        giant_packet;     // [22] Giant Packet
        logic        rx_watchdog_tmo;  // [21] Receive Watchdog Timeout
        logic        overflow_error;   // [20] Overflow Error
        logic        rx_error;         // [19] Receive Error
        logic [18:0] reserved;         // [18:0] Reserved
        logic [14:0] frame_len;        // [14:0] Frame Length
    } rdes3_wb_t;
    
    // 完整的接收描述符
    typedef struct packed {
        logic [31:0] rdes0;
        logic [31:0] rdes1;
        logic [31:0] rdes2;
        logic [31:0] rdes3;
    } rx_descriptor_t;
    
    // ============================================
    // 枚举定义
    // ============================================
    
    // VLAN标签操作
    typedef enum logic [1:0] {
        VLAN_NO_ACTION   = 2'b00,
        VLAN_REMOVE      = 2'b01,
        VLAN_INSERT      = 2'b10,
        VLAN_REPLACE     = 2'b11
    } vlan_tag_op_e;
    
    // CRC和填充控制
    typedef enum logic [1:0] {
        CRC_PAD_AUTO     = 2'b00,  // 自动添加CRC和填充
        CRC_PAD_DISABLE  = 2'b01,  // 禁用
        CRC_PAD_RESERVED = 2'b10,
        CRC_PAD_ALL      = 2'b11   // 添加所有
    } crc_pad_ctrl_e;

endpackage

8.2 描述符管理类

复制代码
import gmac_descriptor_pkg::*;

// 描述符管理类
class DescriptorManager;
    
    // 描述符队列
    tx_descriptor_t tx_desc_queue[$];
    rx_descriptor_t rx_desc_queue[$];
    
    // 统计信息
    int tx_desc_count;
    int rx_desc_count;
    
    // ============================================
    // 发送描述符操作
    // ============================================
    
    // 初始化发送描述符
    function void init_tx_descriptor(
        ref tx_descriptor_t desc,
        input logic [31:0] buf1_addr,
        input logic [31:0] buf2_addr,
        input logic [13:0] buf1_len,
        input logic [13:0] buf2_len,
        input bit is_first,
        input bit is_last,
        input bit enable_interrupt
    );
        // TDES0
        desc.tdes0.buffer1_addr = buf1_addr;
        
        // TDES1
        desc.tdes1.buffer2_addr = buf2_addr;
        
        // TDES2
        desc.tdes2.ioc = enable_interrupt ? 1'b1 : 1'b0;
        desc.tdes2.ttse = 1'b0;  // 默认不使能时间戳
        desc.tdes2.buffer2_len = buf2_len;
        desc.tdes2.vlan_tag_ctrl = VLAN_NO_ACTION;
        desc.tdes2.buffer1_len = buf1_len;
        
        // TDES3
        desc.tdes3.own = 1'b1;  // DMA拥有
        desc.tdes3.ctxt = 1'b0;  // 普通描述符
        desc.tdes3.first_desc = is_first ? 1'b1 : 1'b0;
        desc.tdes3.last_desc = is_last ? 1'b1 : 1'b0;
        desc.tdes3.crc_pad_ctrl = CRC_PAD_AUTO;
        desc.tdes3.sa_ins_ctrl = 3'b000;
        desc.tdes3.slot_num = 4'h0;
        desc.tdes3.tcp_seg_en = 1'b0;
        desc.tdes3.checksum_ins = 2'b00;
        desc.tdes3.frame_len = 15'(buf1_len + buf2_len);
        
        tx_desc_count++;
    endfunction
    
    // 检查发送完成
    function bit check_tx_complete(
        input tx_descriptor_t desc,
        output logic [63:0] timestamp
    );
        if (desc.tdes3.own == 1'b0) begin
            // DMA已完成
            timestamp = {desc.tdes1.buffer2_addr, desc.tdes0.buffer1_addr};
            return 1'b1;
        end
        return 1'b0;
    endfunction
    
    // ============================================
    // 接收描述符操作
    // ============================================
    
    // 初始化接收描述符
    function void init_rx_descriptor(
        ref rx_descriptor_t desc,
        input logic [31:0] buf1_addr,
        input logic [31:0] buf2_addr,
        input bit enable_interrupt
    );
        desc.rdes0 = buf1_addr;
        desc.rdes1 = buf2_addr;
        desc.rdes2 = 32'h0;
        desc.rdes3 = {
            1'b1,                      // OWN = 1
            enable_interrupt ? 1'b1 : 1'b0,  // IOC
            30'h0
        };
        
        rx_desc_count++;
    endfunction
    
    // 检查接收完成
    function bit check_rx_complete(
        input rx_descriptor_t desc,
        output logic [14:0] pkt_len,
        output bit has_error
    );
        rdes3_wb_t rdes3_wb;
        
        // 转换为写回格式
        rdes3_wb = rdes3_wb_t'(desc.rdes3);
        
        if (rdes3_wb.own == 1'b0) begin
            // DMA已完成
            if (rdes3_wb.first_desc && rdes3_wb.last_desc) begin
                // 完整包
                pkt_len = rdes3_wb.frame_len;
                has_error = rdes3_wb.error_status;
                return 1'b1;
            end
        end
        return 1'b0;
    endfunction
    
    // 打印接收状态
    function void print_rx_status(input rx_descriptor_t desc);
        rdes3_wb_t rdes3_wb;
        rdes3_wb = rdes3_wb_t'(desc.rdes3);
        
        $display("=== RX Descriptor Status ===");
        $display("OWN: %0d", rdes3_wb.own);
        $display("First Desc: %0d", rdes3_wb.first_desc);
        $display("Last Desc: %0d", rdes3_wb.last_desc);
        $display("Frame Length: %0d bytes", rdes3_wb.frame_len);
        $display("Error Status: %0d", rdes3_wb.error_status);
        
        if (rdes3_wb.error_status) begin
            $display("  CRC Error: %0d", rdes3_wb.crc_error);
            $display("  Giant Packet: %0d", rdes3_wb.giant_packet);
            $display("  Watchdog Timeout: %0d", rdes3_wb.rx_watchdog_tmo);
            $display("  Overflow Error: %0d", rdes3_wb.overflow_error);
        end
    endfunction
    
endclass

8.3 测试平台示例

复制代码
module gmac_descriptor_tb;
    
    import gmac_descriptor_pkg::*;
    
    // 实例化描述符管理器
    DescriptorManager desc_mgr;
    
    // 测试描述符
    tx_descriptor_t tx_desc;
    rx_descriptor_t rx_desc;
    
    // 测试数据
    logic [31:0] tx_buffer = 'h1000_0000;
    logic [31:0] rx_buffer = 'h2000_0000;
    logic [63:0] timestamp;
    logic [14:0] pkt_len;
    bit has_error;
    
    initial begin
        // 创建描述符管理器
        desc_mgr = new();
        
        $display("========================================");
        $display("GMAC Descriptor Testbench");
        $display("========================================\n");
        
        // ============================================
        // 测试1:发送描述符配置
        // ============================================
        $display("Test 1: TX Descriptor Configuration");
        $display("----------------------------------------");
        
        desc_mgr.init_tx_descriptor(
            .desc(tx_desc),
            .buf1_addr(tx_buffer),
            .buf2_addr(32'h0),
            .buf1_len(14'd1500),
            .buf2_len(14'h0),
            .is_first(1),
            .is_last(1),
            .enable_interrupt(1)
        );
        
        $display("TX Descriptor Created:");
        $display("  TDES0 (Buffer1 Addr): 0x%08h", tx_desc.tdes0);
        $display("  TDES1 (Buffer2 Addr): 0x%08h", tx_desc.tdes1);
        $display("  TDES2 (Control):      0x%08h", tx_desc.tdes2);
        $display("  TDES3 (Status):       0x%08h", tx_desc.tdes3);
        $display("  OWN: %0d, FD: %0d, LD: %0d", 
                 tx_desc.tdes3.own, 
                 tx_desc.tdes3.first_desc, 
                 tx_desc.tdes3.last_desc);
        $display("");
        
        // ============================================
        // 测试2:接收描述符配置
        // ============================================
        $display("Test 2: RX Descriptor Configuration");
        $display("----------------------------------------");
        
        desc_mgr.init_rx_descriptor(
            .desc(rx_desc),
            .buf1_addr(rx_buffer),
            .buf2_addr(32'h0),
            .enable_interrupt(1)
        );
        
        $display("RX Descriptor Created:");
        $display("  RDES0 (Buffer1 Addr): 0x%08h", rx_desc.rdes0);
        $display("  RDES1 (Buffer2 Addr): 0x%08h", rx_desc.rdes1);
        $display("  RDES2 (Reserved):     0x%08h", rx_desc.rdes2);
        $display("  RDES3 (Control):      0x%08h", rx_desc.rdes3);
        $display("");
        
        // ============================================
        // 测试3:模拟接收完成
        // ============================================
        $display("Test 3: Simulate RX Complete");
        $display("----------------------------------------");
        
        // 模拟DMA写回
        rx_desc.rdes3 = {
            1'b0,              // OWN = 0 (DMA完成)
            1'b0,              // CTXT = 0
            1'b1,              // LD = 1
            1'b1,              // FD = 1
            1'b0,              // ERR = 0
            1'b0,              // B1L = 0
            1'b0,              // PL = 0
            1'b0,              // ES = 0 (无错误)
            1'b0,              // CE = 0
            1'b0,              // GP = 0
            1'b0,              // RWT = 0
            1'b0,              // OE = 0
            1'b0,              // RE = 0
            19'h0,             // Reserved
            15'd1514           // Frame Length = 1514 bytes
        };
        
        // 检查接收完成
        if (desc_mgr.check_rx_complete(rx_desc, pkt_len, has_error)) begin
            $display("RX Complete Detected!");
            $display("  Packet Length: %0d bytes", pkt_len);
            $display("  Has Error: %0d", has_error);
            desc_mgr.print_rx_status(rx_desc);
        end
        $display("");
        
        // ============================================
        // 统计信息
        // ============================================
        $display("========================================");
        $display("Statistics:");
        $display("  TX Descriptors: %0d", desc_mgr.tx_desc_count);
        $display("  RX Descriptors: %0d", desc_mgr.rx_desc_count);
        $display("========================================");
        
        $finish;
    end
    
endmodule

九、常见问题与调试技巧

9.1 描述符错误(Descriptor Error)

现象
  • DMA设置DE位(Descriptor Error)
  • 传输停止,无法继续
可能原因
  1. OWN位设置错误

    错误:驱动设置OWN=0,DMA无法获取描述符
    正确:驱动设置OWN=1,DMA才能处理

  2. FD/LD位设置不正确

    错误:一个包的描述符没有正确设置FD和LD
    正确:第一个描述符FD=1,最后一个描述符LD=1

  3. 缓冲区地址无效

    错误:Buffer地址为0或指向无效内存
    正确:确保Buffer地址有效且可访问

  4. 描述符链断裂

    错误:描述符链中间断开,DMA无法继续
    正确:确保描述符链连续且形成环形

调试方法
复制代码
// 检查描述符有效性
function bit validate_tx_descriptor(input tx_descriptor_t desc);
    bit is_valid = 1'b1;
    
    // 检查OWN位
    if (desc.tdes3.own == 1'b0) begin
        $display("Error: OWN bit is 0, DMA cannot process");
        is_valid = 1'b0;
    end
    
    // 检查Buffer地址
    if (desc.tdes0.buffer1_addr == 32'h0) begin
        $display("Error: Buffer 1 address is NULL");
        is_valid = 1'b0;
    end
    
    // 检查长度
    if (desc.tdes2.buffer1_len == 14'h0) begin
        $display("Warning: Buffer 1 length is 0");
    end
    
    // 检查FD/LD
    if (desc.tdes3.first_desc && desc.tdes3.last_desc) begin
        $display("Info: Single descriptor packet");
    end
    
    return is_valid;
endfunction

9.2 接收溢出问题

现象
  • OE位(Overflow Error)被设置
  • 数据丢失,丢包率上升
原因分析
复制代码
接收溢出的根本原因:
1. 接收FIFO满 → 数据无法写入
2. 描述符不足 → 无可用缓冲区
3. 处理速度慢 → 来不及回收描述符
解决方案
  1. 增加描述符数量

    // 建议配置
    parameter RX_DESC_NUM = 512; // 增加到512个
    parameter RX_BUFFER_SIZE = 2048; // 2KB缓冲区

  2. 使用更大的接收缓冲区

    // 支持Jumbo Frame
    parameter RX_BUFFER_SIZE = 9216; // 9KB缓冲区

  3. 优化中断处理

    // 批量处理接收描述符
    task process_rx_batch();
    int processed = 0;

    复制代码
     // 一次处理多个描述符
     while (processed < BATCH_SIZE) begin
         if (check_rx_complete(rx_desc_queue[rx_index], pkt_len, has_error)) begin
             process_rx_packet(pkt_len);
             reinit_rx_descriptor(rx_desc_queue[rx_index]);
             rx_index = (rx_index + 1) % RX_DESC_NUM;
             processed++;
         end else begin
             break;  // 没有更多完成的描述符
         end
     end
     
     // 只在批量处理完成后清中断
     clear_rx_interrupt();

    endtask

9.3 性能优化建议

描述符数量配置
复制代码
经验值:
- 1Gbps网络:TX/RX各256个描述符
- 10Gbps网络:TX/RX各1024个描述符
- 高负载场景:TX/RX各2048个描述符

计算公式:
描述符数量 = (吞吐量 × 最大延迟) / (MTU × 8)
缓冲区大小配置
复制代码
标准配置:
- MTU = 1500字节
- Buffer Size = 2048字节(预留头空间)

Jumbo Frame配置:
- MTU = 9000字节
- Buffer Size = 9216字节

对齐要求:
- 建议缓存行对齐(64字节)
- 提高DMA传输效率
中断优化
复制代码
优化策略:
1. NAPI方式:轮询+中断混合
2. 中断合并:多个包合并一次中断
3. CPU亲和性:绑定到特定CPU核心

配置示例:
- Rx Pacing: 使能,设置合理的包数阈值
- Tx Interrupt: 只在描述符队列快空时产生中断

十、总结与展望

10.1 核心知识点回顾

通过本文的学习,我们掌握了:

  1. 描述符的本质

    • 描述符是DMA与驱动之间的数据传输契约
    • 包含地址、长度、控制、状态等信息
    • 实现零拷贝、异步传输
  2. 两种描述符类型

    • Normal Descriptor:承载数据
    • Context Descriptor:传递控制参数
  3. 关键字段理解

    • OWN位:实现驱动与DMA的同步
    • FD/LD位:标识数据包边界
    • IOC位:控制中断产生
  4. 工作流程

    • 发送:驱动配置 → DMA传输 → 状态写回
    • 接收:驱动准备 → DMA接收 → 状态写回
  5. 高级特性

    • 双缓冲模式:支持分散/聚集I/O
    • TSO:TCP Segmentation Offload
    • IEEE 1588:精确时间戳
    • TSN:时间敏感网络

10.2 实践建议

  1. 阅读Databook

    • DWC Ethernet QoS Databook Chapter 19
    • 重点关注描述符格式和工作流程
  2. 查看波形

    • 使用波形查看工具观察DMA行为
    • 重点观察OWN位变化、状态写回

参考资料

  1. Synopsys DWC Ethernet QoS Databook (Version 5.10a)

    • Chapter 19: Descriptors (Page 1316-1351)
    • Chapter 5: Station Management Agent
  2. IEEE 802.3 Ethernet Standard

    • MAC Control and DMA specification
  3. IEEE 1588 Precision Time Protocol (PTP)

    • Timestamping mechanism
  4. IEEE 802.1Qbv Time-Aware Shaping

    • TSN gate control scheduling

附录:描述符位域速查表

A.1 发送描述符TDES3速查表

名称 说明
31 OWN 1/0 所有权位:1=DMA拥有,0=驱动拥有
30 CTXT 0 上下文类型:0=普通描述符
29 FD 1/0 首描述符:1=包的第一个描述符
28 LD 1/0 尾描述符:1=包的最后一个描述符
27:26 CPC 00 CRC和填充控制:00=自动
25:23 SAIC 000 源地址插入控制
22:19 SLOTNUM - 门控调度槽号
18 TSE 0/1 TCP分段使能
17:16 CIC 00 校验插入控制
14:0 FL - 帧长度(字节)

A.2 接收描述符RDES3速查表

名称 说明
31 OWN 1/0 所有权位:1=DMA拥有,0=驱动拥有
30 CTXT 0/1 上下文描述符标识
29 LD 1/0 尾描述符:1=包的最后一个描述符
28 FD 1/0 首描述符:1=包的第一个描述符
27 ERR 1/0 错误汇总
24 ES 1/0 错误状态:1=接收出错
23 CE 1/0 CRC错误
22 GP 1/0 巨型包
21 RWT 1/0 接收看门狗超时
20 OE 1/0 溢出错误
19 RE 1/0 接收错误
14:0 Length - 接收帧长度(字节)

来源 :DWC Ethernet QoS Databook学习笔记
声明:本文基于Synopsys官方文档整理,仅供学习交流使用

相关推荐
誰能久伴不乏1 天前
SPI总线通信协议基础与ICM20607传感器驱动开发指南
arm开发·c++·驱动开发·嵌入式硬件·arm
CinzWS1 天前
A53指令级验证策略:从随机测试到定向场景——ARM CPU验证的“炼金术“
arm开发·嵌入式·芯片验证·原型验证·a53
AI服务老曹2 天前
【架构深评】打通 X86/ARM 异构屏障:基于 GB28181/RTSP 的企业级 AI 视频管理平台架构解析
arm开发·人工智能·架构
szxinmai主板定制专家2 天前
基于ARM+FPGA高性能MPSOC 多轴伺服设计方案
arm开发·人工智能·嵌入式硬件·fpga开发·架构
AI服务老曹2 天前
[深度解析] 兼容 X86/ARM 与多模态 NPU:基于 GB28181/RTSP 的工业级 AI 视频中台架构设计
arm开发·人工智能·音视频
青柠小苍兰2 天前
Mac(M4 Pro)安装 Parallels Desktop 20 + Windows 11 ARM 完整教程
arm开发·macos·虚拟机·parallels
相偎2 天前
arm平台编译mpp、ffmpeg和xfreerdp
arm开发·ffmpeg
时空自由民.3 天前
蓝牙协议栈知识和网络协议栈知识对比
网络·arm开发·网络协议
QAQ小菜鸟3 天前
五、keil添加AC5
arm开发