API GUIDE / MAC / Middleware

G32S10 MAC Middleware 接口

Middleware 层接口:MID 的 Kconfig 分布在四个位置:

1. 构建配置与文件组织

1.1 Kconfig

MID 的 Kconfig 分布在四个位置:

  • code/middleware/net/lwip/Kconfig:lwIP 协议栈和 IPv6 开关。

  • code/middleware/net/net_adapter/Kconfig:网络适配层与 Ethernet adapter 开关、IP 模式。

  • code/drivers/g32s10/mac/Kconfig:MAC HAL 开关和调试 helper。

  • code/devices/mac_phy/ 下各 Kconfig:PHY 抽象和具体 PHY 驱动。

此外,code/middleware/net/Kconfig 必须通过下列语句把 lwIP 与 net adapter 选项纳入顶层 Kconfig 树:

source "code/middleware/net/lwip/Kconfig"
source "code/middleware/net/net_adapter/Kconfig"

核心选项:

选项类型/依赖默认值说明
MIDDLEWARE_NET_LWIPbool;depends on OS && OS_BACKEND_FREERTOS;select THIRD_PARTY_LWIPn编译 lwIP 2.2.1 和 FreeRTOS port
MIDDLEWARE_NET_LWIP_IPV6bool;依赖 MIDDLEWARE_NET_LWIPn启用 IPv6;当前默认配置关闭,IPv6 相关接口与事件不可用
MIDDLEWARE_NET_ADAPTERbool;依赖 MIDDLEWARE_NET_LWIPy编译网络接口适配层
MIDDLEWARE_NETIF隐藏 boolMIDDLEWARE_NET_ADAPTER适配层公共代码开关
MIDDLEWARE_NET_ADAPTER_ETHbool;依赖 DRIVER_MAC && DEVICE_MAC_PHY;select DRIVER_DTRNG、select DRIVER_EFUSEy编译 Ethernet adapter(im_net_eth.c + im_net_eth_phy.c)
MIDDLEWARE_NET_ADAPTER_ETH_STATIC_IPbool(IP 模式二选一)选中使用静态 IPv4
MIDDLEWARE_NET_ADAPTER_ETH_DHCPbool(IP 模式二选一)未选中启动后运行 DHCP client
MIDDLEWARE_NET_ADAPTER_ETH_IPADDRstring"10.5.4.111"静态 IPv4 地址
MIDDLEWARE_NET_ADAPTER_ETH_GWADDRstring"10.5.4.1"静态网关
MIDDLEWARE_NET_ADAPTER_ETH_NETMASKstring"255.255.255.0"静态掩码
MIDDLEWARE_NET_ADAPTER_ETH_DNS1string"223.5.5.5"首选 DNS;不受 IP 模式影响
MIDDLEWARE_NET_ADAPTER_ETH_DNS2string"0.0.0.0"备用 DNS;0.0.0.0 表示不设置
MIDDLEWARE_NETIF_ETH隐藏 boolMIDDLEWARE_NET_ADAPTER_ETHEthernet netif 辅助开关
DRIVER_MACbool;select DRIVER_CPMn编译 G32S10 MAC HAL
MAC_ENABLE_DEBUG_HELPERSbool;依赖 SDK_ENABLE_DEBUG_HELPERSn编译 HAL 寄存器/描述符 dump
DEVICE_MAC_PHY隐藏 bool被具体 PHY 选中PHY 抽象层公共开关
DEVICE_MAC_PHY_LAN8720Abool;select DEVICE_MAC_PHYn编译 LAN8720A PHY 驱动
DEVICE_MAC_PHY_SZ18201bool;select DEVICE_MAC_PHYn编译 SZ18201 PHY 驱动(当前 EVB/SK 板选用)

Shell 调试选项(code/middleware/shell/Kconfig):

选项依赖默认值命令
MIDDLEWARE_SHELL_CMD_NET_INFOMIDDLEWARE_NET_LWIPynet_info
MIDDLEWARE_SHELL_CMD_PINGMIDDLEWARE_NET_LWIPyping
MIDDLEWARE_SHELL_CMD_IPERFMIDDLEWARE_NET_LWIPyiperf、iperf_duplex
MIDDLEWARE_SHELL_CMD_NET_CONFIGMIDDLEWARE_NET_LWIPynet_config
MIDDLEWARE_SHELL_CMD_MAC_PHYMIDDLEWARE_NET_ADAPTER_ETHymac_phy

说明:

  • 只打开 DRIVER_MAC 而不打开任一 PHY 驱动时,DEVICE_MAC_PHY 不会自动为真,Ethernet adapter 不可用。

  • MIDDLEWARE_NET_ADAPTER_ETH 会通过 select 自动打开 DRIVER_DTRNG 和 DRIVER_EFUSE,用于生成 MAC 地址;如果目标芯片配置缺少这两个驱动,需在配置阶段一并裁剪。

  • 当既未定义 CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_STATIC_IP 也未定义 CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_DHCP 时,im_net_eth.c 在编译期强制回退到静态 IP;这只是防御性兜底,不应依赖。

  • lwIP 内部参数(内存池、pbuf 池、TCP 窗口、MSS、TCP/IP 线程栈与优先级、hostname 等)不在 Kconfig 中暴露,硬编码在 code/middleware/net/lwip/include/lwipopts.h;修改这些参数需要直接修改该头文件或工程提供的覆盖版本。

  • 板级 Kconfig 不选择具体 PHY 型号。defconfig 中的 CONFIG_DEVICE_MAC_PHY_LAN8720A / CONFIG_DEVICE_MAC_PHY_SZ18201 必须与板级 board_mac.c 中调用的 lan8720a_device_get() / sz18201_device_get() 保持一致,否则会在链接阶段缺少符号。

  • 静态 IPv4 配置字符串必须是合法的点分十进制地址。当前实现对解析失败采取静默忽略,失败字段会变成 0.0.0.0,不会在启动时报告配置错误;请在 net_info 中确认实际地址。

1.2 文件职责

文件说明
code/middleware/net/include/im_net_eth_adapter.hMID 公开接口、im_net_eth_phy_config_t、事件回调、链路信息和 PHY 访问接口
code/middleware/net/include/im_net_common_adapter.h公共网络类型:接口类型、IP 模式、链路状态、事件位、IPv4/IPv6 信息、metric
code/middleware/net/include/im_net_common.h公共 lwIP 辅助接口:IPv4 解析/转换、IP 事件更新、默认 netif 更新、lwIP core 初始化
code/middleware/net/net_adapter/ethernet/im_net_eth.c适配器核心:配置生成、生命周期、worker 线程、TX/RX 路径、事件派发、查询接口
code/middleware/net/net_adapter/ethernet/im_net_eth_phy.cPHY 绑定:模板复制、MDIO 回调注入、地址扫描、PHY 复位/自协商/链路状态编排
code/middleware/net/net_adapter/ethernet/im_net_eth_internal.h适配器内部配置与运行上下文字段、PHY 绑定函数声明
code/middleware/net/common/im_net_common.c公共辅助实现(IP 事件、DNS、默认 netif、lwIP core 初始化)
code/include/devices/mac_phy/mac_phy.hPHY 抽象公共宏、类型、MDIO 总线和操作表契约
code/devices/mac_phy/lan8720a/LAN8720A PHY 驱动与 lan8720a_device_get()
code/devices/mac_phy/sz18201/SZ18201 PHY 驱动与 sz18201_device_get()
code/bsp/common/include/board_mac.h板级 board_mac_init() 契约
code/bsp/g32s10/<board>/board_mac.c板级 MAC 时钟、PHY 电源/复位、PHY 注册参考实现
code/middleware/net/example/eth/Ethernet 示例工程与 defconfig
code/middleware/shell/cmds/net/net_info、ping、iperf、net_config、mac_phy 调试命令
test/g32s10/module/gmac/GMAC 模块级测试(寄存器、中断、MTU、吞吐、压力等)

1.3 最小配置与 defconfig

启用 Ethernet MAC MID 的最小配置:

CONFIG_DRIVER_MAC=y
CONFIG_DEVICE_MAC_PHY_SZ18201=y
CONFIG_MIDDLEWARE_NET_LWIP=y
CONFIG_MIDDLEWARE_NET_ADAPTER=y
CONFIG_MIDDLEWARE_NET_ADAPTER_ETH=y
CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_STATIC_IP=y
CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_IPADDR="10.5.4.111"
CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_GWADDR="10.5.4.1"
CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_NETMASK="255.255.255.0"

如需 Shell 调试和链路诊断,再打开:

CONFIG_MIDDLEWARE_SHELL=y
CONFIG_MIDDLEWARE_SHELL_CONSOLE_IO=y
CONFIG_MIDDLEWARE_SHELL_CMD_NET_INFO=y
CONFIG_MIDDLEWARE_SHELL_CMD_PING=y
CONFIG_MIDDLEWARE_SHELL_CMD_IPERF=y
CONFIG_MIDDLEWARE_SHELL_CMD_MAC_PHY=y

可直接参考的 defconfig:

defconfig说明
code/middleware/net/example/eth/eth_example_defconfigEthernet 中间件示例;EVB + SZ18201 + 静态 IPv4
test/g32s10/module/gmac/g32s10_v1_gmac_function_defconfigGMAC 模块测试公共配置;FPGA IMAGE10 + LAN8720A + DHCP
test/g32s10/module/gmac/clock/g32s10_v1_gmac_clock_defconfigGMAC 时钟门控专项测试

构建组件关系:

  • CONFIG_MIDDLEWARE_NET_ADAPTER_ETH 打开时,CMake 注册 im_net_adapter 组件,源文件为 im_net_eth.c、im_net_eth_phy.c,依赖 im_net、im_net_lwip。

  • PHY 驱动分别注册为 dev_lan8720a、dev_sz18201 组件,每个组件只编译一个 .c 文件。

  • 板级组件在 CONFIG_MIDDLEWARE_NET_ADAPTER_ETH 打开时把 board_mac.c 加入源文件列表,并依赖 im_net。

2. MAC MID 资源模型与公开类型

2.1 单实例与静态资源

MID 是单实例设计:im_net_eth.c 内部只有一个 im_net_eth_t 上下文,所有公开接口都作用于它,不支持第二个 Ethernet MAC 网口。WiFi 使用独立的 im_net_wifi 适配器,不共享该上下文。

资源取值说明
TX 描述符数量256IM_NET_ETH_TX_DESC_COUNT,静态数组,按 64 字节对齐
RX 描述符数量256IM_NET_ETH_RX_DESC_COUNT,静态数组,按 64 字节对齐
单个 DMA 缓冲区大小1536 字节IM_NET_ETH_BUFFER_SIZE,每个 TX/RX 描述符槽位一个
DMA 突发长度8IM_NET_ETH_DMA_PBL,同时用于 TX/RX
MDC 时钟范围0x3IM_NET_ETH_PHY_MDC_CLOCK_RANGE,写入 HAL mdc_clock_range
worker 线程栈4096 字节IM_NET_ETH_WORK_THREAD_STACK_SIZE
worker 等待/链路轮询周期1000 msIM_NET_ETH_WORK_TIMEOUT_MS
IRQ 优先级1IM_NET_ETH_IRQ_PRIORITY,作用于 IRQ_GMAC
单次 RX 排空上限256 帧IM_NET_ETH_DRAIN_LIMIT,与 RX 描述符数量相同
TX HAL 超时0单次轮询,不做等待
RX HAL 超时0单次轮询,不做等待
默认 MAC 地址02:32:10:00:00:01EFUSE/DTRNG 都不可用时的兜底值
netif 名称en<num>前两个字符固定为 'e'、'n',编号由 lwIP 分配
netif metric0x10IM_NETIF_METRIC_ETHERNET

静态内存占用说明:

  • 描述符:256 × 16 × 2 = 8192 字节。

  • DMA 缓冲区:256 × 1536 × 2 = 786432 字节。

  • 两者合计约 776 KiB(794624 字节),全部位于静态数据区,不从 FreeRTOS heap 分配。

  • 每个 DMA 缓冲区槽位为 1536 字节(24 × 64),天然按 cache line 对齐。

堆内存占用:

  • 初始化时 MID 通过 malloc(rx_buffer_size) 申请一个 1536 字节 的 RX 落地缓冲区,用于接收 HAL 交出的帧,再复制到 pbuf。

  • 该缓冲区在 im_net_eth_deinit() 成功路径释放;init() 失败时在回滚路径释放。

内核对象:

  • 一个名为 "eth" 的 worker 线程(栈 4096 字节,优先级 OS_priority_high)。

  • 一个 thread_waiter(单等待者,IRQ → worker 唤醒)。

  • 一个 IRQ_GMAC 中断注册项(首次 start() 时申请,stop()/deinit() 时释放)。

2.2 硬件能力摘要

项目说明
MAC 实例单实例 GMAC;MID 不支持多 MAC
速率仅 10 Mbps / 100 Mbps;mac_phy_speed_t 没有 1000M 编码
双工半双工 / 全双工
PHY 接口Clause 22 MDIO,PHY 地址 0~31;0xFF 只作为自动扫描哨兵
MAC 地址6 字节;优先从 EFUSE CHIP_ID 派生,其次 DTRNG,最后使用默认值,并强制为本地管理单播地址
流控仅解析对称 pause;最终结果只可能是 NONE 或 RX_TX,且要求全双工
PHY 中断当前 MID 与两个 PHY 驱动都不使用 PHY 中断,链路靠轮询
MAC 中断IRQ_GMAC,软件 IRQ 号 11;由 MID 注册、设优先级 1 并使能
帧格式IEEE 802.3 Ethernet II;单帧必须完整落在一个描述符/缓冲区中(≤ 1536 字节,含 FCS 处理)
IPv6当前默认配置下 lwIP 以 IPv4-only 构建,IPv6 查询接口返回 IM_ERR_UNSUPPORTED

2.3 MID 公开宏与事件

宏/枚举取值说明
IM_NET_ETH_PHY_ADDR_AUTOMAC_PHY_ADDR_INVALID(0xFF)im_net_eth_phy_config_t.phy_addr 使用该值时,MID 在 0~31 范围内扫描 PHY
IM_NET_EVENT_NONE0U无事件
IM_NET_EVENT_LINK_UP1U << 0PHY 链路由 down 变 up
IM_NET_EVENT_LINK_DOWN1U << 1PHY 链路由 up 变 down
IM_NET_EVENT_GOT_IPV41U << 2netif 首次观察到有效 IPv4 地址
IM_NET_EVENT_LOST_IPV41U << 3netif IPv4 地址消失
IM_NET_EVENT_RX1U << 4worker 向 lwIP 成功投递了至少一个 RX 帧
IM_NET_EVENT_TX1U << 5GMAC 报告 TX 完成(worker 会回收描述符)
IM_NET_EVENT_ERROR1U << 6HAL、PHY、pbuf、netif input 或 DMA 异常
IM_NET_EVENT_GOT_IPV61U << 7netif 首次观察到有效 IPv6 地址(启用 IPv6 时)
IM_NET_EVENT_LOST_IPV61U << 8netif IPv6 地址全部失效(启用 IPv6 时)

事件是 32 位位图,不是队列:同一位在一次 worker 处理周期内只派发一次,多类事件可以在同一次回调中合并出现;回调未注册时事件直接丢弃。

2.4 公开类型

完整定义以公开头文件为准:im_net_eth_adapter.h、im_net_common_adapter.h、mac_phy.h。

2.4.1 im_net_eth_t

typedef struct im_net_eth im_net_eth_t;

im_net_eth_t 是 MID 的唯一适配器上下文,定义在内部头文件中,对应用是不透明类型。事件回调会收到该指针,可用于回调归属判断,但应用不得解引用其字段,也不得保存后在对象生命周期之外使用。

2.4.2 im_net_eth_phy_config_t

typedef struct {
    const mac_phy_device_t *phy_device;
    uint8_t phy_addr;
    uint32_t mdio_timeout_ms;
    uint16_t pause_time;
} im_net_eth_phy_config_t;
字段说明
phy_device板级选定的 PHY driver 模板指针;必须指向固件生存期有效的静态对象(例如 sz18201_device_get() 的返回值)
phy_addrPHY 地址 0~31;IM_NET_ETH_PHY_ADDR_AUTO 表示自动扫描
mdio_timeout_msMDIO 事务超时(毫秒);0 表示单次轮询/不等待。该值同时被 PHY 驱动的软件复位流程用作复位等待预算
pause_time流控启用时写入 MAC_FCR.PT 的 pause quantum;EVB 取 0x0200

2.4.3 im_net_eth_event_callback_t

typedef void (*im_net_eth_event_callback_t)(im_net_eth_t *eth,
                                            uint32_t events,
                                            void *user_data);

回调在以下上下文执行:Ethernet worker 线程、im_net_eth_start() 调用线程、im_net_eth_stop() 调用线程、im_net_eth_deinit() 调用线程。回调不得长时间阻塞,不得在回调中调用 im_net_eth_stop()/im_net_eth_deinit()/im_net_eth_start() 等生命周期接口,也不得调用任何 PHY/MDIO 接口。

2.4.4 im_net_eth_link_info_t

typedef struct {
    im_net_link_state_t state;
    bool link_up;
    bool autoneg_enabled;
    bool autoneg_complete;
} im_net_eth_link_info_t;
字段说明
state适配器状态,见 4.5
link_upPHY 缓存链路状态
autoneg_enabled / autoneg_completePHY 自协商状态

该结构返回的是 worker 最近一次采样并缓存的 PHY 状态,不触发新的 MDIO 事务,因此可能滞后最多约一个空闲轮询周期(约 1 秒)。

2.4.5 公共网络状态与事件类型

im_net_link_state_t:

typedef enum {
    IM_NET_LINK_STATE_RESET = 0,
    IM_NET_LINK_STATE_READY,
    IM_NET_LINK_STATE_STARTED,
    IM_NET_LINK_STATE_LINK_DOWN,
    IM_NET_LINK_STATE_LINK_UP,
    IM_NET_LINK_STATE_GOT_IP,
    IM_NET_LINK_STATE_ERROR,
} im_net_link_state_t;
值说明
RESET未初始化或已 deinit
READYHAL/lwIP 已初始化,MAC 数据流未启动(或已 stop)
STARTED内部过渡状态,start() 赋值为该状态后立即被状态重算覆盖,应用几乎观察不到
LINK_DOWNnetif 已 up,但 PHY 链路 down
LINK_UPnetif 与 PHY 链路均 up,但尚未获得有效 IPv4 地址
GOT_IPnetif 与 PHY 链路均 up,且已获得有效 IPv4 地址(地址、掩码、网关均非 0 且掩码合法)
ERROR最近一次运行期失败,需 stop() 恢复或 deinit() 结束

im_net_event_t 见 4.3。

2.4.6 IPv4 / IPv6 信息类型

typedef struct {
    im_netif_ip_mode_t ip_mode;
    uint32_t addr;
    uint32_t netmask;
    uint32_t gateway;
    uint32_t dns1;
    uint32_t dns2;
} im_net_ipv4_addr_t;
  • 地址字段为主机字节序。

  • dns1/dns2 返回的是配置值(来自 Kconfig),不是 DHCP 或 DNS 客户端实际使用的服务器列表。

typedef struct {
    uint8_t addr[IM_NET_IPV6_ADDR_SIZE];
    uint8_t index;
    im_net_ipv6_addr_state_t state;
} im_net_ipv6_addr_t;
  • addr 为 16 字节网络序地址。

  • index 是底层 netif 的 IPv6 地址槽位号。

  • state 取值见 im_net_ipv6_addr_state_t:INVALID/TENTATIVE/VALID/PREFERRED/DEPRECATED/DUPLICATED。

2.4.7 PHY 抽象类型

mac_phy_mdio_bus_t:

typedef struct mac_phy_mdio_bus {
    void *user_data;
    uint32_t timeout_ms;
    error_code_t (*read)(struct mac_phy_mdio_bus *mdio,
                         uint8_t phy_addr,
                         uint8_t reg_addr,
                         uint16_t *data_out);
    error_code_t (*write)(struct mac_phy_mdio_bus *mdio,
                          uint8_t phy_addr,
                          uint8_t reg_addr,
                          uint16_t data);
} mac_phy_mdio_bus_t;
  • read/write 的调用方必须保证 mdio、data_out 非空,phy_addr/reg_addr 在 0~31。

  • 回调可能轮询或阻塞,只能在任务/线程上下文调用,禁止在中断、临界区或不可阻塞路径中调用。

  • timeout_ms == 0 表示单次轮询/不等待。

mac_phy_ops_t:

操作契约
probe(device)判断当前 phy_addr 是否匹配该驱动;匹配返回 IM_OK,不匹配返回 IM_ERR_UNSUPPORTED
read_id(device, id_out)读取 PHYID1/PHYID2 原始值
reset(device)软件复位 PHY 并等待完成;超时返回 IM_ERR_TIMEOUT,no-wait 仍未完成返回 IM_ERR_BUSY,时间源未初始化返回 IM_ERR_NOT_READY
set_autoneg(device, config)写自协商广告并重启自协商,不等待完成
set_config(device, config)关闭自协商并强制 speed/duplex;当前 MID 不调用该操作
get_link_state(device, state_out)读取并解码当前链路状态

mac_phy_device_t 是 PHY 运行时对象,包含 name、ops、mdio 和 phy_addr。板级只持有驱动提供的静态模板,MID 在初始化时把模板按值复制到适配器上下文,并注入 mdio.user_data、mdio.timeout_ms、mdio.read、mdio.write 与 phy_addr。

mac_phy_link_state_t 的 speed/duplex/flow_control 只在 link_up == true 时有效;link down 时是占位值,调用方不得用于配置 MAC。

2.5 适配器状态模型

对外可见状态由 im_net_eth_state_update() 按下列优先级计算:

netif 尚未加入 lwIP            -> RESET
netif 未 up                    -> READY
netif up 但链路 down           -> LINK_DOWN
netif up、链路 up、无有效 IPv4 -> LINK_UP
netif up、链路 up、有有效 IPv4 -> GOT_IP
运行期错误路径显式设置         -> ERROR

状态迁移:

当前状态操作/事件目标状态
RESETim_net_eth_init() 成功READY
RESETim_net_eth_init() 失败ERROR
READYim_net_eth_start() 成功LINK_DOWN / LINK_UP / GOT_IP(由链路和 IP 决定)
READY / LINK_* / GOT_IPim_net_eth_stop() 成功READY
READY / LINK_* / GOT_IP运行期错误ERROR
ERRORim_net_eth_stop() 成功READY
任意状态im_net_eth_deinit() 成功RESET

要点:

  • ERROR 是粘滞状态:im_net_eth_start() 在 ERROR 下返回 IM_ERR_NOT_READY,必须先 im_net_eth_stop()。

  • LINK_UP 与 GOT_IP 由 worker 周期刷新,不由应用设置。

  • IM_NET_LINK_STATE_STARTED 只是内部过渡值,不应作为外部判断依据。

2.6 对象与资源所有权

  • 适配器上下文归 MID 所有,静态分配,应用不能创建第二个实例。

  • TX/RX 描述符和 DMA 缓冲区是 MID 静态数组,通过 HAL 配置交给 MAC HAL;生命周期与固件一致。

  • RX 落地缓冲区由 MID 在 init() 中 malloc,在 deinit() 或 init() 失败回滚中释放。

  • PHY 模板归 PHY 驱动所有,必须静态生存;MID 只复制 im_net_eth_phy_config_t,并在初始化时按值复制模板到自己的上下文。板级传入的栈上配置结构体在本函数返回后即可失效。

  • PHY 运行时对象归 MID 所有,mdio 回调和 phy_addr 由 MID 注入,应用不得直接操作。

  • netif 内嵌在 MID 上下文中,由 MID 添加/移除;应用通过 lwIP 标准接口(socket/netconn)使用。

  • 事件回调归应用所有;回调函数与 user_data 必须保持有效,直到注销或固件结束。

  • 板级资源(时钟、电源、复位、pinmux)归板级 BSP;board_mac_init() 必须在 MID 初始化前完成。

2.7 全生命周期

下图描述板级、MID、PHY 与 lwIP 的完整生命周期。im_net_eth_* 为公开接口;link_state_process、rx_process、tx_process、irq_handler 为 MID 内部流程。

板级与应用输入

NODE  board_pinmux: RMII / MDC / MDIO 引脚
NODE  board_mac_init(): CPM 25 MHz  PHY 电源与复位
NODE  im_net_eth_register_phy():  PHY 模板 + 地址 + MDIO 超时
+ pause_time + flow_control
NODE  可选 im_net_eth_register_callback()  仅 init 之后

MID 生命周期

NODE  RESET  未初始化,无 HAL/lwIP 资源
NODE  注册 PHY 配置  只保存配置,不访问硬件
NODE  im_net_eth_init()  生成 MAC 地址;HAL init;
PHY 扫描/probe/reset/autoneg;
lwIP tcpip + netif + metric
NODE  READY  HAL、netif、metric 就绪;
MAC 数据流未启动
NODE  im_net_eth_start()  先 netif up;采样 PHY 并配置 MAC;
DHCP/静态 IP;注册 IRQ;创建 worker
NODE  LINK_DOWN / LINK_UP / GOT_IP  数据面运行;worker 处理 TX/RX/事件
NODE  ERROR  运行期失败;start 被拒绝
NODE  im_net_eth_stop()  停 worker;释放 IRQ;停 DHCP;
netif down;停止 MAC
NODE  im_net_eth_deinit()  stop;移除 netif;HAL deinit;
释放 RX 缓冲区

PHY 与链路

NODE  PHY driver 模板  static const mac_phy_device_t
NODE  MDIO 回调注入
NODE  扫描 0..31 或固定地址  read_id + probe
NODE  reset -> set_autoneg  默认 10/100 全半双工广告
NODE  get_link_state  BMSR 双读 + 特殊状态寄存器
NODE

数据面与事件

NODE  GMAC IRQ 11
NODE  pending_events  IRQ 置位 + 唤醒 worker
NODE  worker: link / TX reclaim / RX drain
NODE  netif.input(pbuf)  etharp_output / ethip6_output
NODE  事件合并后 dispatch  LINK/ IP / RX / TX / ERROR

board_pinmux: RMII / MDC / MDIO 引脚 → board_mac_init(): CPM 25 MHz

im_net_eth_register_phy(): → 注册 PHY 配置

可选 im_net_eth_register_callback() → READY

RESET → 注册 PHY 配置

im_net_eth_init() → READY

im_net_eth_init() → ERROR · 失败

READY → im_net_eth_start()

im_net_eth_start() → READY · 失败回滚

im_net_eth_start() → LINK_DOWN / LINK_UP / GOT_IP

LINK_DOWN / LINK_UP / GOT_IP → GMAC IRQ 11

GMAC IRQ 11 → pending_events

worker: link / TX reclaim / RX drain → netif.input(pbuf)

worker: link / TX reclaim / RX drain → 事件合并后 dispatch

事件合并后 dispatch → LINK_DOWN / LINK_UP / GOT_IP

LINK_DOWN / LINK_UP / GOT_IP → ERROR · 运行期错误

ERROR → im_net_eth_stop()

LINK_DOWN / LINK_UP / GOT_IP → im_net_eth_stop()

READY → im_net_eth_stop()

im_net_eth_stop() → READY

READY → im_net_eth_deinit()

ERROR → im_net_eth_deinit()

LINK_DOWN / LINK_UP / GOT_IP → im_net_eth_deinit()

im_net_eth_deinit() → RESET

PHY driver 模板 → MDIO 回调注入

扫描 0..31 或固定地址 → reset -> set_autoneg

im_net_eth_init() → MDIO 回调注入

im_net_eth_init() → 扫描 0..31 或固定地址

im_net_eth_init() → reset -> set_autoneg

worker: link / TX reclaim / RX drain → get_link_state

阅读约定:

  • 注册 PHY 只保存配置,不访问硬件;真正的 PHY 初始化和 MDIO 访问发生在 im_net_eth_init() 内部。

  • im_net_eth_start() 在未初始化时会自动调用 init();start() 失败会回滚到 READY(回滚中也派发 ERROR 事件)。

  • 数据面只在 RUN 状态工作;ERROR 状态下 IRQ 可能仍在产生,但 start() 会被拒绝,需先 stop()。

  • im_net_eth_deinit() 成功后回到 RESET,但 PHY 注册配置仍保留(无需重新 register_phy,但需要重新注册事件回调)。

  • link_state_process 只在 worker 空闲轮询时执行,链路状态与 GOT_IP 状态因此最多滞后约一个轮询周期。

3. 接口规范

本章逐个说明 MID 公开接口。除特别说明外,所有接口都:

  • 操作唯一的静态适配器实例,没有实例句柄参数。

  • 只能在线程/任务上下文调用,禁止在中断或临界区中调用。

  • 没有内部互斥锁,需要由调用方串行化对同一适配器的并发访问。

  • 依赖 CONFIG_SDK_PARAM_CHECK(当前工程配置为打开)执行空指针与取值范围检查;关闭该配置时相应检查消失。

接口能力概览:

接口前置条件访问硬件典型上下文
im_net_eth_register_phy()尚未完成 init()否线程
im_net_eth_register_callback()已完成 init()否线程
im_net_eth_init()已注册 PHY是线程
im_net_eth_start()可自动 init()是线程
im_net_eth_stop()无(未初始化时直接成功)是线程
im_net_eth_deinit()无是线程
im_net_eth_link_state_get()已完成 init()否(读缓存)任意可读上下文
im_net_eth_mac_addr_get()已完成 init()否任意可读上下文
im_net_eth_ip_get()已完成 init()否任意可读上下文
im_net_eth_ipv6_addr_get()已完成 init() 且启用 IPv6否任意可读上下文
im_net_eth_phy_addr_get()已完成 init()否任意可读上下文
im_net_eth_phy_read() / phy_write()已完成 init() 与 PHY 初始化是(MDIO)线程

3.1 事件回调注册

3.1.1 im_net_eth_register_callback

error_code_t im_net_eth_register_callback(im_net_eth_event_callback_t callback,
                                          void *user_data);

功能说明:

注册或注销 Ethernet 事件回调。事件包括链路变化、IPv4/IPv6 地址获得/丢失、RX/TX 和错误。

参数表:

参数类型方向说明
callbackim_net_eth_event_callback_t输入回调函数;传 NULL 表示注销
user_datavoid *输入原样传给回调的应用上下文

返回值表:

返回值说明
IM_OK回调已设置或已注销
IM_ERR_NOT_READY适配器尚未完成 init()

补充说明:

  • 与 im_net_eth_register_phy() 相反,本接口必须在 init 之后调用;im_net_eth_start() 内部会自动 init,因此在首次 start 前调用本接口会返回 IM_ERR_NOT_READY。典型顺序是 init() → register_callback() → start()。

  • 可以重复调用覆盖旧回调和 user_data;callback = NULL 时 user_data 也一并保存但不会被使用。

  • im_net_eth_deinit() 之后适配器不再派发事件;下一次 im_net_eth_init() 会清零适配器上下文并清除已注册的回调,因此重新初始化后需要重新注册事件回调。

  • 事件不是队列:回调未注册期间产生的事件会被丢弃。

3.2 状态与信息查询

3.2.1 im_net_eth_link_state_get

error_code_t im_net_eth_link_state_get(im_net_eth_link_info_t *info_out);

功能说明:

读取适配器状态与最近一次缓存的 PHY 链路信息,不触发新的 MDIO 事务。

参数表:

参数类型方向说明
info_outim_net_eth_link_info_t *输出链路信息输出

返回值表:

返回值说明
IM_OK已填充
IM_ERR_INVALID_PARAMinfo_out 为空
IM_ERR_NOT_READY适配器尚未完成 init()

补充说明:

  • link down 时 speed/duplex/flow_control 分别返回 UNKNOWN/UNKNOWN/NONE。

  • 缓存更新来自 worker 的空闲轮询(约 1 秒一次)以及 start() 中的首次采样,因此信息可能滞后约一个轮询周期。

  • 只读、不访问硬件,不构成跨线程同步屏障。

3.2.2 im_net_eth_mac_addr_get

error_code_t im_net_eth_mac_addr_get(uint8_t *addr_out, uint32_t addr_size);

功能说明:

读取 init() 时生成并写入 netif 的 MAC 地址。

参数表:

参数类型方向说明
addr_outuint8_t *输出MAC 地址输出缓冲区
addr_sizeuint32_t输入输出缓冲区字节数,必须 ≥ 6

返回值表:

返回值说明
IM_OK已复制 6 字节
IM_ERR_INVALID_PARAMaddr_out 为空或 addr_size < 6
IM_ERR_NOT_READY适配器尚未完成 init()

补充说明:只写 6 字节,不修改 addr_out[6..addr_size-1];返回网络字节序地址。

3.2.3 im_net_eth_ip_get

error_code_t im_net_eth_ip_get(im_net_ipv4_addr_t *info_out);

功能说明:

读取当前 IPv4 配置和 netif 上的地址信息。

参数表:

参数类型方向说明
info_outim_net_ipv4_addr_t *输出IPv4 信息输出

返回值表:

返回值说明
IM_OK已填充
IM_ERR_INVALID_PARAMinfo_out 为空
IM_ERR_NOT_READY适配器尚未完成 init()

补充说明:

  • 地址、掩码、网关来自 netif,主机字节序;未获取到地址时为 0。

  • ip_mode 来自适配器配置(静态或 DHCP)。

  • dns1/dns2 返回配置值(Kconfig),不是 DNS 客户端当前实际使用的服务器列表。

3.2.4 im_net_eth_ipv6_addr_get

error_code_t im_net_eth_ipv6_addr_get(im_net_ipv6_addr_t *addr_out,
                                      uint32_t addr_count,
                                      uint32_t *actual_count_out);

功能说明:

读取 netif 上所有状态非 INVALID 的 IPv6 地址。

参数表:

参数类型方向说明
addr_outim_net_ipv6_addr_t *输出地址数组
addr_countuint32_t输入数组容量,必须 > 0
actual_count_outuint32_t *输出实际写入的地址数量

返回值表:

返回值说明
IM_OK已填充;*actual_count_out 为实际数量(可能为 0)
IM_ERR_INVALID_PARAM启用 IPv6 时:任一指针为空或 addr_count == 0
IM_ERR_NOT_READY启用 IPv6 时:适配器尚未完成 init()
IM_ERR_UNSUPPORTED当前 lwIP 以 IPv4-only 构建(LWIP_IPV6 == 0);此路径不校验参数

补充说明:

  • 当前默认配置下 LWIP_IPV6 == 0,本接口恒返回 IM_ERR_UNSUPPORTED。

  • 启用 IPv6 时,地址按 netif 槽位顺序复制,最多 addr_count 条;index 为槽位号,state 为 lwIP 地址状态映射值。

3.2.5 im_net_eth_phy_addr_get

error_code_t im_net_eth_phy_addr_get(uint8_t *addr_out);

功能说明:

读取初始化时确定并回写到配置中的 PHY 地址(自动扫描模式下是扫描结果)。

参数表:

参数类型方向说明
addr_outuint8_t *输出PHY 地址输出

返回值表:

返回值说明
IM_OK已填充
IM_ERR_INVALID_PARAMaddr_out 为空,或已初始化但配置中的 PHY 地址大于 31
IM_ERR_NOT_READY适配器尚未完成 init()

3.3 PHY 访问与诊断

3.3.1 im_net_eth_phy_read

error_code_t im_net_eth_phy_read(uint8_t reg_addr, uint16_t *data_out);

功能说明:

通过 MID 绑定的 MDIO 总线读取当前 PHY 的寄存器。

参数表:

参数类型方向说明
reg_addruint8_t输入PHY 寄存器地址 0~31
data_outuint16_t *输出寄存器值输出

返回值表:

返回值说明
IM_OK读取成功
IM_ERR_INVALID_PARAMdata_out 为空;PHY 未初始化;PHY 地址非法;reg_addr > 31
IM_ERR_NOT_READY适配器尚未完成 init()
IM_ERR_BUSYMDIO 总线正忙(例如与 worker 的链路轮询并发)
IM_ERR_TIMEOUTMDIO 事务超时,或系统时基未初始化且超时值非 0

补充说明:

  • 本接口直接调用 HAL MDIO,不经过 PHY 驱动;可在不初始化 PHY 驱动语义的前提下做寄存器级诊断。

  • 必须在任务上下文调用;可能在 mdio_timeout_ms 内轮询阻塞。

  • MID 没有为 MDIO 访问提供锁;与 worker 的链路轮询或另一线程并发调用时,可能返回 IM_ERR_BUSY,调用方应自行串行化或重试。

  • 写后读、恢复寄存器等序列由调用方自行保证。

3.3.2 im_net_eth_phy_write

error_code_t im_net_eth_phy_write(uint8_t reg_addr, uint16_t data);

功能说明:

通过 MID 绑定的 MDIO 总线写当前 PHY 的寄存器。

参数表:

参数类型方向说明
reg_addruint8_t输入PHY 寄存器地址 0~31
datauint16_t输入写入值

返回值表:与 im_net_eth_phy_read() 相同(无 data_out 空指针检查)。

补充说明:写寄存器可能破坏 PHY 驱动维护的自协商/链路状态,只建议在调试和恢复流程中使用;诊断结束后应重新复位 PHY 或重新 init()。

3.4 板级 PHY 注册

3.4.1 im_net_eth_register_phy

error_code_t im_net_eth_register_phy(const im_net_eth_phy_config_t *config);

功能说明:

注册板级选定的 PHY 模板、PHY 地址策略、MDIO 超时、pause time 和流控策略。MID 只复制该配置,不访问硬件、不申请资源。必须在 im_net_eth_init()(或会自动调用 init 的 im_net_eth_start())之前调用。

参数表:

参数 类型 方向 说明
config const im_net_eth_phy_config_t * 输入 板级 PHY 配置;函数返回后调用方即可释放该结构体,但 config->phy_device 指向的模板必须永久有效

返回值表:

返回值 说明
IM_OK 注册成功;配置已按值复制
IM_ERR_INVALID_PARAM config 为空;phy_device 为空;phy_addr 既不是 IM_NET_ETH_PHY_ADDR_AUTO 又大于 31;flow_control 含 HAL_MAC_FLOW_CONTROL_RX_TX 之外的位;或 PHY 操作表缺少 probe/read_id/reset/set_autoneg/get_link_state 之一
IM_ERR_BUSY 适配器已完成初始化;不能在 init() 之后重新注册

补充说明:

  • 成功注册后适配器会记录 phy_registered 标志;该标志在 deinit() 中不会被清除,因此 deinit 后重新 init 无需再次注册。
  • im_net_eth_init() 失败后 all_initialized 仍为 false,可以重新注册 PHY 配置再重试。
  • 注册本身不校验 mdio_timeout_ms 和 pause_time;mdio_timeout_ms = 0 是合法值(单次轮询/不等待)。
  • phy_device 必须来自 PHY 驱动的静态模板获取接口(如 sz18201_device_get()、lan8720a_device_get()),不能指向栈上或动态分配的结构体。
  • 同一适配器可以重复调用本接口覆盖配置,只要尚未完成初始化。

3.5 初始化与启停

3.5.1 im_net_eth_init

error_code_t im_net_eth_init(void);

功能说明:

初始化 Ethernet MID:生成/选择 MAC 地址、初始化 MAC HAL、扫描或绑定 PHY、复位并配置 PHY 自协商、初始化 lwIP 核心并添加 netif、注册 metric 和默认 netif。该接口不启动 MAC 数据流,不注册 IRQ,不创建 worker 线程。

参数表:

无参数。

返回值表:

返回值 说明
IM_OK 初始化成功,适配器进入 READY;已初始化时立即返回 IM_OK
IM_ERR_NOT_READY 未注册 PHY;或 lwIP tcpip 初始化失败;或 netif 添加失败;或 IPv6 link-local 初始化失败
IM_ERR_BUSY RX 落地缓冲区 malloc 失败,或 metric 注册失败
IM_ERR_TIMEOUT lwIP tcpip 线程初始化 5 秒超时
IM_ERR_NO_MEMORY lwIP 初始化等待器创建失败
其他 HAL/PHY 错误码 HAL handle/init 失败、PHY 扫描/probe/reset/autoneg 失败等原样返回

补充说明:

  • 幂等:all_initialized 已为真时立即返回 IM_OK,不重复初始化。
  • 前置条件:必须已通过 im_net_eth_register_phy() 注册 PHY;未注册时打印错误日志、把状态置为 ERROR 并返回 IM_ERR_NOT_READY。
  • init() 会清零整个适配器上下文,包括之前注册的事件回调;重新 init 后需要重新调用 im_net_eth_register_callback()。
  • 初始化失败时 MID 会回滚已申请的 netif、HAL 和 RX 缓冲区,状态置为 ERROR;all_initialized 保持 false,可以修正原因后重试 init()。
  • init() 生成的 MAC 地址来自 EFUSE CHIP_ID → DTRNG → 默认值的回退链;EFUSE 无有效 CHIP_ID 时每次 init 可能得到不同的随机 MAC。
  • 初始化内部顺序:HAL handle/init → PHY 模板复制与 MDIO 回调注入 → 地址扫描或固定地址 probe → PHY 复位 → 默认自协商广告 → 首次链路采样 → lwIP core → netif 添加 → IPv6 link-local(若启用)→ metric 与默认 netif。
  • 建议在 sys_time_init()(或等价时基初始化)之后调用;当 mdio_timeout_ms != 0 时,PHY 软件复位与 MDIO 事务依赖系统时基,时基未初始化会返回 IM_ERR_NOT_READY(PHY 复位)或 IM_ERR_TIMEOUT(MDIO)。

3.5.2 im_net_eth_start

error_code_t im_net_eth_start(void);

功能说明:

启动 Ethernet 数据面:启动 MAC RX/TX 与 DMA、把 netif 置 up、采样链路并配置 MAC、按 IP 模式启动 DHCP 或使用静态 IPv4、注册并使能 IRQ_GMAC、创建 Ethernet worker 线程。

参数表:

无参数。

返回值表:

返回值 说明
IM_OK 数据面已启动;或此前已经处于启动状态
IM_ERR_NOT_READY init() 失败(含未注册 PHY);当前状态不是 READY(例如 ERROR);netif up 或 DHCP 启动失败
IM_ERR_BUSY worker 线程创建失败
其他 IRQ/PLIC 错误码 IRQ_GMAC 申请、优先级设置或使能失败时返回底层错误码
其他 HAL/PHY 错误码 hal_mac_start() 或首次链路配置失败等原样返回

补充说明:

  • 若尚未初始化,start() 会先自动调用 init(),因此未注册 PHY 时错误由 init() 返回。
  • 幂等:已经处于 STARTED/LINK_DOWN/LINK_UP/GOT_IP 时立即返回 IM_OK,不会重复创建线程或 IRQ。
  • ERROR 状态下不会尝试恢复,必须先 stop()(stop() 成功会把状态恢复为 READY),再重新 start()。
  • 启动过程中会主动采样一次 PHY 链路状态;若自协商尚未完成或链路 down,本次启动仍会成功,链路状态由后续 worker 周期采样更新。
  • 失败回滚:MID 先派发一次 IM_NET_EVENT_ERROR,再执行 stop 流程(会额外派发 LINK_DOWN 和 LOST_IPV4);回滚中的 hal_mac_stop() 成功时回到 READY,失败时保持 ERROR。函数返回原始错误码,READY 下可以重试 start()。
  • 副作用:使能 IRQ_GMAC(优先级 1),创建名为 "eth"、栈 4096 字节、优先级 OS_priority_high 的 worker 线程,并立即唤醒一次。

3.5.3 im_net_eth_stop

error_code_t im_net_eth_stop(void);

功能说明:

停止 Ethernet 数据面并恢复为 READY:停止 worker 线程、禁用并释放 IRQ、停止 DHCP、把 netif link 和 netif 置 down、停止 MAC RX/TX/DMA。

参数表:

无参数。

返回值表:

返回值 说明
IM_OK 已停止;未初始化或本已处于 READY 时也返回 IM_OK
其他 HAL 错误码 hal_mac_stop() 失败;状态置为 ERROR 并派发 IM_NET_EVENT_ERROR

补充说明:

  • 幂等:未初始化、或状态已经是 READY 时立即返回成功,不访问硬件、不派发事件。
  • 在 ERROR 状态下调用本接口是正式恢复手段;成功后会清除运行期错误并回到 READY。
  • 停止成功会派发 LINK_DOWN、LOST_IPV4,若停止前存在有效 IPv6 地址还会派发 LOST_IPV6。
  • stop() 不释放 RX 落地缓冲区、不反初始化 HAL、不移除 netif;这些由 deinit() 完成。
  • stop() 之后再 start() 会重新初始化 DHCP/IRQ/worker,但不会重新初始化 HAL 和 PHY。

3.5.4 im_net_eth_deinit

error_code_t im_net_eth_deinit(void);

功能说明:

结束 MID 生命周期:先按 stop() 语义停止数据面,再移除 lwIP netif、反初始化 MAC HAL、释放 RX 落地缓冲区并将状态置回 RESET。

参数表:

无参数。

返回值表:

返回值 说明
IM_OK 已释放;未初始化时也返回 IM_OK
im_net_eth_stop() 的错误 stop() 失败时立即返回,后续 netif/HAL 资源不会释放
HAL 反初始化错误 hal_mac_deinit() 失败时返回该错误并派发 IM_NET_EVENT_ERROR

补充说明:

  • 幂等:未初始化时立即返回 IM_OK。
  • 只要 init() 曾成功返回,应用就应在退出前调用 deinit();中途 start()/stop() 失败不改变这一要求。
  • deinit() 不会清除 PHY 注册配置,因此再次初始化不需要重新 register_phy();但再次 init() 会清零上下文并清除事件回调,需要重新注册。
  • 已知限制:若 stop() 返回错误,deinit() 直接返回且不释放资源;若 hal_mac_deinit() 失败,netif 和 RX 缓冲区已经释放但 all_initialized 仍为 true,此时不应直接再次 start(),应视为需要复位的异常状态。

4. 行为约束与实现说明

4.1 初始化顺序与幂等性

推荐的初始化顺序:

  1. 板级 pinmux:完成 RMII、MDC、MDIO、PHY 电源/复位引脚配置。

  2. board_mac_init():使能 MAC 时钟、释放 MAC 软复位、给 PHY 上电并复位、调用 im_net_eth_register_phy()。

  3. 时基初始化(im_systick_init() 或等价接口):PHY 软复位和 MDIO 超时依赖系统时基。

  4. im_net_eth_init()(可选):提前完成 HAL/PHY/lwIP 初始化。

  5. im_net_eth_register_callback()(可选):注册事件回调。

  6. im_net_eth_start():启动数据面。

  7. 退出前 im_net_eth_stop()、im_net_eth_deinit()。

幂等性汇总:

操作未初始化时已初始化/已启动时
register_phy()可重复注册,后注册覆盖先注册返回 IM_ERR_BUSY
register_callback()返回 IM_ERR_NOT_READY可重复注册,覆盖旧值
init()执行初始化立即返回 IM_OK
start()自动先 init已启动则立即返回 IM_OK;ERROR 则返回 IM_ERR_NOT_READY
stop()立即返回 IM_OKREADY 时立即返回 IM_OK;其它状态执行停止
deinit()立即返回 IM_OK执行停止+释放

失败语义:

  • init() 失败会自动回滚并进入 ERROR,不会留下半初始化资源;可以再次 init()。

  • start() 失败会回滚到 READY,但会派发两轮事件。

  • stop() 失败会把状态置为 ERROR 并派发错误事件。

  • deinit() 在 stop() 失败时直接返回错误,不释放后续资源。

4.2 并发与上下文

  • MID 不提供全局锁;下列状态可能被多个上下文访问:

    • pending_events:IRQ 写、worker 读清,已用短临界区保护。

    • link_state:IRQ 错误路径和 worker/线程路径都会写,未加锁。

    • HAL handle、PHY 缓存、初始化状态位:无锁。

  • 调用方应保证同一时刻只有一个线程执行生命周期接口(init/start/stop/deinit)和 PHY 访问接口;不要在事件回调中调用这些接口。

  • im_net_eth_phy_read()/im_net_eth_phy_write() 与 worker 的链路轮询可能并发访问 MDIO,冲突时可能返回 IM_ERR_BUSY;需要可靠诊断序列时先 stop(),或在应用层加互斥。

  • CONFIG_SDK_PARAM_CHECK 关闭时,所有空指针/参数检查消失;生产工程建议保持开启。

  • 日志等级:链路 up 为 INFO、链路 down 为 WARN、初始化/PHY/MDIO 失败为 ERROR;TX 失败细节为 DEBUG,在默认日志级别下不输出。

4.3 已知限制与注意事项

  1. 单实例:只支持一个 Ethernet MAC 网口,所有接口没有实例参数。

  2. 只支持 10/100 Mbps:PHY 抽象和 MID 都不支持 1000M;SZ18201 的 1000M 编码被视为无效。

  3. 单帧单描述符:不支持跨描述符分段,单帧上限 1536 字节;超过或分段帧会被丢弃并可能上报错误。

  4. TX 无排队、无重试:TX ring 满时 linkoutput 返回 ERR_IF,由 lwIP 上层决定是否丢弃或重传。

  5. RX 每轮排空上限 256 帧:没有额外背压,超出部分依赖后续中断/轮询继续处理。

  6. 链路只在 worker 空闲时轮询:MDIO 事务会干扰该板的 RMII 接收通路,每次轮询约丢一帧;因此链路状态最多滞后约 1 秒,PHY 寄存器诊断与链路轮询并发时可能返回 IM_ERR_BUSY。

  7. 流控仅对称:两个 PHY 驱动都只解析对称 pause,结果只可能是 NONE 或 RX_TX,非对称广告无法在链路上解析回来。

  8. 无 PHY 中断:链路变化完全依赖轮询,PHY 事件类寄存器未被使用。

  9. 无内部锁:生命周期接口、PHY 访问和 worker 之间需要应用自行串行化;ISR 会写 link_state,与 worker 存在理论竞态。

  10. 事件不是队列:未注册回调或回调未及时处理的事件会丢失;一次回调可能同时携带多个事件位。

  11. hostname 当前不生效:MID 配置了 "eth" 主机名,但当前 lwIP 配置未启用 LWIP_NETIF_HOSTNAME,netif->hostname 不会被赋值。

  12. IPv6 当前默认不可用:当前默认配置未打开 CONFIG_MIDDLEWARE_NET_LWIP_IPV6,lwIP 以 IPv4-only 构建,im_net_eth_ipv6_addr_get() 返回 IM_ERR_UNSUPPORTED,GOT_IPV6/LOST_IPV6 事件不会产生。

  13. MAC 地址可能每次 init 变化:EFUSE 无有效 CHIP_ID 时回退到 DTRNG;只有 EFUSE 有效时同一芯片的 MAC 才稳定。

  14. deinit() 失败分支状态不一致:HAL 反初始化失败时 netif 与 RX 缓冲区已释放,但 all_initialized 仍为 true;此时不应直接 start()。

  15. 静态 RAM 占用约 776 KiB:描述符和 DMA 缓冲区全部静态分配,对内存紧张的工程需要评估。

  16. 不暴露 HAL 统计:MID 没有 MAC 收发计数、错误计数接口;需要统计时直接使用 HAL API 或外围系统监控。

  17. mdio_timeout_ms 语义双重:既用于单次 MDIO 事务超时,也用于 PHY 软件复位等待预算;调整该值会同时影响两者。

  18. 参数检查依赖配置:IM_PARAM_CHECK 在 CONFIG_SDK_PARAM_CHECK 关闭时不生效。

5. 典型用法

5.1 最小启动

板级已实现 board_mac_init() 时,应用只需两步:

#include "board_mac.h"
#include "im_error.h"
#include "im_log.h"
#include "im_net_eth_adapter.h"

error_code_t app_eth_start(void)
{
    error_code_t ret;

    ret = board_mac_init();
    if (ret != IM_OK) {
        return ret;
    }

    ret = im_net_eth_start();
    if (ret != IM_OK) {
        return ret;
    }

    return IM_OK;
}

board_mac_init() 负责板级时钟、PHY 电源/复位和 PHY 注册;im_net_eth_start() 在未初始化时自动调用 init()。工程中可参考 code/middleware/net/example/eth/main/main.c。

5.2 事件回调与状态查询

#include "im_net_eth_adapter.h"

static void app_eth_event(im_net_eth_t *eth, uint32_t events, void *user_data)
{
    (void)eth;
    (void)user_data;

    if ((events & IM_NET_EVENT_LINK_UP) != 0U) {
        /* 链路 up:可触发应用层重连、重新开始业务。 */
    }
    if ((events & IM_NET_EVENT_LINK_DOWN) != 0U) {
        /* 链路 down。 */
    }
    if ((events & IM_NET_EVENT_GOT_IPV4) != 0U) {
        /* 已获得 IPv4 地址。 */
    }
    if ((events & IM_NET_EVENT_LOST_IPV4) != 0U) {
        /* IPv4 地址丢失。 */
    }
    if ((events & IM_NET_EVENT_ERROR) != 0U) {
        /* 记录错误;不要在此回调内调用 stop/start/deinit。 */
    }
}

error_code_t app_eth_bringup(void)
{
    error_code_t ret;
    im_net_eth_link_info_t link;
    im_net_ipv4_addr_t ip;

    ret = im_net_eth_init();
    if (ret != IM_OK) {
        return ret;
    }

    ret = im_net_eth_register_callback(app_eth_event, NULL);
    if (ret != IM_OK) {
        return ret;
    }

    ret = im_net_eth_start();
    if (ret != IM_OK) {
        return ret;
    }

    (void)im_net_eth_link_state_get(&link);
    (void)im_net_eth_ip_get(&ip);
    return IM_OK;
}

5.3 DHCP 模式

把 Kconfig 的 IP 模式改为 DHCP:

CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_DHCP=y
# CONFIG_MIDDLEWARE_NET_ADAPTER_ETH_STATIC_IP is not set

应用代码不变:im_net_eth_start() 在 netif up 后调用 netifapi_dhcp_start()。地址获取成功时 worker 会产生 GOT_IPV4 事件,im_net_eth_ip_get() 可读到实际地址。stop() 会调用 netifapi_dhcp_release_and_stop() 并忽略其返回值。

6. 示例程序与验证

6.1 示例程序

code/middleware/net/example/eth/:

  • 入口:main/main.c,流程为 board_mac_init() → im_net_eth_start() → 打印启动结果。

  • 默认配置:eth_example_defconfig,EVB 板 + SZ18201 PHY + 静态 IPv4 10.5.4.111/24,网关 10.5.4.1。

  • 示例不直接调用 PHY 模板获取接口、不重复执行 pinmux/PHY 复位,符合板级职责边界。

  • code/middleware/net/example/eth/README.md 仍描述 “FPGA IMAGE10 + LAN8720A”,与当前 defconfig(EVB + SZ18201 + 静态 IPv4)和板级注册代码不一致,属于过期描述;以本文件和源码为准。

构建示例的基本流程:

tools/imde/bin/imde use-defconfig code/middleware/net/example/eth/eth_example_defconfig
tools/imde/bin/imde -D SDK_APP_DIR=code/middleware/net/example/eth configure
tools/imde/bin/imde build

SDK_APP_DIR 用于把示例的 main/main.c 接入固件;平台启动代码仍使用 main/core_v1。

启动后使用 net_info 查看接口与地址,使用 ping、iperf 验证链路和吞吐。

6.2 GMAC 模块测试

test/g32s10/module/gmac/ 是 GMAC 模块级测试集合,覆盖:

子目录覆盖内容
register寄存器默认值、有效位和读写行为
clock时钟门控打开/关闭及恢复后的寄存器访问
basic10/100M、全/半双工 TCP/UDP 收发
interruptDMA RX/TX 中断及异常事件
ahbDMA 突发配置、地址边界
mtu小帧、46/1500/超 MTU 帧
rate10M/100M 反复切换后的收发
robustness地址空间遍历和阈值寄存器读写
stress长时间压力测试

注意事项:

  • 该测试目录基于 FPGA IMAGE10,公共 defconfig 为 g32s10_v1_gmac_function_defconfig,使用 LAN8720A 和 DHCP;它验证的是 GMAC/MAC 路径,不是当前 EVB 的 SZ18201 板级组合。

  • 测试程序负责初始化 PHY、启动 DHCP 并记录 Ethernet 事件;网络类用例需要 PC 作为对端。

  • clock 用例只做门控和寄存器访问,不需要 PC 对端,使用独立 defconfig。

  • 该目录中的 ahb/im_net_eth.c/im_net_eth_adapter.h 是测试专用副本,不应作为生产 MID 的引用;生产实现以 code/middleware/net/net_adapter/ethernet/ 为准。

6.3 Shell 调试命令

命令语法说明
net_infonet_info列出 lwIP netif、up/link 状态、MTU、MAC、flags、IPv4、IPv6、DNS
pingping <host_address> [count] [interval_ms] [packet_size] [timeout_ms]通过 lwIP raw socket 发送 ICMP Echo
iperfiperf [-u] [-s|-c host] [-p port] [-i seconds] [-b bandwidth] [-t seconds] [-l length]TCP/UDP 吞吐测试(兼容 iperf 2.0.9 参数)
iperf_duplexiperf_duplex -c <peer> [-p <peer_port>] [-lp <local_port>] [-i seconds] [-b bandwidth] [-t seconds] [-l length]同时运行 UDP 服务端与客户端做双向测试
mac_phymac_phy <register_offset> [value]通过 MID 读写当前 Ethernet PHY 寄存器;register_offset 范围 0~31
net_confignet_config <action> <ifname> [args...]运行期配置:ip <ifname> <ip> <netmask> <gw>、up <ifname>、down <ifname>、default <ifname>、help

示例:

net_info
ping 10.5.4.1
iperf -c 10.5.4.10 -t 10
iperf -s
mac_phy 0
mac_phy 0 0x1140

mac_phy 属于调试接口,不属于 MID 公共业务 API;生产业务代码应使用 im_net_eth_phy_read()/im_net_eth_phy_write() 或应用自己的 PHY 管理逻辑。

net_config 的修改只在运行期有效,复位后恢复 Kconfig 中的配置;ip 动作会先停止 DHCP,default 设置可能被后续链路/IP 事件触发的 metric 重算覆盖。以太网接口名通常为 en0,可用 net_info 确认。

Shell 中的 ping、iperf、iperf_duplex 使用 lwIP socket 实现,不是 PHY/MAC MID 的接口;它们用于验证 MID 启动后数据面是否正常。

7. MID 错误码与边界

7.1 error_code_t 错误码

公共错误码出现场景
IM_OK操作成功
IM_ERR_INVALID_PARAM空指针、PHY 配置非法、PHY 地址或寄存器地址越界、输出缓冲区过小、addr_count == 0
IM_ERR_NOT_READY未注册 PHY;适配器未初始化;状态非 READY 时 start;未注册回调时 register_callback;PHY 扫描/链路未就绪;lwIP 初始化失败
IM_ERR_BUSY初始化完成后注册 PHY;RX 缓冲区分配失败;worker 线程创建失败;MDIO 总线忙
IM_ERR_TIMEOUTlwIP tcpip 初始化超时;MDIO 超时;PHY 软件复位超时
IM_ERR_UNSUPPORTEDIPv6 未启用时查询 IPv6;PHY 不匹配;HAL 不支持的能力
IM_ERR_NO_MEMORYlwIP 初始化等待器创建失败
IM_ERR_HARDWARE/IM_ERR_IOHAL/PHY 运行期硬件或 IO 错误
IM_ERR_ALREADY_REGISTEREDIRQ_GMAC 已被其他模块注册(MID 内部的 IRQ 标志通常可避免该路径)

7.2 lwIP err_t 映射

err_t触发场景
ERR_OK发送成功
ERR_ARGlinkoutput 参数空指针
ERR_RTEnetif 未 up 或链路 down
ERR_BUF帧长度为 0、超过 1536 字节,或链式 pbuf 长度不一致
ERR_MEM链式 pbuf 线性化分配失败
ERR_IFHAL 发送失败(含 TX ring 满)

7.3 HAL 事件到 MID 事件的映射

见 6.4。

7.4 与 HAL/LL 文档的分界

主题本文档HAL/LL 文档
MAC 寄存器、位域、描述符协议不展开mac_hal_ll_api.md
PHY 寄存器逐位定义只说明驱动内部使用不属于 HAL/LL 文档,见 PHY 驱动源码
板级时钟/电源/复位/pinmux只定义 board_mac_init() 契约和 EVB 参考流程HAL/LL 文档说明 HAL 不负责这些工作
lwIP netif/pbuf/DHCP本文档定义 MID 的接入行为不属于 HAL/LL 文档

7.5 版本与兼容性约定

  • MID 公开接口的签名、返回码和状态语义按本文档承诺;im_net_eth_t 内部字段、静态资源数量、worker 时序、日志文本属于实现细节,可能在不通知的情况下调整。

  • PHY 抽象层的枚举数值是与 HAL 的隐式契约(mac_phy_speed_t、mac_phy_duplex_t、mac_phy_flow_control_t),新增 PHY 驱动不得改变这些数值。

  • 新增 PHY 驱动必须实现 probe/read_id/reset/set_autoneg/get_link_state 五个操作,并保持模板静态生存期;set_config 为可选能力,当前 MID 不使用。

  • 如果后续引入多 MAC 实例,现有“无实例参数”的接口形态需要重新设计,本文档的所有接口契约都需要同步更新。