API GUIDE / MAC / HAL
G32S10 MAC HAL 接口
HAL 层接口:hal_mac.h 为调试开关提供默认值,保证未经过 Kconfig 时也可编译:
1. 资源模型与公开类型
1.1 Kconfig 选项
| 配置项 | 类型/依赖 | 默认值 | 说明 |
|---|---|---|---|
CONFIG_DRIVER_MAC | bool,select DRIVER_CPM | n | 编译 G32S10 MAC HAL 驱动 |
CONFIG_MAC_ENABLE_DEBUG_HELPERS | bool,depends on SDK_ENABLE_DEBUG_HELPERS | n | 编译 MAC 调试辅助代码(寄存器/描述符 dump) |
CONFIG_SDK_ENABLE_DEBUG_HELPERS | SDK 全局开关 | 由 SDK 配置决定 | 与上一项同时打开时 dump 接口才输出日志 |
hal_mac.h 为调试开关提供默认值,保证未经过 Kconfig 时也可编译:
#ifndef CONFIG_MAC_ENABLE_DEBUG_HELPERS #define CONFIG_MAC_ENABLE_DEBUG_HELPERS (0U) #endif
CMakeLists.txt 在 CONFIG_DRIVER_MAC 打开时注册组件 g32s10_mac,源文件为 hal_mac.c。
1.2 硬件能力摘要
以下能力均可由 mac_regs.h、hal_mac.h 或 hal_mac.c 直接证实;未封装的硬件特性单独标注。
| 项目 | 说明 | 依据 |
|---|---|---|
| 控制器实例 | 单实例 MAC | mac_regs.h |
| 速率与双工 | MAC_CR.PS 选择 MII、FES 选择 10/100 Mbps、DM 选择半/全双工;HAL 只接受 10M/100M | hal_mac_speed_t、hal_mac_duplex_t |
| MDIO | IEEE 802.3 Clause 22,PHY 地址与寄存器地址各 5 bit,MDC 时钟范围 4 bit | GMII_AR.PA[15:11]、GR[10:6]、CR[5:2] |
| DMA 描述符 | normal 4 字描述符;enhanced 有结构定义但 HAL 当前拒绝 | hal_mac_dma_desc_t、hal_mac_dma_ext_desc_t、hal_mac_init() |
| DMA 突发 | TX/RX PBL 可配,取值 1/2/4/8/16/32;支持 fixed burst、mixed burst | hal_mac_config_t、MAC_DMA_BMR.PBL/RPBL/FB/MB |
| DMA 地址宽度 | 描述符基地址与 buffer 地址按 32 位编程 | hal_mac.c 中 (uint32_t)(uintptr_t) 转换 |
| MAC 地址寄存器 | 2 个(索引 0、1) | MAC_ADDRESS_REGISTER_COUNT |
| 流控与校验和 | MAC_FCR.RFE/TFE 与 pause time;RX MAC_CR.IPC;TX descriptor CIC=3 | hal_mac_set_flow_control()、hal_mac_config_t |
| 中断 | 单个 SoC IRQ IRQ_GMAC;DMA 数据通路中断经 DMA_IER 使能;MAC_ISR 的 LPI/TS/PMT/PCS/RGSMII 等 MAC 核中断由 MAC_IMR 屏蔽(MMC 中断位无对应 IMR mask),HAL 均不处理 | irq_table.def、hal_mac_init()、MAC_ISR_* |
| 时间戳/PPS/AV/MMC/LPI/VLAN | 寄存器布局与位域有定义,HAL/LL 未提供访问函数 | mac_regs.h、MAC_LPI_*、MAC_VTR_* |
1.3 错误位
| 错误位 | 值 | 置位来源 |
|---|---|---|
HAL_MAC_ERROR_NONE | 0x000 | 初始值 |
HAL_MAC_ERROR_INVALID_PARAM | 0x001 | 定义保留;当前实现不在 handle 中置位 |
HAL_MAC_ERROR_DMA_RESET_TIMEOUT | 0x002 | hal_mac_init() 等待 DMA_BMR.SWR 清零超时 |
HAL_MAC_ERROR_TX_TIMEOUT | 0x004 | hal_mac_transmit() 等待 TX 环可用超时,或 systick 未初始化 |
HAL_MAC_ERROR_RX_TIMEOUT | 0x008 | 定义保留;当前 hal_mac_receive() 超时只返回错误码,不置位 |
HAL_MAC_ERROR_MII_TIMEOUT | 0x010 | MDIO 等待 GMII_AR.GB 清零超时 |
HAL_MAC_ERROR_TX_UNDERFLOW | 0x020 | hal_mac_irq_handler() 处理 DMA_SR.UNF |
HAL_MAC_ERROR_RX_OVERFLOW | 0x040 | hal_mac_irq_handler() 处理 DMA_SR.OVF |
HAL_MAC_ERROR_FATAL_BUS | 0x080 | hal_mac_irq_handler() 处理 DMA_SR.FBI,同时进入 ERROR 状态 |
HAL_MAC_ERROR_RX_FRAME | 0x100 | hal_mac_receive() 丢弃错误帧/分段帧 |
handle->error_code 是错误位的 OR 累积值,只有 hal_mac_handle_init()/hal_mac_init() 会清零。致命错误只有 DMA_RESET_TIMEOUT 与 FATAL_BUS,都会把状态置为 ERROR。
1.4 事件位
| 事件位 | 值 | 对应 DMA_SR 位 | 说明 |
|---|---|---|---|
HAL_MAC_EVENT_NONE | 0x00 | 无 | 无事件 |
HAL_MAC_EVENT_RX | 0x01 | RI[6] | RX 帧完成 |
HAL_MAC_EVENT_TX | 0x02 | TI[0] | TX 帧完成 |
HAL_MAC_EVENT_RX_BUFFER_UNAVAILABLE | 0x04 | RU[7] | RX 缓冲区不可用 |
HAL_MAC_EVENT_TX_BUFFER_UNAVAILABLE | 0x08 | TU[2] | TX 缓冲区不可用 |
HAL_MAC_EVENT_TX_UNDERFLOW | 0x10 | UNF[5] | TX underflow |
HAL_MAC_EVENT_RX_OVERFLOW | 0x20 | OVF[4] | RX overflow |
HAL_MAC_EVENT_FATAL_BUS_ERROR | 0x40 | FBI[13] | 致命总线错误 |
HAL_MAC_EVENT_ABNORMAL | 0x80 | AIS[15] | DMA 异常中断汇总 |
说明:事件集合只覆盖 HAL 默认通过 DMA_IER 使能的 DMA 数据通路中断源。DMA_SR 中 early receive/transmit、receive watchdog、process-stopped、jabber timeout 等源当前未使能,不会由 hal_mac_irq_handler() 报告;MAC_ISR 中的 LPI、PMT、PCS、MMC、timestamp 等 MAC 核中断源不在该 handler 范围内。
1.5 hal_mac_config_t
| 字段 | 类型 | 说明 | 约束 |
|---|---|---|---|
mac_address | uint8_t[6] | 主 MAC 地址,hal_mac_init() 写入地址寄存器 0 | 6 字节;字节序见 4.3.3 |
mtu | uint32_t | Ethernet MTU | > 0 且 <= HAL_MAC_MAX_MTU(2000);> 1500 时 HAL 置 MAC_CR.TWOKPE |
speed | hal_mac_speed_t | 初始速率 | HAL_MAC_SPEED_10M 或 HAL_MAC_SPEED_100M |
duplex | hal_mac_duplex_t | 初始双工 | HAL_MAC_DUPLEX_HALF 或 HAL_MAC_DUPLEX_FULL |
mdc_clock_range | uint32_t | GMII_AR.CR[5:2] 字段值 | 0 ~ 0xF |
tx_dma_pbl / rx_dma_pbl | uint32_t | 分别写入 DMA_BMR.PBL / RPBL 的 TX/RX 突发长度 | 非 0、<= 32 且为 2 的幂(1/2/4/8/16/32) |
fixed_burst / mixed_burst | bool | 置 DMA_BMR.FB / MB | 无额外校验;两者互斥性由调用方保证 |
checksum_offload | bool | 置 MAC_CR.IPC,并在 TX 描述符写 CIC=3 | 无额外校验 |
rx_watchdog_enable | bool | 为真时写 DMA_RIWTR | 无额外校验 |
rx_watchdog | uint8_t | DMA_RIWTR.RIWT[7:0] 值 | 0 ~ 0xFF |
desc_type | hal_mac_desc_type_t | 描述符格式 | hal_mac_config_is_valid() 接受两个枚举值,但 hal_mac_init() 只接受 HAL_MAC_DESC_NORMAL |
desc_mode | hal_mac_desc_mode_t | 描述符遍历方式 | RING 或 CHAIN |
tx_desc / rx_desc | void * | TX/RX 描述符数组首地址 | 非 NULL,按 HAL_MAC_DMA_ALIGN 对齐,容量至少 count * sizeof(hal_mac_dma_desc_t) |
tx_desc_count / rx_desc_count | uint32_t | TX/RX 描述符数量 | >= HAL_MAC_MIN_DESCRIPTOR_COUNT(2) |
tx_buffer / rx_buffer | uint8_t * | TX/RX 缓冲区首地址 | 非 NULL,按 HAL_MAC_DMA_ALIGN 对齐,容量至少 count * buffer_size |
tx_buffer_size / rx_buffer_size | uint32_t | 每个 TX/RX 槽字节数 | >= mtu 且 <= HAL_MAC_MAX_BUFFER_SIZE(2047) |
hal_mac_config_is_valid() 会逐项校验上表约束。hal_mac_handle_init() 会清零整个 handle,因此必须在 hal_mac_handle_init() 之后再填充 handle->config。
1.6 hal_mac_stats_t
| 字段 | 说明 | 更新点 |
|---|---|---|
tx_packets | DMA 完成且描述符无错误的 TX 帧数 | hal_mac_tx_clean() |
rx_packets | 成功接收并拷贝的 RX 帧数 | hal_mac_receive() |
tx_bytes | 拷入 TX 缓冲区的字节数(按完成描述符长度统计) | hal_mac_tx_clean() |
rx_bytes | 从 RX 缓冲区拷出的字节数(FCS 处理后) | hal_mac_receive() |
tx_errors | TX 侧 HAL 错误计数(描述符 ES、TX underflow) | hal_mac_tx_clean()、hal_mac_irq_handler() |
rx_errors | RX 侧 HAL 错误计数(丢弃错误帧、RX overflow) | hal_mac_receive()、hal_mac_irq_handler() |
tx_underflow_errors | DMA UNF 次数 | hal_mac_irq_handler() |
rx_overflow_errors | DMA OVF 次数 | hal_mac_irq_handler() |
fatal_bus_errors | DMA FBI 次数 | hal_mac_irq_handler() |
统计只在 hal_mac_handle_init()/hal_mac_init() 时清零,其余时刻单调累加。
1.7 hal_mac_handle_t
| 字段 | 类型 | 说明 |
|---|---|---|
macx | mac_regs_t * | 绑定的 MAC 寄存器块,当前固定为 MAC |
config | hal_mac_config_t | 初始化配置副本;hal_mac_set_link_config() 会回写 speed/duplex |
state | hal_mac_state_t | 当前 HAL 状态 |
error_code | uint32_t | OR 累积的 hal_mac_error_t 错误位 |
tx_index | uint32_t | 下一次 hal_mac_transmit() 使用的 TX 描述符索引 |
tx_clean_index | uint32_t | 下一次回收检查的 TX 描述符索引 |
tx_pending_count | uint32_t | 已交给 DMA、尚未回收的 TX 描述符数量 |
rx_index | uint32_t | 下一次 hal_mac_receive() 使用的 RX 描述符索引 |
stats | hal_mac_stats_t | 运行期统计 |
说明:HAL 不提供内部锁。hal_mac_transmit() 与 hal_mac_tx_reclaim() 内部用短临界区保护 TX 环索引与描述符状态,但 config、stats、state、error_code 的并发访问仍需调用方串行化;同一 handle 不应被多个任务或任务与 ISR 同时操作。
2. HAL 接口规范
HAL 公开函数共 19 个,分为生命周期与状态、数据路径、链路与 MDIO、查询与调试四组。
2.1 生命周期与状态
2.1.1 hal_mac_config_is_valid
bool hal_mac_config_is_valid(const hal_mac_config_t *config);
功能:校验配置负载是否满足 HAL 的硬件与内存约束,不做任何寄存器操作。参数 config 为待校验配置,NULL 返回 false。
返回:true 合法,false 非法。校验项包括:speed/duplex/desc_type/desc_mode 枚举合法;mtu 为 1 ~ HAL_MAC_MAX_MTU;mdc_clock_range <= 0xF;PBL 非 0、<= 32 且为 2 的幂;四个指针非 NULL 且按 HAL_MAC_DMA_ALIGN 对齐;tx_desc_count/rx_desc_count >= HAL_MAC_MIN_DESCRIPTOR_COUNT;tx_buffer_size/rx_buffer_size 均在 [mtu, HAL_MAC_MAX_BUFFER_SIZE] 内。注意本函数接受 HAL_MAC_DESC_ENHANCED,但 hal_mac_init() 会拒绝。
2.1.2 hal_mac_handle_init
error_code_t hal_mac_handle_init(hal_mac_handle_t *handle);
功能:清零 handle,绑定默认 MAC 实例,状态置 HAL_MAC_STATE_RESET;不访问 MAC 寄存器、不使能时钟。参数 handle 为调用方提供的存储,为空或 MAC 实例检查失败返回 IM_ERR_INVALID_PARAM。
返回:IM_OK 或 IM_ERR_INVALID_PARAM。本函数会 memset 整个 handle,因此 handle->config 必须在调用本函数之后填充。典型顺序:hal_mac_handle_init() → 填充 handle->config → hal_mac_init()。
2.1.3 hal_mac_init
error_code_t hal_mac_init(hal_mac_handle_t *handle);
功能:复位 DMA、初始化 TX/RX 描述符环、编程 DMA 与 MAC 基础寄存器,使 handle 进入 READY;MAC RX/TX 与 DMA 引擎仍保持停止,需要 hal_mac_start() 才启动。参数 handle 必须已完成 hal_mac_handle_init() 并填充 config。
| 返回值 | 说明 |
|---|---|
IM_OK | 初始化成功,状态为 READY |
IM_ERR_INVALID_PARAM | handle 为空、实例非法或 config 未通过 hal_mac_config_is_valid() |
IM_ERR_UNSUPPORTED | config.desc_type == HAL_MAC_DESC_ENHANCED |
IM_ERR_TIMEOUT | 等待 DMA_BMR.SWR 清零超过内部 100 ms 超时 |
执行步骤:
清零
state、error_code、TX/RX 索引与计数、stats,状态置RESET。置
DMA_BMR.SWR发起 DMA 软复位,等待其自动清零(HAL_MAC_DMA_RESET_TIMEOUT_MS = 100)。按
desc_mode初始化描述符:RING 在尾元素置END_RING,CHAIN 在所有元素置CHAINED并写下一元素地址(尾元素回绕首元素);随后写DMA_TDLAR/DMA_RDLAR为 32 位基地址。编程
DMA_BMR(PBL、RPBL,按需FB、MB)、DMA_OMR = TSF|RSF|OSF、DMA_IER = NORMAL_IRQ_MASK|ABNORMAL_IRQ_MASK(NIE|RIE|TIE|AIE|FBE|UNE),按需写DMA_RIWTR。写入地址寄存器 0;再执行 MAC 核配置:
MAC_CR |= JD|PS|ACS|BE,MTU 大于 1500 时追加TWOKPE,checksum_offload时追加IPC;随后写速率/双工位;最后写MAC_IMR屏蔽LPIIM|TSIM|PMTIM|PCSANCIM|PCSLCHGIM|RGSMIIIM。状态置
READY,返回IM_OK。
补充说明:时钟门控与 MAC 软复位不由本接口负责;调用前 BSP 必须已使能 HAL_CPM_ID_GATE_MAC 并释放 MAC 软复位。描述符与 DMA 寄存器编程可重复;失败时不会回滚已写寄存器,建议重新走完整初始化流程;DMA 软复位超时会置 ERROR 状态。
2.1.4 hal_mac_deinit
error_code_t hal_mac_deinit(hal_mac_handle_t *handle);
功能:停止 MAC RX/TX 与 DMA,清 DMA_IER,handle 状态置回 RESET。参数 handle 为已初始化句柄;返回 IM_OK,handle 为空或实例非法返回 IM_ERR_INVALID_PARAM。
补充说明:内部调用 hal_mac_stop(),可重复调用;不关闭 CPM 时钟、不置 MAC 软复位、不释放描述符/缓冲区内存,也不清零 stats 与 error_code。
2.1.5 hal_mac_start
error_code_t hal_mac_start(hal_mac_handle_t *handle);
功能:置 MAC_CR.TE|RE 使能 MAC 发送/接收,置 DMA_OMR.ST|SR 启动 DMA TX/RX 引擎,状态变为 BUSY。
| 返回值 | 说明 |
|---|---|
IM_OK | 启动成功,状态为 BUSY |
IM_ERR_INVALID_PARAM | handle 为空或实例非法 |
IM_ERR_NOT_READY | 当前状态不是 HAL_MAC_STATE_READY |
补充说明:只置启动位,不重写描述符或配置寄存器;重复调用会因状态不是 READY 而返回 IM_ERR_NOT_READY。
2.1.6 hal_mac_stop
error_code_t hal_mac_stop(hal_mac_handle_t *handle);
功能:清 DMA_OMR.ST|SR 与 MAC_CR.TE|RE,停止 MAC/DMA 收发。返回 IM_OK;handle 为空或实例非法返回 IM_ERR_INVALID_PARAM。
补充说明:不检查当前状态;状态为 BUSY 时停止后变为 READY,其它状态不变。停止后未回收的 TX 描述符与未读取的 RX 描述符不会被清除,重新 hal_mac_start() 后可继续处理。
2.2 数据路径
2.2.1 hal_mac_transmit
error_code_t hal_mac_transmit(hal_mac_handle_t *handle, const uint8_t *data, uint32_t len, uint32_t timeout_ms);
功能:把一帧数据拷入 TX 缓冲区,填写当前 TX 描述符并交给 DMA。参数 handle 必须处于 BUSY;data 为帧数据首地址;len 必须 > 0 且 <= config.tx_buffer_size;timeout_ms 为等待 TX 环可用的超时,0 表示只检查一次。
| 返回值 | 说明 |
|---|---|
IM_OK | 帧已交给 DMA |
IM_ERR_INVALID_PARAM | handle/实例/data 非法,或 len 越界 |
IM_ERR_NOT_READY | 状态不是 BUSY;或 timeout_ms > 0 且 systick 未初始化 |
IM_ERR_TIMEOUT | 超时时间内没有等到可用 TX 描述符 |
行为与约束:
进入短临界区后先调用内部
hal_mac_tx_clean()回收已完成描述符;tx_pending_count >= tx_desc_count时释放临界区并按timeout_ms重试。当前tx_index描述符若仍被 DMA 拥有(DES0[31]=1),说明环满,需要等待。timeout_ms == 0时只检查一次,条件不满足立即失败;timeout_ms > 0时循环等待,内部每轮msleep(1)。等待依赖im_systick_is_initialized();未初始化 systick 且timeout_ms > 0时记录HAL_MAC_ERROR_TX_TIMEOUT并返回IM_ERR_NOT_READY。数据拷入
config.tx_buffer[tx_index * tx_buffer_size]后对缓冲区做 cache clean。成功后推进
tx_index并递增tx_pending_count,一帧只占一个描述符。本接口不做链路状态检查;链路 down 时是否发送由上层决定。
2.2.2 hal_mac_receive
error_code_t hal_mac_receive(hal_mac_handle_t *handle, uint8_t *data, uint32_t *len_inout, uint32_t timeout_ms);
功能:从当前 RX 描述符读取一帧,做 FCS 处理与基本合法性检查后拷出。参数 handle 必须处于 BUSY;data 为目的缓冲区;len_inout 输入为容量、输出为实际帧长(FCS 处理后);timeout_ms 为等待 RX 帧的超时,0 表示只检查一次。
| 返回值 | 说明 |
|---|---|
IM_OK | 成功接收一帧 |
IM_ERR_INVALID_PARAM | handle/实例/data/len_inout 非法,或 *len_inout == 0 |
IM_ERR_NOT_READY | 状态不是 BUSY;发生错误帧丢弃;或 systick 未初始化且 timeout_ms > 0 |
IM_ERR_TIMEOUT | 超时时间内当前 RX 描述符仍被 DMA 拥有 |
IM_ERR_UNSUPPORTED | 帧没有同时置 FS 与 LS(跨描述符帧),该帧被丢弃 |
IM_ERR_NO_SPACE | 目的缓冲区容量小于实际帧长;*len_inout 被更新为所需长度,该帧被丢弃 |
行为与约束:
每次调用首先读取
DMA_MFOCR(读清寄存器),该读取会清除 missed frame 计数与 overflow 标志,只用于调试日志,不影响接收流程。当前
rx_index描述符被 DMA 拥有(DES0[31]=1)时按timeout_ms等待;timeout_ms == 0只检查一次。DES0[15](错误汇总)置位时丢弃该帧:rx_errors++、置HAL_MAC_ERROR_RX_FRAME、释放描述符,返回IM_ERR_NOT_READY;帧未同时置FS与LS时丢弃并返回IM_ERR_UNSUPPORTED。帧长取自
DES0[29:16],随后按 FCS 规则修正:
| 类型/长度字段 | MAC_CR 条件 | HAL 判定 |
|---|---|---|
< 0x0600(802.3 长度字段) | ACS = 1 | 硬件已剥离 FCS,不再减 4 |
>= 0x0600(EtherType) | CST = 1 | 硬件已剥离 FCS,不再减 4 |
| 其它情况 | — | 认为 FCS 仍在帧尾,HAL 去掉末尾 4 字节 |
FCS 处理后帧长仍小于 Ethernet 头(14 字节)时丢弃;需要减 FCS 但帧长不足 4 字节时也丢弃。目的缓冲区不足时先写回所需长度,再丢弃该帧并返回
IM_ERR_NO_SPACE。
2.2.3 hal_mac_tx_reclaim
error_code_t hal_mac_tx_reclaim(hal_mac_handle_t *handle);
功能:回收已由 DMA 完成的 TX 描述符,更新 TX 统计和索引。参数 handle 为已初始化句柄。
| 返回值 | 说明 |
|---|---|
IM_OK | 至少回收一个描述符 |
IM_ERR_BUSY | 当前没有已完成的 TX 描述符 |
IM_ERR_INVALID_PARAM | handle 为空或实例非法 |
IM_ERR_UNSUPPORTED | config.desc_type != HAL_MAC_DESC_NORMAL |
补充说明:
头文件约定本接口在线程上下文调用,不要在中断上下文中调用;实现内部用短临界区保护 TX 环。典型时机:收到
HAL_MAC_EVENT_TX之后,或在检查 TX 环空间之前。回收逻辑从
tx_clean_index开始逐项 invalidate 描述符;OWN仍为 1 时停止。对LS置位的描述符统计:ES置位时tx_errors++,否则tx_packets++且tx_bytes += DES1[10:0]。回收后描述符
DES0只保留CHAINED|END_RING,DES1、DES2清零,DES3保留。
2.2.4 hal_mac_irq_handler
uint32_t hal_mac_irq_handler(hal_mac_handle_t *handle);
功能:读取并清除 HAL 已处理的 DMA 数据通路中断状态,返回事件位图供上层分发。参数 handle 为 MAC handle,为 NULL 或实例非法时直接返回 0;返回 OR 组合的 hal_mac_event_t 位图,无事件时返回 HAL_MAC_EVENT_NONE。
DMA_SR 位与事件、副作用的对应关系:
DMA_SR 位 | 事件 | 附加动作 |
|---|---|---|
RI[6] | HAL_MAC_EVENT_RX | 无 |
TI[0] | HAL_MAC_EVENT_TX | 无 |
RU[7] | HAL_MAC_EVENT_RX_BUFFER_UNAVAILABLE | 无 |
TU[2] | HAL_MAC_EVENT_TX_BUFFER_UNAVAILABLE | 无 |
UNF[5] | HAL_MAC_EVENT_TX_UNDERFLOW | tx_underflow_errors++、tx_errors++、置 HAL_MAC_ERROR_TX_UNDERFLOW |
OVF[4] | HAL_MAC_EVENT_RX_OVERFLOW | rx_overflow_errors++、rx_errors++、置 HAL_MAC_ERROR_RX_OVERFLOW |
FBI[13] | HAL_MAC_EVENT_FATAL_BUS_ERROR | fatal_bus_errors++、置 HAL_MAC_ERROR_FATAL_BUS 并进入 ERROR 状态 |
AIS[15] | HAL_MAC_EVENT_ABNORMAL | 无 |
NIS[16] | 无对应事件 | 仅清除状态位 |
补充说明:
只清除上述已处理的
DMA_SR位与NIS,未处理的中断源(early RX/TX、RWT、RPS、ETI、ERI 等)不清除;本 handler 也不读取MAC_ISR,不处理 LPI、PMT、PCS、MMC、timestamp 等 MAC 核中断(这些源在hal_mac_init()中通过MAC_IMR屏蔽)。本 handler 不回收 TX 描述符。收到
HAL_MAC_EVENT_TX后,调用方应在线程上下文调用hal_mac_tx_reclaim()。调用方应在 SoC IRQ 入口调用本接口,并把返回值交给事件/worker 分发逻辑;不要在 IRQ 中做帧拷贝或阻塞等待。
2.3 链路、MDIO 与地址
2.3.1 hal_mac_mdio_read
error_code_t hal_mac_mdio_read(hal_mac_handle_t *handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data_out, uint32_t timeout_ms);
功能:通过 Clause 22 MDIO 读取一个 PHY 寄存器。参数 handle 需提供已填好的 mdc_clock_range;phy_addr、reg_addr 均为 0 ~ 31;data_out 为读回的 16 位值;timeout_ms 为等待 MDIO 完成的超时,0 表示只检查一次。
| 返回值 | 说明 |
|---|---|
IM_OK | 读取成功 |
IM_ERR_INVALID_PARAM | handle/实例/地址/输出指针非法 |
IM_ERR_BUSY | 发起事务前 GMII_AR.GB 已置位(上一次事务未完成) |
IM_ERR_TIMEOUT | 等待 GMII_AR.GB 清零超时;同时置 HAL_MAC_ERROR_MII_TIMEOUT |
补充说明:GMII_AR 字段组成为 PA[15:11]、GR[10:6]、CR[5:2](来自 config.mdc_clock_range)、GB[0]=1;等待完成的条件是 GB 清零,完成后读 GMII_DR[15:0]。本接口不检查 HAL 状态机,但 config.mdc_clock_range 需在调用前填好;timeout_ms == 0 时如果第一次检查仍忙,直接返回 IM_ERR_TIMEOUT。HAL 不解析 PHY 寄存器语义,也不做自动协商。
2.3.2 hal_mac_mdio_write
error_code_t hal_mac_mdio_write(hal_mac_handle_t *handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t data, uint32_t timeout_ms);
功能:通过 Clause 22 MDIO 写一个 PHY 寄存器。参数含义同 hal_mac_mdio_read(),data 为待写入的 16 位值。
| 返回值 | 说明 |
|---|---|
IM_OK | 写入成功 |
IM_ERR_INVALID_PARAM | handle/实例/地址非法 |
IM_ERR_BUSY | 发起事务前 GMII_AR.GB 已置位 |
IM_ERR_TIMEOUT | 等待 GMII_AR.GB 清零超时;同时置 HAL_MAC_ERROR_MII_TIMEOUT |
补充说明:先写 GMII_DR[15:0],再写 GMII_AR = PA | GR | CR | GW | GB(GW[1]=1 表示写事务)。
2.3.3 hal_mac_set_address
error_code_t hal_mac_set_address(hal_mac_handle_t *handle, uint32_t index, const uint8_t address[HAL_MAC_ADDRESS_SIZE]);
功能:写 MAC 地址寄存器 0 或 1。参数 handle 为 MAC handle;index 为 0 或 1(< MAC_ADDRESS_REGISTER_COUNT);address 为 6 字节 Ethernet MAC 地址,address[0] 为线上最先发送的字节。
返回:IM_OK;handle/实例/地址指针为空或 index >= 2 时返回 IM_ERR_INVALID_PARAM。
补充说明:
地址高字:
ADDRHI = (address[5] << 8) | address[4];低字:ADDRLO = address[3..0]大端拼接。
2.3.4 hal_mac_set_link_config
error_code_t hal_mac_set_link_config(hal_mac_handle_t *handle, hal_mac_speed_t speed, hal_mac_duplex_t duplex);
功能:按请求的速率/双工配置 MAC_CR 的 PS、FES、DM 位,并回写 handle->config。参数 speed 取 HAL_MAC_SPEED_10M 或 HAL_MAC_SPEED_100M;duplex 取 HAL_MAC_DUPLEX_HALF 或 HAL_MAC_DUPLEX_FULL。
返回:IM_OK(同步更新 config.speed/duplex);handle/实例非法或枚举为 UNKNOWN 时返回 IM_ERR_INVALID_PARAM。
位映射:100 Mbps → PS=1、FES=1;10 Mbps → PS=1、FES=0;全双工 → DM=1;半双工 → DM=0。写入前先清 PS|FES|DM,再按映射置位;不改变 MAC_CR 其它位,也不访问 PHY 或 CPM。
2.3.5 hal_mac_set_flow_control
error_code_t hal_mac_set_flow_control(hal_mac_handle_t *handle, hal_mac_flow_control_t flow_control, uint16_t pause_time);
功能:写 MAC_FCR,配置 pause frame 时间值和 RX/TX 流控使能。参数 flow_control 取 NONE、RX、TX、RX_TX 的组合;pause_time 写入 MAC_FCR.PT[31:16]。
返回:IM_OK;handle/实例非法或 flow_control 含 RX_TX 之外的位时返回 IM_ERR_INVALID_PARAM。
补充说明:本接口是整寄存器写,DZPQ、PLT、UP、FCB_BPA 等未涉及字段会被清零;不保存流控配置副本,也不在 hal_mac_init() 中自动恢复。
2.4 查询与调试
2.4.1 hal_mac_get_stats
error_code_t hal_mac_get_stats(const hal_mac_handle_t *handle, hal_mac_stats_t *stats_out);
功能:把 handle 内的统计快照拷贝到调用方缓冲区。参数 handle 为 MAC handle;stats_out 为统计输出。返回 IM_OK;参数为空返回 IM_ERR_INVALID_PARAM。本接口只做结构体赋值,不检查实例、状态或描述符类型,也不清零统计。
2.4.2 hal_mac_get_hw_feature
error_code_t hal_mac_get_hw_feature(const hal_mac_handle_t *handle, uint32_t *value_out);
功能:读取 HWFR 硬件能力寄存器原始值。参数 value_out 为输出指针。返回 IM_OK;handle/实例/输出指针非法时返回 IM_ERR_INVALID_PARAM。HAL 不对 HWFR 做位域解码,位定义见 6.14。
2.4.3 hal_mac_dump_regs
error_code_t hal_mac_dump_regs(const hal_mac_handle_t *handle);
功能:把 MAC 核与 DMA 关键寄存器输出到日志,用于调试。
| 返回值 | 说明 |
|---|---|
IM_OK | 日志已输出 |
IM_ERR_INVALID_PARAM | handle 为空或实例非法 |
IM_ERR_UNSUPPORTED | 未同时启用 CONFIG_SDK_ENABLE_DEBUG_HELPERS 与 CONFIG_MAC_ENABLE_DEBUG_HELPERS |
补充说明:
只有两个 Kconfig 开关同时为真时才编译日志代码,否则直接返回
IM_ERR_UNSUPPORTED。输出寄存器包括:
CR、FFR、HTHR、HTLR、GMII_AR、GMII_DR、FCR、VTR、VR、DR、LPI_CSR、LPI_TCR、ISR、IMR、A0HR/A0LR、A1HR/A1LR、DMA_BMR、DMA_RDLAR、DMA_TDLAR、DMA_SR、DMA_OMR、DMA_IER、DMA_MFOCR、DMA_RIWTR、DMA_AHBSR、DMA_CHTDR/CHRDR/CHTBAR/CHRBAR、HWFR。本接口会读取
DMA_MFOCR,该寄存器为读清寄存器,因此 dump 会顺带清除 missed frame 计数与 overflow 标志。本接口只读寄存器,不改变 HAL 状态。
2.4.4 hal_mac_dump_desc
error_code_t hal_mac_dump_desc(const hal_mac_handle_t *handle);
功能:把 TX/RX 描述符环的 DES0~`DES3` 输出到日志,用于调试。
| 返回值 | 说明 |
|---|---|
IM_OK | 日志已输出 |
IM_ERR_INVALID_PARAM | handle 为空、tx_desc/rx_desc 为空或指针非法 |
IM_ERR_NOT_READY | tx_desc_count 或 rx_desc_count 为 0 |
IM_ERR_UNSUPPORTED | 未同时启用两个调试 Kconfig 开关 |
补充说明:输出内容是采样快照;DMA 正在运行时描述符会被硬件并发更新,多字输出之间可能不一致。描述符地址按 32 位十六进制打印。
2.5 超时语义与公共行为约定
| 场景 | timeout_ms == 0 | timeout_ms > 0 |
|---|---|---|
| 条件已满足 | 立即成功 | 立即成功 |
| 条件未满足 | 检查一次后失败 | 轮询直到超时,每轮之间 msleep(1) |
| systick 未初始化 | 不依赖 systick,仍可单次检查 | 该次调用失败 |
各接口在 systick 未初始化且 timeout_ms > 0 时的具体表现:hal_mac_transmit() 返回 IM_ERR_NOT_READY 并置 HAL_MAC_ERROR_TX_TIMEOUT;hal_mac_receive() 返回 IM_ERR_NOT_READY 且不置位;hal_mac_mdio_read()/hal_mac_mdio_write() 返回 IM_ERR_TIMEOUT 并置 HAL_MAC_ERROR_MII_TIMEOUT。
其它公共约定:
HAL 内部只在 TX 环相关路径(
hal_mac_transmit()、hal_mac_tx_reclaim())使用短临界区,不提供全局锁。HAL 负责描述符与缓冲区的 cache 维护:初始化时对 RX 缓冲区做 clean + invalidate 后交给 DMA;发送前 clean TX 缓冲区;读取 RX 缓冲区前 invalidate;描述符更新后 clean、读取前 invalidate;接收完成释放 RX 描述符时只写回
OWN并 clean 描述符(不再次刷缓冲区)。HAL 不做动态内存分配;不检查链路状态;不访问 PHY 寄存器语义;不注册 IRQ。
3. 当前实现约束与行为说明
3.1 DMA 使用 32 位地址、MTU 与缓冲区上限
DMA_RDLAR、DMA_TDLAR、描述符 DES2/DES3 都只有 32 位。HAL 在 hal_mac_init() 和 hal_mac_transmit() 中把指针转换为 uint32_t,因此描述符与缓冲区必须位于 32 位可寻址空间;超出 32 位的高地址会被截断,属于调用方配置错误。
mtu 最大 2000,大于 1500 时 HAL 置 MAC_CR.TWOKPE;单描述符缓冲区最大 2047 字节,受 TX/RX 描述符 DES1[10:0] 位宽限制;tx_buffer_size/rx_buffer_size 必须 >= mtu 且 <= 2047。一帧必须放进一个缓冲区;HAL 不支持跨描述符 TX 分段,也不接受跨描述符 RX 帧。
3.2 RX FCS 处理
hal_mac_receive() 根据帧的 type/length 字段与 MAC_CR.ACS/CST 判断硬件是否已剥离 FCS:长度字段 < 0x0600 且 ACS=1,或 EtherType >= 0x0600 且 CST=1 时认为已剥离;否则认为 FCS 仍在帧尾,HAL 减去 4 字节。该判断依赖 MAC_CR 当前值,而不是每个描述符都带“FCS 已剥离”标志;若调用方在运行中改变 ACS/CST,需要自行保证判断与硬件行为一致。
3.3 无内部锁
HAL 不提供互斥锁。hal_mac_transmit() 与 hal_mac_tx_reclaim() 用 local_irq_save()/local_irq_restore() 保护 TX 环索引与描述符状态,但多个任务同时调用 hal_mac_transmit() 仍可能因拷贝/描述符更新顺序产生竞争;hal_mac_receive() 没有临界区保护;config、stats、error_code 的读写没有保护。调用方必须自行串行化同一个 handle 的所有访问。
3.4 HAL 不提供 link 自动协商
HAL 只提供 MDIO 读写通道(hal_mac_mdio_read()/hal_mac_mdio_write())、按上层决策写 MAC_CR.PS/FES/DM(hal_mac_set_link_config())和写 MAC_FCR(hal_mac_set_flow_control())。自动协商、PHY 复位、链路状态解码由 PHY 驱动与 Ethernet adapter 完成,见 docs/api/g32s10/middleware/mac_mid_api.md。