<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<atom:link href="https://www.yono233.cn/feed" rel="self" type="application/rss+xml"/>
<title>土星环的基地</title>
<link>https://www.yono233.cn</link>
<description>朋友没来齐，派对不结束</description>
<language>zh-CN</language>
<copyright>© yono </copyright>
<pubDate>Fri, 31 Jul 2026 20:50:12 GMT</pubDate>
<generator>Mix Space CMS (https://github.com/mx-space)</generator>
<docs>https://mx-space.js.org</docs>
<image>
    <url>https://cloudflare-imgbed-6qt.pages.dev/file/1735626843710_ic.jpg</url>
    <title>土星环的基地</title>
    <link>https://www.yono233.cn</link>
</image>
<item>
    <title>NI 驱动导致 win 蓝屏</title>
    <link>https://www.yono233.cn/posts/novel/26_7_31_ni-win</link>
    <pubDate>Fri, 31 Jul 2026 07:30:11 GMT</pubDate>
    <description>现象

windows 笔记本合盖睡眠，且不接电源的情况下。经过随机 1~3 小时。

再开盖时，按</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/posts/novel/26_7_31_ni-win'>https://www.yono233.cn/posts/novel/26_7_31_ni-win</a></blockquote>
          <h1>现象</h1>
<p>windows 笔记本合盖睡眠，且不接电源的情况下。经过随机 1~3 小时。</p>
<p>再开盖时，按下电源笔记本无法正常开启，经过 1<del>3 分钟，会蓝屏并报出 DRIVER_POWER_STATE_FAILURE (0x9F) 错误码，随后经过 2</del>5 分钟自检并彻底重启。</p>
<p>这非常打断工作流，重启后所有的工作区和软件都要重新打开，特别是在国内的傻逼软件<strong>微信系</strong>的玩意，都必须再手动掏出手机，然后扫码，然后他又得过一段时间同步信息，有时还会丢失信息。</p>
<p>经过这样一次事件，需要几乎半小时，才能准备好一切工作条件再重新开始。</p>
<h1>排查</h1>
<p>我一直以为是 windows 某次更新后引入的奇怪 bug，或者硬件上的某种不适配。今天受不了决定了解下具体是什么问题。</p>
<p>好在现在有 AI 帮助，只要自己检索规划出合理的排查路径，大多数信息都可以询问 AI 而不用自己从零学习。</p>
<p>主要的参考文章是</p>
<p><a href="https://www.cnblogs.com/xiykj/p/13304725.html">Windows蓝屏Dump文件分析 - 凡是過往；皆為序章 - 博客园</a></p>
<p>介绍了如何分析蓝屏现场保存的 windows 崩溃记录文件 Dump，该系列文件在 <strong>C:\Windows\Minidump</strong>，为了避免权限问题，复制一份放在外面进行分析。</p>
<h2>WinDbg</h2>
<p>windows 有 <strong>WinDbg</strong> 工具，参考文章中的版本相对老旧，所以需要基本探索一下 <strong>WinDbg</strong> 工具的使用。</p>
<p>微软官方有安装指南 <a href="https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debugger/">安装 WinDbg - Windows drivers | Microsoft Learn</a>，最方便快捷的就是使用终端指令安装，在终端运行</p>
<pre><code class="language-sh">winget install Microsoft.WinDbg</code></pre><p>或者你的终端环境不可用，也可以选用指南中的其他方法。安装完成后在开始菜单的应用列表中搜索 <strong>WinDbg</strong>，即可打开。</p>
<p>与参考文章不同，新版本的 <strong>WinDbg</strong> 工具操作方法和设置项名有一些区别，下面会逐步演示。</p>
<p>在正式导入 Dump 文件分析前需要做预配置。</p>
<p>首先点击左上角的 <strong>File</strong>。</p>
<p></p>
<p>然后点击 <strong>Settings</strong>，打开弹出页的 <strong>Debugging settings</strong>，设置其中的 <strong>Symbol path</strong>，为</p>
<pre><code class="language-">srv*C:\Symbols*http://msdl.microsoft.com/download/symbols</code></pre><p>这里我的操作方法和参考文章就已经不同，微软系的这些小软件，未来更新可能操作逻辑又有变化。</p>
<p>宗旨是预先配置 <strong>Symbol</strong> 这个关键词相关的设置项就行。</p>
<p></p>
<p>然后来到 <strong>Start debugging</strong>，点击其中的 <strong>Open dump file</strong>。这里我是灰色因为我在进行一个 dump 分析且暂时没有保存或关闭文件。</p>
<p>这一步的操作逻辑也未必一致，宗旨是找到 <strong>Open dump</strong> 这个关键词。</p>
<p></p>
<p>如果成功打开，那么将会有一些头信息的输出，并提示你运行相应指令进行正式分析。</p>
<p>你只要打命令开始分析就好</p>
<pre><code class="language-">!analyze -v</code></pre><p>注意，这个分析有一定耗时且不会给你提示，耐心等待 Debugging Details: 后的信息完全输出。当他分析完毕后，Debugging Details: 信息会不间断一次性输出。</p>
<p></p>
<p>然后你就可以成批量将输出的分析信息一次性包给 AI 分析了，实际上我也完全看不懂。</p>
<h2>我的问题分析结论</h2>
<p>AI 给出的分析结论如下。</p>
<pre><code class="language-sh">∴ The user has provided the complete !analyze -v output along with the !devobj and !irp commands I requested. Now I can
  give a comprehensive analysis.

  Let me parse the key findings:

  1. Bug Check: 0x9F (DRIVER_POWER_STATE_FAILURE) with Arg1=3 (device object blocking IRP too long)
  2. IMAGE_NAME: pci.sys
  3. FAILURE_BUCKET: 0x9F_3_POWER_DOWN_nipcibrd_IMAGE_pci.sys
  4. DRVPOWERSTATE_SUBCODE: 3 — power down transition
  5. STACK_TEXT: Shows nt!PopIrpWatchdogBugcheck → nt!PopIrpWatchdog — the power watchdog timer fired, meaning an IRP
  was stuck too long

  From !irp output:
  - Current stack (stack 7): IRP_MJ_POWER(16), IRP_MN_SET_POWER(2) — this is a SET_POWER IRP
  - The driver handling it is nipcibrd.sys — this is the National Instruments PCI/PXI bridge driver
  - The status shows "Success Error Cancel pending" — the IRP is still pending
  - The completion routine is nt!PopRequestCompletion
  - The device stack shows: \Driver\nipcibrd → \Driver\pci → \Driver\ACPI

  From !devobj:
  - The PDO belongs to \Driver\pci
  - Upper attached device is \Driver\ACPI

  So the power IRP is going through: pci → ACPI → nipcibrd

  The nipcibrd.sys driver has the pending IRP — it's not completing the power down request.

  Let me give a thorough analysis.

● 完整分析结论

  崩溃根因

  肇事驱动：nipcibrd.sys — National Instruments PCI/PXI Bridge Driver

  这是一个 National Instruments (NI) 的驱动，用于 NI 的 PCI/PXI 数据采集或仪器控制硬件。

  ---
  证据链

  ┌──────────────────────┬──────────────────────────────────────────────────────────────────┐
  │         证据         │                               指向                               │
  ├──────────────────────┼──────────────────────────────────────────────────────────────────┤
  │ FAILURE_BUCKET       │ 0x9F_3_POWER_DOWN_nipcibrd_IMAGE_pci.sys                         │
  ├──────────────────────┼──────────────────────────────────────────────────────────────────┤
  │ IRP 当前栈 (stack 7) │ IRP_MJ_POWER(16), IRP_MN_SET_POWER(2) — 由 \Driver\nipcibrd 持有 │
  ├──────────────────────┼──────────────────────────────────────────────────────────────────┤
  │ IRP 状态             │ Success Error Cancel pending — 仍在 pending，未完成              │
  ├──────────────────────┼──────────────────────────────────────────────────────────────────┤
  │ 子代码               │ DRVPOWERSTATE_SUBCODE: 3 — 电源下降转换 (S0→S3/S4/关机)          │
  ├──────────────────────┼──────────────────────────────────────────────────────────────────┤
  │ 设备栈               │ nipcibrd → pci → ACPI                                            │
  └──────────────────────┴──────────────────────────────────────────────────────────────────┘

  ---
  故障机制

  1. 系统发起电源状态转换（睡眠/休眠/关机），向设备栈发送 IRP_MN_SET_POWER IRP
  2. IRP 沿设备栈传递：ACPI → pci → nipcibrd
  3. nipcibrd.sys 收到了这个电源 IRP，但没有在时限内完成它（一直保持 pending 状态）
  4. 电源管理看门狗 (PopIrpWatchdog) 超时（默认约 10 分钟），触发 0x9F 蓝屏

  调用栈也完全印证：
  nt!PopIrpWatchdogBugcheck    ← 电源看门狗触发蓝屏
  nt!PopIrpWatchdog            ← 检测到 IRP 超时
  nt!KiProcessExpiredTimerList ← 定时器到期
  nt!KiTimerExpiration
  nt!KiRetireDpcList
  nt!KiIdleLoop

  ---
  解决建议

  ┌────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ 优先级 │                                                  操作                                                   │
  ├────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────┤
  │ 1 立即 │ 更新 NI 驱动 — 去 ni.com/drivers 下载最新版 NI 设备驱动（NI-DAQmx、NI-VISA、或 NI-488.2，视你的 NI      │
  │        │ 硬件而定）                                                                                              │
  ├────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────┤
  2. IRP 沿设备栈传递：ACPI → pci → nipcibrd
  3. nipcibrd.sys 收到了这个电源 IRP，但没有在时限内完成它（一直保持 pending 状态）
  4. 电源管理看门狗 (PopIrpWatchdog) 超时（默认约 10 分钟），触发 0x9F 蓝屏

  调用栈也完全印证：
  nt!PopIrpWatchdogBugcheck    ← 电源看门狗触发蓝屏
  nt!PopIrpWatchdog            ← 检测到 IRP 超时
  nt!KiProcessExpiredTimerList ← 定时器到期
  nt!KiTimerExpiration
  nt!KiRetireDpcList
  nt!KiIdleLoop

  ---
  解决建议

  ┌────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ 优先级 │                                                     操作                                                      │
  ├────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
  │ 1 立即 │ 更新 NI 驱动 — 去 ni.com/drivers 下载最新版 NI 设备驱动（NI-DAQmx、NI-VISA、或 NI-488.2，视你的 NI 硬件而定） │
  ├────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
  │ 2 立即 │ 检查是否有 NI 硬件连接到这台电脑（PCI 卡、PXI 机箱、USB DAQ 等），确认固件也是最新的                          │
  ├────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
  │ 3 检查 │ 运行 driverquery /v 查看 nipcibrd.sys 的版本号，当前崩溃版本 10.0.26100.8737 可能不兼容 Windows 11 24H2       │
  ├────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
  │ 4 临时 │ 如果暂时不需要 NI 硬件，可以在设备管理器中禁用 NI 相关设备，或卸载 NI 软件                                    │
  ├────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
  │ 5 长期 │ 在 NI 更新驱动之前，避免让系统进入睡眠状态（电源选项里关闭睡眠），可以减少触发概率                            │
  └────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

  ---
  关键信息速查

  肇事文件:   nipcibrd.sys
  发布者:     National Instruments
  崩溃类型:   DRIVER_POWER_STATE_FAILURE (0x9F)
  触发场景:   系统电源下降 (睡眠/休眠/关机)
  系统:       Windows 11 24H2 (Build 26100)
  运行时长:   5 天 2 小时

  这个崩溃发生在系统试图进入低功耗状态或关机时，NI PCI 桥驱动没有正确响应。如果你在使用 NI 的 DAQ、GPIB
  或其他测量设备，这就是根本原因。

✻ Sautéed for 32s</code></pre>
          <p style='text-align: right'>
          <a href='https://www.yono233.cn/posts/novel/26_7_31_ni-win#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">164999773374386176</guid>
  <category>post</category>
<category>禹步</category>
 </item>
  <item>
    <title>无 Docker Hub 环境下容器化部署 Mihomo 代理</title>
    <link>https://www.yono233.cn/posts/HuangShiGong/docker-hub-mihomo</link>
    <pubDate>Mon, 27 Jul 2026 08:52:21 GMT</pubDate>
    <description>决定新开一个分类&quot;天书&quot;，url-slug 为 &quot;黄石公&quot;
用于存放完全 AI 生成的教程内容
这就</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/posts/HuangShiGong/docker-hub-mihomo'>https://www.yono233.cn/posts/HuangShiGong/docker-hub-mihomo</a></blockquote>
          <blockquote>
<p>决定新开一个分类&quot;天书&quot;，url-slug 为 &quot;黄石公&quot;</p>
<p>用于存放完全 AI 生成的教程内容</p>
<p>这就是第一篇了</p>
</blockquote>
<h1>无 Docker Hub 环境下容器化部署 Mihomo 代理</h1>
<h2>适用场景</h2>
<p>服务器几乎不能正常访问外网，Docker Hub 不可用（或无法拉取任何镜像）。Podman、宝塔面板、或直接安装的 Docker Engine 均适用。</p>
<h2>核心思路</h2>
<ul>
<li>利用服务器已有的任意 Alpine 镜像（如 <code>redis:alpine</code>）作为构建时的 CA 证书来源，最终镜像基于 <code>scratch</code> 构建，<strong>不产生额外镜像拉取</strong>。</li>
<li>所有新增文件集中在 <code>/root/mihomo/</code> 目录下，不污染服务器其他位置。</li>
<li>仅目标容器走代理，宿主机与其他容器不受影响。</li>
</ul>
<hr>
<h2>第一步：准备文件</h2>
<p>以下文件可在**个人 PC（能正常访问 GitHub）**上下载好，再放置到服务器的 <code>/root/mihomo/</code> 目录。</p>
<table>
<thead>
<tr>
<th>文件</th>
<th>作用</th>
<th>获取方式</th>
</tr>
</thead>
<tbody><tr>
<td><code>mihomo</code>（二进制）</td>
<td>代理核心</td>
<td><a href="https://github.com/MetaCubeX/mihomo/releases">GitHub Releases</a> 下载 <code>mihomo-linux-amd64-v*.gz</code>，解压后重命名为 <code>mihomo</code></td>
</tr>
<tr>
<td><code>geoip.metadb</code></td>
<td>GeoIP 规则数据库</td>
<td><a href="https://github.com/MetaCubeX/meta-rules-dat/releases">meta-rules-dat Releases</a> 下载 <code>geoip.metadb</code>，放入 <code>data/</code> 子目录</td>
</tr>
<tr>
<td><code>config.yaml</code></td>
<td>代理配置</td>
<td>见下方</td>
</tr>
<tr>
<td><code>Dockerfile</code></td>
<td>镜像构建</td>
<td>见下方</td>
</tr>
<tr>
<td><code>docker-compose.yml</code></td>
<td>容器编排</td>
<td>见下方</td>
</tr>
</tbody></table>
<p>最终目录结构：</p>
<pre><code class="language-">/root/mihomo/
├── mihomo              # 二进制文件
├── config.yaml         # 代理配置
├── Dockerfile
├── docker-compose.yml
└── data/
    └── geoip.metadb    # GeoIP 数据库</code></pre><hr>
<h2>第二步：config.yaml</h2>
<p>核心思路：订阅 URL 返回完整配置，从中提取 DNS 和 rules 部分直接放入 config.yaml；代理节点通过 <code>proxy-providers</code> 指向订阅 URL，由 mihomo 每日自动拉取更新。</p>
<p>有一些部分依据服务商不同，填写服务商给到的订阅 URL 中的对应固定部分，<strong>可以由 AI 代劳</strong>。</p>
<blockquote>
<p><code>url:</code> 填入你的订阅地址，URL 本身自带鉴权（路径中的随机 token），无需额外认证。</p>
</blockquote>
<pre><code class="language-yaml"># 端口与模式
port: 7890
socks-port: 7891
allow-lan: true
mode: Rule
log-level: info
external-controller: 0.0.0.0:9090

# DNS（从订阅返回内容中提取）
dns:
  enable: true
  # ... 完整内容从订阅 URL 拉取后填入

# 每日自动从订阅地址拉取最新节点
proxy-providers:
  sub:
    type: http
    url: "https://你的订阅地址?clash=3"
    interval: 86400
    path: ./providers/sub.yaml
    health-check:
      enable: true
      url: https://cp.cloudflare.com
      interval: 300

# 自动选择最快节点
proxy-groups:
  - name: 🔰 选择节点
    type: url-test
    use: [sub]
    url: https://www.gstatic.com/generate_204
    interval: 300

# 规则（从订阅返回内容中提取）
rules:
  - GEOIP,CN,DIRECT
  - MATCH,🔰 选择节点</code></pre><hr>
<h2>第三步：Dockerfile</h2>
<pre><code class="language-dockerfile">FROM redis:alpine AS certs
FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY mihomo /mihomo
ENTRYPOINT ["/mihomo"]
CMD ["-d", "/etc/mihomo"]</code></pre><ul>
<li>第一阶段 <code>FROM redis:alpine</code>：使用服务器已有镜像，仅提取 CA 根证书。</li>
<li>第二阶段 <code>FROM scratch</code>：空镜像，最终产物仅包含 mihomo 二进制与 CA 证书，干净无冗余。</li>
<li><code>redis:alpine</code> 仅作为构件引用，不运行、不被修改，可替换为服务器上任意 Alpine 系镜像。</li>
</ul>
<hr>
<h2>第四步：docker-compose.yml</h2>
<pre><code class="language-yaml">services:
  mihomo:
    build: .
    container_name: mihomo
    restart: unless-stopped
    volumes:
      - ./config.yaml:/etc/mihomo/config.yaml:ro
      - ./data:/etc/mihomo
    ports:
      - "7890:7890"
      - "9090:9090"</code></pre><ul>
<li><code>build: .</code> 使用本地 Dockerfile 构建，无需拉取外部镜像。</li>
<li><code>9090</code> 端口为 REST API（可选，用于热更新或状态查询）。</li>
</ul>
<hr>
<h2>第五步：构建与启动</h2>
<pre><code class="language-bash">cd /root/mihomo

# 确保二进制文件存在且可执行
chmod +x mihomo

# 构建并启动
docker compose build
docker compose up -d</code></pre><p>验证代理可用：</p>
<pre><code class="language-bash">curl -x http://localhost:7890 https://www.google.com -o /dev/null -w "%{http_code}"</code></pre><p>返回 <code>200</code> 即成功。</p>
<hr>
<h2>第六步：让其他容器走代理</h2>
<p>以博客后端容器为例，在其 <code>docker-compose.yml</code> 中添加环境变量：</p>
<pre><code class="language-yaml">environment:
  HTTP_PROXY: "http://172.17.0.1:7890"
  HTTPS_PROXY: "http://172.17.0.1:7890"
  NO_PROXY: "localhost,127.0.0.1"</code></pre><p><code>172.17.0.1</code> 为 Docker 默认 bridge 网关，容器通过它访问宿主机上 mihomo 映射的 <code>7890</code> 端口。如后端使用自定义网络，用 <code>docker inspect &lt;容器名&gt; | grep Gateway</code> 确认实际网关地址。</p>
<p>重建目标容器后进入容器验证：</p>
<pre><code class="language-bash">docker exec &lt;容器名&gt; curl -x http://172.17.0.1:7890 https://www.google.com -o /dev/null -w "%{http_code}"</code></pre><p>返回 <code>200</code> 即完成。</p>
<hr>
<h1>对于 mx-space 的 OAuth</h1>
<p>mx-space 使用 better-auth 包进行 OAuth 认证，但这个包不会默认走容器的代理。所以需要 js 注入的额外处理。</p>
<h3>问题</h3>
<p>设置了 <code>HTTP_PROXY</code> 环境变量后，<code>curl</code> 等传统工具能走代理，但 better-auth、Google OAuth 等使用了 Node.js 原生 <code>fetch()</code> 的包仍然直连——因为 <code>fetch()</code> 底层是 <code>undici</code>，它<strong>不读取 <code>HTTP_PROXY</code> 环境变量</strong>。</p>
<h3>解决方案</h3>
<p>三步：注入脚本 → 声明依赖 → 部署。</p>
<h4>1. 创建 <code>proxy-patch.mjs</code></h4>
<pre><code class="language-js">import { ProxyAgent, setGlobalDispatcher } from 'undici';

const proxy = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
if (proxy) {
  setGlobalDispatcher(new ProxyAgent(proxy));
}</code></pre><h4>2. 容器 docker-compose.yml 中添加</h4>
<pre><code class="language-yaml">environment:
  NODE_OPTIONS: "--import /app/proxy-patch.mjs"
  # HTTP_PROXY 和 HTTPS_PROXY 已有

volumes:
  - ./proxy-patch.mjs:/app/proxy-patch.mjs:ro
  - ./undici:/app/node_modules/undici:ro   # 如果镜像内未预装 undici</code></pre><h4>3. 如果镜像内未预装 undici</h4>
<p>在个人 PC 上下载 undici npm 包，放入容器项目目录：</p>
<pre><code class="language-bash"># 在 PC 上（需要 npm）
npm pack undici --pack-destination .
tar -xzf undici-*.tgz
mv package undici</code></pre><p>将 <code>undici/</code> 目录随容器项目一起传到服务器即可。</p>
<p>最终的结构类似</p>
<pre><code class="language-">  mx-core/
  ├── docker-compose.yml
  ├── proxy-patch.mjs
  ├── undici/              # undici 8.9.0 完整包
  └── data/</code></pre><hr>
<h3>验证</h3>
<p>进入容器后执行：</p>
<pre><code class="language-bash">node -e "fetch('https://www.google.com').then(r =&gt; console.log(r.status))"</code></pre><p>返回 <code>200</code> 即代理生效。</p>

          <p style='text-align: right'>
          <a href='https://www.yono233.cn/posts/HuangShiGong/docker-hub-mihomo#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">163570901592313856</guid>
  <category>post</category>
<category>天书</category>
 </item>
  <item>
    <title>GD32H7 的 MPU 备查——关于 0x0000 寻址区的配置</title>
    <link>https://www.yono233.cn/notes/55</link>
    <pubDate>Fri, 10 Jul 2026 06:39:50 GMT</pubDate>
    <description>旧的背景故事

之前有过 GD32H7 打开网络功能的尝试，因为没有在最终工程产品中用到该芯片，仅作</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/notes/55'>https://www.yono233.cn/notes/55</a></blockquote>
          <h1>旧的背景故事</h1>
<p>之前有过 GD32H7 打开网络功能的尝试，因为没有在最终工程产品中用到该芯片，仅作评估后封存。</p>
<p>当时的现象是，完全采用与官方例程一模一样的<strong>库、外设配置、调用顺序、操作方法</strong>，只是我将官方的 keil 例程改为 cmake-gcc 工程。问题是<strong>官方例程编译烧录后一切正常，而我的工程编译后无论如何都无法 ping 通</strong>。</p>
<p>我对 lwip 这个网络库、ETH 外设这块的了解实在有限，GD 支持也无法找到原因所在。</p>
<h1>原因</h1>
<p>总的来说，GD32H7 芯片需要以类似这样的配置方法，将 0x0000 开始的整个寻址区域，都设置 MPU 保护，作为背景设置，然后后续的 MPU 配置块再做实际配置。</p>
<pre><code class="language-c">    mpu_region_init_struct mpu_init_struct;
    /* disable MPU */
    ARM_MPU_Disable();
   
    mpu_init_struct.region_number       = MPU_REGION_NUMBER0;
    mpu_init_struct.region_base_address = 0x00000000U;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_NOT_PERMIT;
    mpu_init_struct.access_permission   = MPU_AP_NO_ACCESS;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE0;
    mpu_init_struct.access_shareable    = MPU_ACCESS_SHAREABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_NON_BUFFERABLE;
    mpu_init_struct.subregion_disable   = 0x87;
    mpu_init_struct.region_size         = MPU_REGION_SIZE_4GB;  
   
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();
    /* enable MPU */
    ARM_MPU_Enable(MPU_MODE_PRIV_DEFAULT);</code></pre><h1>问题是如何产生的</h1>
<p>在 GD32H7 手册<strong>1.3 存储器映射</strong>上可见</p>
<p>0x0000 0000~0x0007 FFFF 划归为 ITCM RAM(来自共享 RAM)，但是这个区域又被划归为<strong>代码</strong>区域。我暂时不太理解其意图。总之就是在内核运行的过程中将该区域认为是 RAM 区，所以有读写可能。</p>
<p>依据参考材料的说法，GD 官方勘误表或任何手册都没有描述这一点。当然官方例程很多时候也没有做到这一点，否则我此前改为 gcc 编译应当是一切正常。只有 ST 官方的甚至 <a href="https://support.touchgfx.com/zh-CN/docs/development/scenarios/running-graphics-on-stm32h7r">touchgfx</a> 这个图形库手册而非芯片手册中有这样的描述。</p>
<blockquote>
<p>M7处理器上，必须防止对外部存储器的推测性访问，否则可能引发高延迟或系统错误。 对于STM32H7R/S，这将影响访问内存的AXI主设备，并显著降低图形性能。
MPU可通过控制可访问的地址范围来防止推测性读取访问。 最简单的方法是使用包含整个内存区域的背景区域，通过将其设置为“强排序，永不执行”来限制访问。
背景区域应定义在默认区域ID-1中，因为所有其他区域的优先级都将高于此区域。 然后，应为需要访问的内存区域定义具有相应设置的其他MPU区域。 在STM32H7R/S上最多可定义16个区域。</p>
</blockquote>
<p>也就是这是一个 M7 内核原设计就有的缺陷，而我使用 stm32H7 只是 ST 官方做成芯片时使用某种手段规避了问题，或者甚至只是恰巧没有碰到。</p>
<h1>参考资料备查</h1>
<p>GD32H7移植NEXTDUO问题</p>
<p><a href="https://forum.anfulai.cn/forum.php?mod=viewthread&tid=125782&extra=">https://forum.anfulai.cn/forum.php?mod=viewthread&amp;tid=125782&amp;extra=</a></p>
<p> GD32H757ZMT6 仅因 Flash/Load image 布局变化，程序运行稳定性就出现明显差异</p>
<p><a href="https://forum.anfulai.cn/forum.php?mod=viewthread&tid=131926&extra=">https://forum.anfulai.cn/forum.php?mod=viewthread&amp;tid=131926&amp;extra=</a></p>

          <p style='text-align: right'>
          <a href='https://www.yono233.cn/notes/55#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383669563441</guid>
  <category>note</category>
false
 </item>
  <item>
    <title>md 的迷思</title>
    <link>https://www.yono233.cn/posts/novel/26_6_17_md</link>
    <pubDate>Wed, 17 Jun 2026 07:10:38 GMT</pubDate>
    <description>markdown

实际上在部署本博客前，我从来没有接触过 Markdown(md) 标记语法。Mi</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/posts/novel/26_6_17_md'>https://www.yono233.cn/posts/novel/26_6_17_md</a></blockquote>
          <h1>markdown</h1>
<p>实际上在部署本博客前，我从来没有接触过 Markdown(md) 标记语法。<a href="https://mx-space.js.org/">Mix Space</a> 博客框架算是我的 md 入门。</p>
<p>在后续尝试搭出 wiki、搭出网站、md 产出说明书等等实用实例时，md 都可以作为关键的<strong>内容源</strong>，而且非常便于使用 git 之类做版本控制和更改比对。</p>
<p>恰巧，在我对 md 的深入使用的时间，正好贴合，AI 领域也从早期的“提示词”对话，变成了现在“skill  +agent”作为真正助手。现在想要真正用好 AI，md 语言和文件已经是必不可少了。</p>
<p>我和领导一直有一个巨大分歧，我认为“内容很重要，形式更重要”，而他认为形式根本不用管。</p>
<p>无论什么内容，最终是给某个“实体”阅读和理解，而合理的形式将极大增强可读性，不好的形式容易曲解内容。</p>
<p>md 恰好<strong>编写内容</strong>、<strong>调整格式</strong>都还算简单，也适合人类、AI、或者任何其他脚本工具理解。在现代，可能所有的内容写作都应该是 md 格式，再制作工具或借助 AI 转为目标形式。</p>
<h1>agent</h1>
<p>经历<strong>直接调用大模型</strong>[^直接大模型] &gt;&gt;&gt;<strong>compound AI system</strong>[^复合式AI系统]，现在特别是龙虾爆火之后，各种真正的 agent<a href>^智能体</a> 加速涌现。Claude code、GitHub copilot 都开发成了真正 agent 的形式。</p>
<p>[^直接大模型]: 一段 prompt 丢给模型,模型直接吐出一段文本</p>
<p>[^复合式AI系统]: 通常是对话框形式，他不能输入一个长期目标，不断迭代完成，但是具有一定预处理和调用工具的能力，也不用自己输入各种各样 prompt</p>
<p>在 agent 的使用中，md 的地位更加重要</p>
<ul>
<li>作为技能提示，指示 agent 工作时的关键侧重技术栈</li>
<li>作为边界条件，设定 agent 可自主操作的文件边界，哪些操作一定需要获得批准</li>
<li>作为风格侧重，更注重性能，还是更注重封装和代码可重用性</li>
<li>作为可信信源，增加一些绝对可信的资料信息供 agent 查阅</li>
<li>作为持久性信息，让 AI 缩减上下文、记录项目现状、项目特定注重项，跨项目阶段和环境做统一</li>
</ul>
<p>无论如何，哪怕你创建一个 skill.md 像直接用大模型一样写一句，也是会产生效果的。</p>
<pre><code class="language-">**你是一个xxx技术专家,擅长xxxx领域应用**</code></pre><h1>我的 agent 学习</h1>
<p>起因并不是为了学习 agent，市面上的<strong>酒馆AI</strong>调用的模型太烂了，根本没办法正常游玩，迫不得已自己部署一个来玩，体验相当不错。</p>
<p><a href="https://github.com/SillyTavern/SillyTavern">SillyTavern/SillyTavern: LLM Frontend for Power Users.</a></p>
<p>为了自己好的游戏体验，自己编写<strong>角色/世界卡</strong>，但是我的想法又过分复杂，不得已自己部署了一个 agent 来辅助创作。</p>
<p>抄袭自该项目，借助 claude 做了一些微调。</p>
<p><a href="https://github.com/CodePothunter/lingque">CodePothunter/lingque: A self-awared agent(s) assistents with very compact core, natively connected to Lark (feishu).</a></p>
<p>这个项目相对简单，各种机制却非常合我的胃口。具体机制可见项目开发文档，或者作者在抄袭项目下的声明(这部分写的比原项目文档更加清晰)。并且我计划基于该项目制作所有自用的 agent。</p>
<p><a href="https://github.com/LDPrompt/lingque/issues/1">关于 LDPrompt/lingque 项目抄袭灵雀（LingQue）框架的声明 · Issue #1 · LDPrompt/lingque</a></p>
<p>在该项目中，也是使用 SOUL.md/MEMORY.md 做总体技能设定/持久化，同时他也支持本地优先的知识库，知识文档也应该以 md 格式存放便于 agent 理解。</p>
<h1>文字游戏再次崛起</h1>
<p>现在 AI 还依然无法便宜地接入现代化的游戏中，但是已经在老派类型<strong>文字游戏</strong>中大放异彩，非常痴迷文字游戏的我已经爽到。</p>
<p>这些所有关于 AI 的用户可设定部分，依然是 md 格式。我想未来模型便宜到足够接入现代化游戏的时候，也是如此。</p>
<p>AI 让 md 再次伟大？</p>

          <p style='text-align: right'>
          <a href='https://www.yono233.cn/posts/novel/26_6_17_md#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383661174830</guid>
  <category>post</category>
<category>禹步</category>
 </item>
  <item>
    <title>FlashDB 的引入</title>
    <link>https://www.yono233.cn/posts/novel/flashdb</link>
    <pubDate>Wed, 13 May 2026 04:04:30 GMT</pubDate>
    <description>前置条件

这个简单数据库可以以任意存储介质作为实际空间。

对于 flash，通常的最小擦除单位是</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/posts/novel/flashdb'>https://www.yono233.cn/posts/novel/flashdb</a></blockquote>
          <h1>前置条件</h1>
<p>这个简单数据库可以以任意存储介质作为实际空间。</p>
<p>对于 flash，通常的最小擦除单位是扇区。</p>
<p>如果是片上 flash，至少需要规划预留一个扇区对齐的区域供 FlashDB 使用。</p>
<p>如果是外部 flash，除了扇区对齐的规划，需要实现并测试<code>读、写、擦除</code>的 API 作为准备工作。</p>
<p>如果是 eeprom，同样的，实现并测试<code>读、写、擦除</code>的 API 作为准备工作，此时会简单很多，不必考虑扇区对齐问题。擦除 API 是为了兼容 FlashDB 默认存储介质是 flash，采用符合 flash 的行为逻辑，实际上可以将擦除 API 做空操作。</p>
<p>FlashDB 会自行处理好扇区对齐问题，所以在实现 API 时不必添加扇区对齐的检查，以减小开销。</p>
<h1>引入源码包</h1>
<p>在 <a href="https://github.com/armink/FlashDB">armink/FlashDB</a> 可以下载到原始源码包。</p>
<p>但是他没有 CMakeLists，需要了解其源码划分，才能正确引入所需的源码。</p>
<p>其实际上必须引入的源码文件夹如下，其他的则可以在工程中删除。下面用更清晰的 ASCII 树展示，方便在 Markdown 中阅读和复制。</p>
<pre><code class="language-">FlashDB/
├─ demos/
├─ docs/
├─ inc/            # 需要加入到 include path
├─ port/
│  └─ fal/
│     ├─ docs/
│     ├─ inc/      # 需要加入到 include path
│     ├─ samples/
│     └─ src/      # 需要加入到编译的 .c 文件
├─ samples/
├─ src/            # 需要加入到编译的 .c 文件
├─ tests/
└─ zephyr/</code></pre><p>其中标识的 .c 文件需要加入编译，同时加入以下的 includePATH</p>
<pre><code class="language-">FlashDB/inc
FlashDB/port/fal/inc</code></pre><p>FlashDB/inc 中有 <code>fdb_cfg_template.h</code>，复制一份并重命名为 <code>fdb_cfg.h</code> 放在自己的工程中，比如原地，在 includePATH 范围内就好。</p>
<p>最小起步时其中的默认配置不必修改，只要考虑编写 <code>FDB_PRINT</code> 即可，例如我编写为使用 RTT 打印，或者留空。</p>
<pre><code class="language-c">#define FDB_PRINT(...) SEGGER_RTT_printf(0, __VA_ARGS__)

// #define FDB_PRINT(...) \
//     do                 \
//     {                  \
//     }                  \
//     while(0)</code></pre><p>新建一份 <code>fal_cfg.h</code> 放在自己的工程中，例如</p>
<pre><code class="language-c">#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#define FAL_PART_HAS_TABLE_CFG

#define FAL_FLASHDB_DEV_NAME       "norflash0"
#define FAL_FLASHDB_KV_PART_NAME   "fdb_kv_cfg"
#define FAL_FLASHDB_KV_PART_OFFSET (0x00040000u)
#define FAL_FLASHDB_KV_PART_LENGTH (0x00040000u)

extern struct fal_flash_dev nor_flash0;

#define FAL_FLASH_DEV_TABLE \
    {                       \
        &nor_flash0,        \
    }

#ifdef FAL_PART_HAS_TABLE_CFG
#define FAL_PART_TABLE                                                                                                                    \
    {                                                                                                                                     \
        {FAL_PART_MAGIC_WORD, FAL_FLASHDB_KV_PART_NAME, FAL_FLASHDB_DEV_NAME, FAL_FLASHDB_KV_PART_OFFSET, FAL_FLASHDB_KV_PART_LENGTH, 0}, \
    }
#endif

#endif /* _FAL_CFG_H_ */</code></pre><h1>为工程引入 fal</h1>
<p>注意到上面的 <code>fal_cfg.h</code> 其中有这样的内容，其中 <code>FAL_FLASH_DEV_TABLE</code> 是一个必须定义的 falsh 设备表，这里有一个 <code>nor_flash0</code> 设备描述对象。</p>
<p>这些描述对象与期望操作的 flash 抽象一一对应，比如我这里只有一个 spi-norflash，所以只使用了一个抽象对象。</p>
<pre><code class="language-c">extern struct fal_flash_dev nor_flash0;

#define FAL_FLASH_DEV_TABLE \
    {                       \
        &nor_flash0,        \
    }</code></pre><p>在现在，虽然使用了声明，但是这个 flash 抽象依然还没有定义，定义这个抽象内容是使其真正具备真实 flash 操作能力的关键。</p>
<p>这里我们可以新建一个源码进行整体绑定，使其具有 读/写/擦 接口。比如如下的核心定义，其中</p>
<ul>
<li><code>.len</code> 是完整 flash 空间大小，</li>
<li><code>.blk_size</code> 是擦除最小单位在 flash 中通常是扇区大小。</li>
<li><code>.ops</code> 是 读/写/擦 回调，在回调中使用<strong>前置条件</strong>中已实现的 API。</li>
<li><code>.write_gran</code> 是写最小字节数粒度，例如 norflash  此值定义为 1，而片上 flash 可能要求 4/8 字节对齐。</li>
</ul>
<pre><code class="language-c">struct fal_flash_dev nor_flash0 = {
    .name       = FAL_FLASHDB_DEV_NAME,
    .addr       = 0,
    .len        = 1 * 1024 * 1024,
    .blk_size   = DEVICE_SECTOR_SIZE,
    .ops        = {fal_norflash_init,
                     fal_norflash_read, 
                     fal_norflash_write, 
                     fal_norflash_erase},
    .write_gran = FDB_WRITE_GRAN,
};</code></pre><p>下面会展示为了支持这个抽象内容的完整源码，在这里有一个重要的问题需要处理。因为 fal 似乎并没有按页逐步写的操作，所以在 norflash 的回调处理中，需要注意不要跨页写，分为多次写使能和写请求。</p>
<pre><code class="language-c">#include &lt;NorFlashSpi.h&gt;
/* Port */
extern uint32_t FlashSpiTransmitPort(_NOR_FLASH_MESSAGE *pd, const uint8_t *TBuf, uint32_t ui32Len);
extern uint32_t FlashSpiReceivePort(_NOR_FLASH_MESSAGE *pd, uint8_t *RBuf, uint32_t ui32Len);
extern uint32_t FlashSpiTransmitReceivePort(_NOR_FLASH_MESSAGE *pd, const uint8_t *TBuf, uint8_t *RBuf, uint32_t ui32Len);
#include &lt;fal.h&gt;
#include &lt;fdb_cfg.h&gt;
#include &lt;includes.h&gt;

extern volatile uint8_t fSpiTxBuf[];
extern volatile uint8_t fSpiRxBuf[];
/* 片选使能函数 */
#define CS_EN( ) HAL_GPIO_WritePin(SPI5_FLASH_CS_GPIO_Port, SPI5_FLASH_CS_Pin, GPIO_PIN_RESET);
/* 片选失能函数 */
#define CS_UN( ) HAL_GPIO_WritePin(SPI5_FLASH_CS_GPIO_Port, SPI5_FLASH_CS_Pin, GPIO_PIN_SET);
/* 定义写入最小单位 */
#define FLASH_PAGE_SIZE   256

#define FALFDB_TRACE(...) SEGGER_RTT_printf(0, "[FALNOR] " __VA_ARGS__)

static int      fal_norflash_init(void);
static int      fal_norflash_read(long offset, uint8_t *buf, size_t size);
static int      fal_norflash_write(long offset, const uint8_t *buf, size_t size);
static int      fal_norflash_erase(long offset, size_t size);

static uint32_t fal_norflash_wait_idle(void)
{
    uint32_t i;

    fSpiTxBuf[0] = CMD_RDSR1;
    fSpiTxBuf[1] = 0;

    CS_EN( );
    if(FlashSpiTransmitReceivePort(NULL, (uint8_t *)fSpiTxBuf, (uint8_t *)fSpiRxBuf, 2) != RETURN_DEFAULT)
    {
        CS_UN( );
        return RETURN_FLASH_READ_ERR;
    }
    CS_UN( );

    i = 0;
    while(((fSpiRxBuf[1] & WIP_FLAG) != 0) && (i &lt; 0xFFFF))
    {
        CS_EN( );
        if(FlashSpiTransmitReceivePort(NULL, (uint8_t *)fSpiTxBuf, (uint8_t *)fSpiRxBuf, 2) != RETURN_DEFAULT)
        {
            CS_UN( );
            return RETURN_FLASH_READ_ERR;
        }
        CS_UN( );
        i++;
    }

    if((fSpiRxBuf[1] & WIP_FLAG) != 0)
    {
        return RETURN_FLASH_BUSY;
    }

    return RETURN_DEFAULT;
}

struct fal_flash_dev nor_flash0 = {
    .name       = FAL_FLASHDB_DEV_NAME,
    .addr       = 0,
    .len        = 1 * 1024 * 1024,
    .blk_size   = DEVICE_SECTOR_SIZE,
    .ops        = {fal_norflash_init, fal_norflash_read, fal_norflash_write, fal_norflash_erase},
    .write_gran = FDB_WRITE_GRAN,
};

static int fal_norflash_init(void)
{
    /* 发送buffer转为 读ID指令 */
    fSpiTxBuf[0] = CMD_RDID;
    fSpiTxBuf[1] = 0;
    fSpiTxBuf[2] = 0;
    fSpiTxBuf[3] = 0;
    fSpiRxBuf[1] = 0;
    fSpiRxBuf[2] = 0;
    fSpiRxBuf[3] = 0;

    CS_EN( );
    if(FlashSpiTransmitReceivePort(NULL, (uint8_t *)fSpiTxBuf, (uint8_t *)fSpiRxBuf, 4) != RETURN_DEFAULT) // 收发
    {
        FALFDB_TRACE("[SPI-FLASH]init warn: read id transfer failed\r\n");
    }
    CS_UN( );

    uint32_t ChipID = ((uint32_t)fSpiRxBuf[1] &lt;&lt; 16) | ((uint32_t)fSpiRxBuf[2] &lt;&lt; 8) | fSpiRxBuf[3];
    switch(ChipID)
    {
    case W25Q80_ID:
        nor_flash0.len      = 1 * 1024 * 1024;
        nor_flash0.blk_size = 4 * 1024;
        break;
    case W25Q64_ID:
        nor_flash0.len      = 8 * 1024 * 1024;
        nor_flash0.blk_size = 4 * 1024;
        break;
    case W25Q128_ID:
        nor_flash0.len      = 16 * 1024 * 1024;
        nor_flash0.blk_size = 4 * 1024;
        break;
    case W25Q256_ID:
        nor_flash0.len      = 32 * 1024 * 1024;
        nor_flash0.blk_size = 4 * 1024;
        break;
    case W25Q512_ID:
        nor_flash0.len      = 64 * 1024 * 1024;
        nor_flash0.blk_size = 4 * 1024;
        break;
    default:
        nor_flash0.len      = 0;
        nor_flash0.blk_size = 0;
        FALFDB_TRACE("[SPI-FLASH]init failed: unsupported chip id=0x%08X\r\n", (unsigned)ChipID);
        return -1;
    }

    return 0;
}

static int fal_norflash_read(long offset, uint8_t *buf, size_t size)
{
    uint32_t addr;
    uint32_t chunk;
    size_t   remaining;
    size_t   copied;

    if(fal_norflash_wait_idle( ) != RETURN_DEFAULT)
    {
        FALFDB_TRACE("read failed: flash busy before read\r\n");
        return -1;
    }

    addr = (uint32_t)offset;

    /* 发送读指令和3字节地址 */
    fSpiTxBuf[0] = CMD_READ;
    fSpiTxBuf[1] = (addr &gt;&gt; 16) & 0xFF;
    fSpiTxBuf[2] = (addr &gt;&gt; 8) & 0xFF;
    fSpiTxBuf[3] = addr & 0xFF;

    CS_EN( );
    if(FlashSpiTransmitPort(NULL, (uint8_t *)fSpiTxBuf, 4) != RETURN_DEFAULT)
    {
        CS_UN( );
        FALFDB_TRACE("read failed: cmd tx error off=0x%08X size=%u\r\n", (unsigned)offset, (unsigned)size);
        return -1;
    }

    remaining = size;
    copied    = 0;
    while(remaining &gt; 0)
    {
        chunk = (remaining &gt; DEVICE_SECTOR_SIZE) ? DEVICE_SECTOR_SIZE : (uint32_t)remaining;
        if(FlashSpiTransmitReceivePort(NULL, (uint8_t *)fSpiTxBuf, (uint8_t *)fSpiRxBuf, chunk) != RETURN_DEFAULT)
        {
            CS_UN( );
            FALFDB_TRACE("read failed: data rx error off=0x%08X remain=%u\r\n", (unsigned)(addr + copied), (unsigned)remaining);
            return -1;
        }

        for(uint32_t i = 0; i &lt; chunk; i++)
        {
            buf[copied + i] = fSpiRxBuf[i];
        }

        copied += chunk;
        remaining -= chunk;
    }

    CS_UN( );

    return (int)size;
}

static int fal_norflash_write(long offset, const uint8_t *buf, size_t size)
{
    uint32_t addr;
    size_t   remaining;
    size_t   copied;

    if(fal_norflash_wait_idle( ) != RETURN_DEFAULT)
    {
        FALFDB_TRACE("write failed: flash busy before write\r\n");
        return -1;
    }

    addr      = (uint32_t)offset;
    remaining = size;
    copied    = 0;

    while(remaining &gt; 0)
    {
        uint32_t page_offset = addr % FLASH_PAGE_SIZE;
        uint32_t page_room   = FLASH_PAGE_SIZE - page_offset;
        uint32_t prog_len    = (remaining &gt; page_room) ? page_room : (uint32_t)remaining;

        /* 写使能 */
        fSpiTxBuf[0] = CMD_WREN;
        CS_EN( );
        if(FlashSpiTransmitPort(NULL, (uint8_t *)fSpiTxBuf, 1) != RETURN_DEFAULT)
        {
            CS_UN( );
            FALFDB_TRACE("write failed: wren tx error off=0x%08X\r\n", (unsigned)addr);
            return -1;
        }
        CS_UN( );

        /* 页编程命令 + 3字节地址 + 数据 */
        fSpiTxBuf[0] = CMD_PP;
        fSpiTxBuf[1] = (addr &gt;&gt; 16) & 0xFF;
        fSpiTxBuf[2] = (addr &gt;&gt; 8) & 0xFF;
        fSpiTxBuf[3] = addr & 0xFF;
        for(uint32_t i = 0; i &lt; prog_len; i++)
        {
            fSpiTxBuf[4 + i] = buf[copied + i];
        }

        CS_EN( );
        if(FlashSpiTransmitReceivePort(NULL, (uint8_t *)fSpiTxBuf, (uint8_t *)fSpiRxBuf, 4 + prog_len) != RETURN_DEFAULT)
        {
            CS_UN( );
            FALFDB_TRACE("write failed: pp tx error off=0x%08X size=%u\r\n", (unsigned)addr, (unsigned)prog_len);
            return -1;
        }
        CS_UN( );

        if(fal_norflash_wait_idle( ) != RETURN_DEFAULT)
        {
            FALFDB_TRACE("write failed: wait idle timeout off=0x%08X\r\n", (unsigned)addr);
            return -1;
        }

        addr += prog_len;
        copied += prog_len;
        remaining -= prog_len;
    }

    /* 关闭写使能 */
    fSpiTxBuf[0] = CMD_DISWR;
    CS_EN( );
    if(FlashSpiTransmitPort(NULL, (uint8_t *)fSpiTxBuf, 1) != RETURN_DEFAULT)
    {
        CS_UN( );
        FALFDB_TRACE("write warn: diswr tx error\r\n");
        return -1;
    }
    CS_UN( );

    if(fal_norflash_wait_idle( ) != RETURN_DEFAULT)
    {
        FALFDB_TRACE("write failed: flash busy after diswr\r\n");
        return -1;
    }

    return (int)size;
}

static int fal_norflash_erase(long offset, size_t size)
{
    uint32_t addr;
    uint32_t blk_size;
    size_t   remaining;

    blk_size = nor_flash0.blk_size;

    if(fal_norflash_wait_idle( ) != RETURN_DEFAULT)
    {
        FALFDB_TRACE("erase failed: flash busy before erase\r\n");
        return -1;
    }

    addr      = (uint32_t)offset;
    remaining = size;

    while(remaining &gt; 0)
    {
        /* 写使能 */
        fSpiTxBuf[0] = CMD_WREN;
        CS_EN( );
        if(FlashSpiTransmitPort(NULL, (uint8_t *)fSpiTxBuf, 1) != RETURN_DEFAULT)
        {
            CS_UN( );
            FALFDB_TRACE("erase failed: wren tx error off=0x%08X\r\n", (unsigned)addr);
            return -1;
        }
        CS_UN( );

        /* 扇区擦除命令 + 3字节地址 */
        fSpiTxBuf[0] = CMD_SE;
        fSpiTxBuf[1] = (addr &gt;&gt; 16) & 0xFF;
        fSpiTxBuf[2] = (addr &gt;&gt; 8) & 0xFF;
        fSpiTxBuf[3] = addr & 0xFF;

        CS_EN( );
        if(FlashSpiTransmitPort(NULL, (uint8_t *)fSpiTxBuf, 4) != RETURN_DEFAULT)
        {
            CS_UN( );
            FALFDB_TRACE("erase failed: se tx error off=0x%08X\r\n", (unsigned)addr);
            return -1;
        }
        CS_UN( );

        if(fal_norflash_wait_idle( ) != RETURN_DEFAULT)
        {
            FALFDB_TRACE("erase failed: wait idle timeout off=0x%08X\r\n", (unsigned)addr);
            return -1;
        }

        addr += blk_size;
        remaining -= blk_size;
    }

    /* 关闭写使能 */
    fSpiTxBuf[0] = CMD_DISWR;
    CS_EN( );
    if(FlashSpiTransmitPort(NULL, (uint8_t *)fSpiTxBuf, 1) != RETURN_DEFAULT)
    {
        CS_UN( );
        FALFDB_TRACE("erase warn: diswr tx error\r\n");
        return -1;
    }
    CS_UN( );

    if(fal_norflash_wait_idle( ) != RETURN_DEFAULT)
    {
        FALFDB_TRACE("erase failed: flash busy after diswr\r\n");
        return -1;
    }

    return (int)size;
}</code></pre><h1>为工程引入 FlashDB</h1>
<p>有了此前由下至上的引入和支持，现在可以正式处理 FlashDB 的操作流程了。</p>
<p>现在需要处理的主要就是按序初始化了，一个最小的可用初始化顺序为</p>
<pre><code class="language-c">struct fdb_kvdb g_flashdb_kvdb;

int32_t ModuleFlashDBInit(void)
{
    uint32_t  sec_size;

    memset(&g_flashdb_kvdb, 0, sizeof(g_flashdb_kvdb));

    sec_size = (4 * 1024); // 默认单扇区大小;
    fdb_kvdb_control(&g_flashdb_kvdb, FDB_KVDB_CTRL_SET_LOCK, (void *)module_flashdb_lock);
    fdb_kvdb_control(&g_flashdb_kvdb, FDB_KVDB_CTRL_SET_UNLOCK, (void *)module_flashdb_unlock);
    fdb_kvdb_control(&g_flashdb_kvdb, FDB_KVDB_CTRL_SET_SEC_SIZE, &sec_size);

    result = fdb_kvdb_init(&g_flashdb_kvdb, "cfg", FAL_FLASHDB_KV_PART_NAME, NULL, NULL);
    if(result != FDB_NO_ERR)
    {
        FLASHDB_TRACE("init failed: fdb_kvdb_init err=%d\r\n", (int)result);
        return -1;
    }

    return 0;
}</code></pre><p>此后就可以使用这样的原子操作以读写键值</p>
<pre><code class="language-c">    struct fdb_blob blob;
    uint8_t verifyIp[4]   = {192,168,1,100};

    fdb_kv_set_blob(&g_flashdb_kvdb, "lan_ip", fdb_blob_make(&blob, verifyIp, sizeof(verifyIp)));
    fdb_kv_get_blob(&g_flashdb_kvdb, "lan_ip", fdb_blob_make(&blob, verifyIp, sizeof(verifyIp)));</code></pre><h1>需要自己做的包装</h1>
<ol>
<li>依据你的工程框架，可以使用线程锁来额外包装一套 API，以简单支持跨线程的键值读写。</li>
<li>进阶的，在包装中可以额外增加一个读 API 传参，在未命中键时使用默认值返回。类似 esp32 的 Preferences 数据库，<code>int    canBaud   = prefs.getInt(&quot;canbtaud&quot;, 250000);</code>。</li>
<li>更加进阶的，由于 FlashDB 是一套阻塞操作、SPI 收发相当耗时，在线程中直接使用原子操作将导致毫秒级的阻塞，这是不太能接受的。可以采用独立线程和请求队列，专用于管理 FlashDB 的读写操作。在通常的场景，采用异步使得业务逻辑更通顺。而在必须立即读写并获值参与逻辑时，也可以直接调用原子操作。</li>
</ol>

          <p style='text-align: right'>
          <a href='https://www.yono233.cn/posts/novel/flashdb#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383661174829</guid>
  <category>post</category>
<category>禹步</category>
 </item>
  <item>
    <title>C2000 的特殊内存排布</title>
    <link>https://www.yono233.cn/notes/54</link>
    <pubDate>Wed, 22 Apr 2026 06:11:26 GMT</pubDate>
    <description>C2000 DSP 是现代化蝎子粑粑独一份的 16 位字节，所以内存寻址时和通常的 CHAR_BIT</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/notes/54'>https://www.yono233.cn/notes/54</a></blockquote>
          <p>C2000 DSP 是现代化蝎子粑粑独一份的 16 位字节，所以内存寻址时和通常的 CHAR_BIT == 8 不同。</p>
<p>这在协议层到数据零拷贝强转时需要格外注意。过去处理过，今天遇到又忘了，得重新手测。记录一下吧。</p>
<table>
<thead>
<tr>
<th></th>
<th>U32</th>
<th>实际内存排布</th>
</tr>
</thead>
<tbody><tr>
<td>C2000</td>
<td>0x87654321</td>
<td>4321 8765</td>
</tr>
<tr>
<td>通常的8位小端</td>
<td>0x87654321</td>
<td>21 43 65 87</td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th></th>
<th>浮点值</th>
<th>实际内存排布</th>
<th>内存排布对应U32</th>
</tr>
</thead>
<tbody><tr>
<td>C2000</td>
<td>123.456</td>
<td>E979 42F6</td>
<td>0x42F6E979</td>
</tr>
<tr>
<td>通常的8位小端</td>
<td>123.456</td>
<td>79 E9 F6 42</td>
<td>0x42F6E979</td>
</tr>
</tbody></table>
<p>另外其对于取址对齐有很高的要求，32位数据要求地址也是 2 byte 对齐，例子如下。</p>
<pre><code class="language-c">uint16_t buffer[8];

uint32_t t32;

/* 以下两个实际上都会以 [0][1] 取内存转为 u32 */
// 在通常的CPU中，以下会以 [1][2] 取内存转 u32 
t32 = *(uint32_t *)(& buffer[1]); 
// 在通常的CPU中，以下是 [0][1] 正确零拷贝取法
t32 = *(uint32_t *)(& buffer[0]);

/* 以下两个则会以 [2][3] 取内存转为 u32 */
t32 = *(uint32_t *)(& buffer[3]);
t32 = *(uint32_t *)(& buffer[2]);</code></pre>
          <p style='text-align: right'>
          <a href='https://www.yono233.cn/notes/54#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383669563440</guid>
  <category>note</category>
false
 </item>
  <item>
    <title>macOS 搭建 arm-gcc 构建环境</title>
    <link>https://www.yono233.cn/posts/novel/macos-arm-gcc</link>
    <pubDate>Mon, 20 Apr 2026 07:46:47 GMT</pubDate>
    <description>前置条件

mac 常用的包管理器是 brew(Homebrew)，首先需要安装这个环境，后续才好方</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/posts/novel/macos-arm-gcc'>https://www.yono233.cn/posts/novel/macos-arm-gcc</a></blockquote>
          <h1>前置条件</h1>
<p>mac 常用的包管理器是 brew(Homebrew)，首先需要安装这个环境，后续才好方便地安装 mac 中所谓的「命令行工具」。</p>
<p>而安装 brew 又需要<strong>可以访问 GitHub</strong>的前置条件，在 mac 系统中很难使用我最爱的 steam++，那么有两种最简单方法。一是使用最通用的 VPN 方式——clash；二则更简单更小白，使用 UU 加速器就可以，UU 加速器搜索「学术」，即可免费加速。</p>
<p>等确认可以正确访问 GitHub 之后，在终端中使用以下指令。<strong>注意，这个指令最后有提示如何操作 PASH</strong>。</p>
<pre><code class="language-sh">/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"</code></pre><p>安装完成后使用以下指令确认是否安装成功。</p>
<pre><code class="language-sh">brew -v</code></pre><h1>安装编译链和构建工具</h1>
<p>首先安装构建工具，<code>cmake</code> 和 <code>ninja</code>。</p>
<pre><code class="language-sh">brew install cmake ninja</code></pre><p>然后安装编译链，这里有一个问题，arm-gcc 不能直接使用 brew 安装原名包，这样可能是一种 without-headers 变体，缺少很多标准库和头文件。windows 下使用 msys2 管理也有类似这样的问题。</p>
<p>首先尝试卸载原名包和原名工具，如果有旧环境遗留，这一步将很重要。</p>
<pre><code class="language-sh">brew uninstall arm-none-eabi-gcc arm-none-eabi-binutils</code></pre><p>随后安装完整包</p>
<pre><code class="language-sh">brew install --cask gcc-arm-embedded

PKG="$(find "$(brew --caskroom)/gcc-arm-embedded" -name '*.pkg' | head -n 1)"
[ -n "$PKG" ] || { echo "未找到 gcc-arm-embedded 的 pkg"; exit 1; }
installer -pkg "$PKG" -target CurrentUserHomeDirectory

TOOLBIN="$(find "$HOME/Applications/ArmGNUToolchain" -type d -path '*/arm-none-eabi/bin' | sort | tail -n 1)"
[ -n "$TOOLBIN" ] || { echo "未找到 ArmGNUToolchain bin 目录"; exit 1; }
for t in gcc g++ as ar objcopy size gdb nm objdump ranlib readelf strip addr2line gcc-ar gcc-nm gcc-ranlib; do
	ln -sf "$TOOLBIN/arm-none-eabi-$t" "/opt/homebrew/bin/arm-none-eabi-$t"
done</code></pre><p>最后验证完整工具，需要输出包含正确的头文件路径以及类似 stdint 的头文件名。</p>
<pre><code class="language-sh">arm-none-eabi-gcc -v -E -x c - &lt; /dev/null</code></pre><p>然后就可以正常编译项目了</p>
<p></p>

          <p style='text-align: right'>
          <a href='https://www.yono233.cn/posts/novel/macos-arm-gcc#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383661174828</guid>
  <category>post</category>
<category>禹步</category>
 </item>
  <item>
    <title>可能是你需要的第三台笔记本——macbook neo</title>
    <link>https://www.yono233.cn/posts/luxury/macbook-neo</link>
    <pubDate>Sat, 18 Apr 2026 21:15:27 GMT</pubDate>
    <description>总结

依然是总结写在前面，比起正派的高性能笔记本，neo 小姐当然不能胜任过多的工作。

但她确实</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/posts/luxury/macbook-neo'>https://www.yono233.cn/posts/luxury/macbook-neo</a></blockquote>
          <h1>总结</h1>
<p>依然是总结写在前面，比起正派的高性能笔记本，neo 小姐当然不能胜任过多的工作。</p>
<p>但她确实是我需要的<strong>第三台笔记本</strong>，第一台是工作用全能开发笔记本，第二台是出差专用可以随便删裁环境的笔记本。</p>
<p>她是伪装成笔记本的平板，自带支架和键盘，正适合我这样讨厌在触屏上写写画画，非常刚需键盘和触摸板的用户。没有风扇，不吵闹，超高续航，可以在床上毫无负担运行。</p>
<h1>到手</h1>
<p>目前日常叠国补能 3599 拿到，无论狗东、淘宝、并夕夕，大多数平台都能蹲到这个价格。叠教育补贴、以旧换新这些，我不太懂就没管。</p>
<p>这个粉色完全没有想象中精致，那我说真精致还得是 win 本有没有懂的。<a href="https://www.yono233.cn/posts/warning/24_8_5_LG">一台美丽的废物！LG gram style 16</a></p>
<p>而且相当重啊，单手拿捏对我是很大的负担。</p>
<p></p>
<h1>能做什么？</h1>
<h3>可以刷B站</h3>
<p>这就是我急迫拿下 <code>macbook刘奥</code> 的根本原因。我真的很需要一款能在床上侧躺着一路看视频到睡着的工具。作为自带支架的 ipad 模拟器，这台本子确实完美满足我的需求，和我期望中他的生态位没有太大的区别。</p>
<p>在这个价位下，没有风扇，没有通风孔，完整一体所以可以安心放在床上，甚至看起来还是--坚固型计算机--。除了 <code>macbook刘奥</code> 的确没有第二选择。</p>
<p></p>
<h3>可以写博客</h3>
<p>本文就是新的本子编撰。暂时使用 vscode 环境。</p>
<p></p>
<h3>用来写小说吗</h3>
<p>准备拿来写小说，所以安装了 node.js 环境。看起来如此轻量的开发需求，他是完全可以支持的。问题完全不在 neo 小姐，vscode 太吃内存真该死啊。</p>
<p>::: grid {cols=2,gap=4}</p>
<p></p>
<p></p>
<p>:::</p>
<h3>打游戏</h3>
<p>看着 app store 里的陈年游戏，我已经几乎 8 年没有接触 apple 的任何生态了吗。</p>
<p>可能是因为大约八年前苹果发明了世界上最愚蠢的额头摄像头，最愚蠢的灵动岛，这种设计以低成本的优势打垮了市面上所有的伸缩前置摄像头。他是摧毁我最爱的设计的始作俑者，我对果子一直有很大的偏见。</p>
<p>哪怕贫民窟的 neo 小姐使用的是手机级 cpu，但是她依然是高贵的「搭载 Apple 芯片的 Mac」，可以享受到苹果生态运行 ipad app。随便下了一个以前的老游戏，还是可以爽玩的。</p>
<p>我也不期望她的游戏体验，正常人还是会在主机上打游戏的。</p>
<p>::: grid {cols=2,gap=4}</p>
<p></p>
<p></p>
<p>:::</p>
<h3>剪视频</h3>
<p>找了一个样本，体验了一下用剪映剪视频，如果我的使用场景，仅仅是剪一下加点字幕，neo 小姐还是可以胜任的。就是 RAM 太小，导入和导出会有些慢。</p>
<h1>缺陷</h1>
<p>最大的缺陷当然是她真的非常<strong>重</strong>，我将其定义为超轻量的使用场景，但是这个重量真的不轻。</p>
<p>超弱的充电速度，神奇的 20W 充电。</p>
<p>触控板的问题，首先是所有评测都说过的，这是一个阉割特制的触控板，没有重力感应，需要机械按下。另外，我是不太常用<strong>按下</strong>这个操作，我更喜欢多指结合轻点，但是这块触控板的轻点似乎不太灵敏。</p>
<p>另外比较个人化的问题，她真的非常粘烟灰，仅仅是口吹或者干擦拭都弄不干净，必须湿纸巾来擦。</p>
<p>另外就没有其他缺陷了，如果你也需要一个<strong>没有触屏自带键盘和支架的 ipad</strong>，那么将非常合适。</p>

          <p style='text-align: right'>
          <a href='https://www.yono233.cn/posts/luxury/macbook-neo#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383661174827</guid>
  <category>post</category>
<category>千机</category>
 </item>
  <item>
    <title>gitea 的 mail 配置</title>
    <link>https://www.yono233.cn/notes/53</link>
    <pubDate>Wed, 15 Apr 2026 09:17:15 GMT</pubDate>
    <description>部署 gitea 后一直没法自动发送通知邮件，作为未来的合作平台，今天打算解决这个问题。
官方文档或</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/notes/53'>https://www.yono233.cn/notes/53</a></blockquote>
          <p>部署 gitea 后一直没法自动发送通知邮件，作为未来的合作平台，今天打算解决这个问题。
官方文档或者各种中文教程并没有解释清楚，我的应用环境下是在论坛老外的帖子中摸索出的正确配置。</p>
<p>配置段为</p>
<pre><code class="language-">[mailer]
ENABLED        = true
PROTOCOL       = smtps
SMTP_ADDR      = smtp.qq.com
SMTP_PORT      = 465
FROM           = yono233@foxmail.com
USER           = yono233@foxmail.com
PASSWD         = `你不应该知道这个`
ENABLE_HELO    = false</code></pre><p>关键点有三个</p>
<ul>
<li>使用 SMTP，PROTOCOL 不是 smtp 而应该是 smtps</li>
<li>对于 QQ 邮箱，SMTP_PORT 不能配置为 587，而应该使用 465</li>
<li>如果测试邮件报 EOF，需要添加 ENABLE_HELO 字段为 false</li>
<li></li>
</ul>

          <p style='text-align: right'>
          <a href='https://www.yono233.cn/notes/53#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383669563439</guid>
  <category>note</category>
false
 </item>
  <item>
    <title>netxduo 包长一致性问题</title>
    <link>https://www.yono233.cn/notes/52</link>
    <pubDate>Mon, 13 Apr 2026 06:00:08 GMT</pubDate>
    <description>[!NOTE]
由于赶进度，暂时没有分析根因，只是在当前现象下的临时解决方案。
所以作为『手记』发布</description>
    <content:encoded><![CDATA[
      <blockquote>This rendering is produced by marked and may have formatting issues. For the best experience, visit: <a href='https://www.yono233.cn/notes/52'>https://www.yono233.cn/notes/52</a></blockquote>
          <blockquote>
<p>[!NOTE]</p>
<p>由于赶进度，暂时没有分析根因，只是在当前现象下的临时解决方案。</p>
<p>所以作为『手记』发布，后续可能转为『文章』描述根因。</p>
</blockquote>
<p>移植 ST fork 的 netxduo ，未开启任何实际应用，只是基于 Example 开启了基本组件 IP/ICMP/TCP/UDP 。在这样的条件下，用 ping 做 PHY 驱动和物理链路设计的测试，并完善 netxduo 基础设施的移植。</p>
<h2>现象</h2>
<p>在 ping 的过程中，偶发 ping 不通一次，随后 ETH 外设进入 DMA 错误并死掉。</p>
<h2>现象原因</h2>
<p>经过 RTT 插入打印，发现发送时偶尔 append 会小于 prepend，导致计算包长为负数，展现到驱动发送时会是一个超越 DMA 空间的极大值，最终引起 DMA 错误并彻底丧失正确的 DMA 关系。</p>
<pre><code class="language-c">NETX TX ok
NETX ISR: TX complete
NETX ISR: RX complete
NETX RX hw-&gt;stack
NETX RX: type=IPv4(0x0800) len=74
NETX TX: cmd=IP_SEND type=IPv4 len=74
NETX TX ok
NETX ISR: TX complete
NETX ISR: RX complete
NETX RX hw-&gt;stack
NETX RX: type=IPv4(0x0800) len=74
NETX TX: cmd=IP_SEND type=IPv4 len=74
NETX TX invalid seg: append&lt;=prepend pkt=0x2401B610 pre=0x2401B64E app=0x2401B64C len=74
NETX TX fail: hw_send status=90
NETX ISR: RX complete
NETX RX hw-&gt;stack
NETX RX: type=IPv4(0x0800) len=82
RTT:0&gt;</code></pre><h2>简单解决方案</h2>
<p>追溯到 <code>nx\_stm32\_eth\_driver.c</code> 文件的 <code>\_nx\_driver\_hardware\_packet\_send</code> 函数，向下追溯 ping 测试下的数据来源 <code>HAL\_ETH\_RxAllocateCallback</code>，其原版有这样的语句。 <code>packet_ptr-&gt;nx_packet_prepend_ptr += 2;</code> 而没有强制同步 <code>nx_packet_append_ptr</code>，所以可以增加 <code>packet_ptr-&gt;nx_packet_append_ptr = packet_ptr-&gt;nx_packet_prepend_ptr;</code></p>
<p>注意到意外包 <code>pre=0x2401B64E app=0x2401B64C</code> 正好相差 2，也就是对于 0 长度包的接收实际上这里的处理存在问题。</p>
<pre><code class="language-c">void HAL_ETH_RxAllocateCallback(uint8_t **buff)
{
    NX_PACKET *packet_ptr;
    if(nx_packet_allocate(nx_driver_information.nx_driver_information_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_NO_WAIT) == NX_SUCCESS)
    {
      /*** 注意这里 ***/
        /* Adjust the packet.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += 2;
      /*** ***/
        invalidate_cache_by_addr((uint32_t *)packet_ptr-&gt;nx_packet_data_start, packet_ptr-&gt;nx_packet_data_end - packet_ptr-&gt;nx_packet_data_start);
        *buff = packet_ptr-&gt;nx_packet_prepend_ptr;
    }
    else
    {
        ULONG total_packets;
        ULONG free_packets;
        ULONG empty_pool_requests;
        ULONG empty_pool_suspensions;
        ULONG invalid_packet_releases;

        nx_packet_pool_info_get(nx_driver_information.nx_driver_information_packet_pool_ptr, &total_packets, &free_packets, &empty_pool_requests, &empty_pool_suspensions, &invalid_packet_releases);

        /* Rx Buffer Pool is exhausted. */
        NX_NET_TRACE("NETX RX alloc fail: pool exhausted (free=%lu total=%lu empty_req=%lu)\r\n", (unsigned long)free_packets, (unsigned long)total_packets, (unsigned long)empty_pool_requests);
        *buff = NULL;
    }
}</code></pre><p>除了上述  <code>HAL\_ETH\_RxAllocateCallback</code> 中的调整，为接收问题。</p>
<p>调整两种分支下的 <code>_nx_driver_hardware_packet_send</code> 函数，对包长为 0 或者意外极大的情况做特殊处理。不知为何，st 的原版驱动对于 0 长包的处理经常有问题，这是后续可能需要排查的，但是使用以下方案可以临时用着。</p>
<pre><code class="language-c">#ifdef MULTI_QUEUE_FEATURE
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
{
    UINT          status;
    UCHAR         channel_number = 0;

    NX_INTERFACE *interface_ptr;

    interface_ptr = nx_driver_information.nx_driver_information_interface;

    status        = nx_shaper_hw_queue_id_get(interface_ptr, packet_ptr, &channel_number);

    status        = _nx_driver_hardware_packet_send_distribute(packet_ptr, channel_number);

    return status;
}

static UINT _nx_driver_hardware_packet_send_distribute(NX_PACKET *packet_ptr, UINT channel_number)
{
    NX_PACKET               *pktIdx;
    UINT                     buffLen = 0;
    int                      i       = 0;

    static ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];

    memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));

    for(pktIdx = packet_ptr; pktIdx != NX_NULL; pktIdx = pktIdx-&gt;nx_packet_next)
    {
        ULONG seg_len;

        if(i &gt;= ETH_TX_DESC_CNT)
        {
            return NX_DRIVER_ERROR;
        }

        if(pktIdx-&gt;nx_packet_append_ptr &lt; pktIdx-&gt;nx_packet_prepend_ptr)
        {
            NX_NET_TRACE("NETX TX invalid seg: append&lt;prepend pkt=0x%08lX pre=0x%08lX app=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr, (unsigned long)pktIdx-&gt;nx_packet_length);
            return NX_DRIVER_ERROR;
        }

        seg_len = (ULONG)(pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);
        if(seg_len == 0U)
        {
            if((pktIdx-&gt;nx_packet_length &gt; 0U) && (pktIdx-&gt;nx_packet_next == NX_NULL) && (pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length &lt;= pktIdx-&gt;nx_packet_data_end))
            {
                pktIdx-&gt;nx_packet_append_ptr = pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length;
                seg_len                      = pktIdx-&gt;nx_packet_length;
                NX_NET_TRACE("NETX TX repair seg: pkt=0x%08lX repaired_len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)seg_len);
            }
            else
            {
                NX_NET_TRACE("NETX TX skip empty seg: pkt=0x%08lX next=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_next, (unsigned long)pktIdx-&gt;nx_packet_length);
                continue;
            }
        }

        if(seg_len &gt; 0x3FFFU)
        {
            NX_NET_TRACE("NETX TX invalid seg: oversize pkt=0x%08lX seg_len=%lu pre=0x%08lX app=0x%08lX\r\n", (unsigned long)pktIdx, (unsigned long)seg_len, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr);
            return NX_DRIVER_ERROR;
        }

        Txbuffer[i].buffer = pktIdx-&gt;nx_packet_prepend_ptr;
        Txbuffer[i].len    = seg_len;
        buffLen += seg_len;

        if(i &gt; 0)
        {
            Txbuffer[i - 1].next = &Txbuffer[i];
        }

        if(pktIdx-&gt;nx_packet_next == NULL)
        {
            Txbuffer[i].next = NULL;
        }

        i++;
        clean_cache_by_addr((uint32_t *)(pktIdx-&gt;nx_packet_data_start), pktIdx-&gt;nx_packet_data_end - pktIdx-&gt;nx_packet_data_start);
    }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & (NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM))
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    }
    else if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_INSERT;
    }
#else
    TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_DISABLE;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

#ifdef NX_DRIVER_ENABLE_PTP
    /* Enable PTP timestamp */
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_PTP_TIMESTAMP)
    {
        HAL_ETH_PTP_InsertTxTimestamp(&eth_handle);
    }
#endif /* NX_DRIVER_ENABLE_PTP */

    if(buffLen == 0U)
    {
        NX_NET_TRACE("NETX TX invalid: no payload segments after filtering\r\n");
        return NX_DRIVER_ERROR;
    }

    TxPacketCfg.TxDMACh  = channel_number;
    TxPacketCfg.Length   = buffLen;
    TxPacketCfg.TxBuffer = Txbuffer;
    TxPacketCfg.pData    = (uint32_t *)packet_ptr;

    if(HAL_ETH_Transmit_IT(&eth_handle, &TxPacketCfg) != HAL_OK)
        return NX_DRIVER_ERROR;

    return NX_SUCCESS;
}

#else
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
{
    NX_PACKET               *pktIdx;
    UINT                     buffLen = 0;

    static ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
    memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));

    int i = 0;

    for(pktIdx = packet_ptr; pktIdx != NX_NULL; pktIdx = pktIdx-&gt;nx_packet_next)
    {
        ULONG seg_len;

        if(i &gt;= ETH_TX_DESC_CNT)
        {
            return NX_DRIVER_ERROR;
        }

        if(pktIdx-&gt;nx_packet_append_ptr &lt; pktIdx-&gt;nx_packet_prepend_ptr)
        {
            NX_NET_TRACE("NETX TX invalid seg: append&lt;prepend pkt=0x%08lX pre=0x%08lX app=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr, (unsigned long)pktIdx-&gt;nx_packet_length);
            return NX_DRIVER_ERROR;
        }

        seg_len = (ULONG)(pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);
        if(seg_len == 0U)
        {
            if((pktIdx-&gt;nx_packet_length &gt; 0U) && (pktIdx-&gt;nx_packet_next == NX_NULL) && (pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length &lt;= pktIdx-&gt;nx_packet_data_end))
            {
                pktIdx-&gt;nx_packet_append_ptr = pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length;
                seg_len                      = pktIdx-&gt;nx_packet_length;
                NX_NET_TRACE("NETX TX repair seg: pkt=0x%08lX repaired_len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)seg_len);
            }
            else
            {
                NX_NET_TRACE("NETX TX skip empty seg: pkt=0x%08lX next=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_next, (unsigned long)pktIdx-&gt;nx_packet_length);
                continue;
            }
        }

        if(seg_len &gt; 0x3FFFU)
        {
            NX_NET_TRACE("NETX TX invalid seg: oversize pkt=0x%08lX seg_len=%lu pre=0x%08lX app=0x%08lX\r\n", (unsigned long)pktIdx, (unsigned long)seg_len, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr);
            return NX_DRIVER_ERROR;
        }

        Txbuffer[i].buffer = pktIdx-&gt;nx_packet_prepend_ptr;
        Txbuffer[i].len    = seg_len;
        buffLen += seg_len;

        if(i &gt; 0)
        {
            Txbuffer[i - 1].next = &Txbuffer[i];
        }

        if(pktIdx-&gt;nx_packet_next == NULL)
        {
            Txbuffer[i].next = NULL;
        }

        i++;
        clean_cache_by_addr((uint32_t *)(pktIdx-&gt;nx_packet_data_start), pktIdx-&gt;nx_packet_data_end - pktIdx-&gt;nx_packet_data_start);
    }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & (NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM))
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    }
    else if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_INSERT;
    }
#else
    TxPacketCfg.ChecksumCtrl      = ETH_CHECKSUM_DISABLE;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

    if(buffLen == 0U)
    {
        NX_NET_TRACE("NETX TX invalid: no payload segments after filtering\r\n");
        return NX_DRIVER_ERROR;
    }

    TxPacketCfg.Length   = buffLen;
    TxPacketCfg.TxBuffer = Txbuffer;
    TxPacketCfg.pData    = (uint32_t *)packet_ptr;

    if(HAL_ETH_Transmit_IT(&eth_handle, &TxPacketCfg))
    {
        return (NX_DRIVER_ERROR);
    }

    return (NX_SUCCESS);
}
#endif /* MULTI_QUEUE_FEATURE */</code></pre><h2>compare</h2>
&lt;Tabs&gt;
&lt;Tab label="新的 nx_stm32_eth_driver.c 文件"&gt;<pre><code class="language-c/**************************************************************************/">/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/

/* Indicate that driver source is being compiled.  */

#define NX_DRIVER_SOURCE

/****** DRIVER SPECIFIC ****** Start of part/vendor specific include area.  Include driver-specific include file here!  */

#ifndef NX_STM32_ETH_DRIVER_H

/* Determine if the driver uses IP deferred processing or direct ISR processing.  */

#define NX_DRIVER_ENABLE_DEFERRED /* Define this to enable deferred ISR processing.  */

/* Include driver specific include file.  */
#include "nx_stm32_eth_driver.h"

/* Include the phy driver header */
#include "nx_stm32_phy_driver.h"
#include "SEGGER_RTT.h"

#endif /* NX_STM32_ETH_DRIVER_H */

#ifndef NX_NET_RTT_TRACE
#define NX_NET_RTT_TRACE 1
#endif

#if NX_NET_RTT_TRACE
#define NX_NET_TRACE(...) SEGGER_RTT_printf(0, __VA_ARGS__)
static const char *nx_eth_type_to_str(USHORT ether_type)
{
    if(ether_type == NX_DRIVER_ETHERNET_ARP)
    {
        return "ARP";
    }
    if(ether_type == NX_DRIVER_ETHERNET_RARP)
    {
        return "RARP";
    }
    if(ether_type == NX_DRIVER_ETHERNET_IP)
    {
        return "IPv4";
    }
    if(ether_type == NX_DRIVER_ETHERNET_IPV6)
    {
        return "IPv6";
    }
    return "OTHER";
}

static const char *nx_cmd_to_str(UINT cmd)
{
    if(cmd == NX_LINK_ARP_SEND)
    {
        return "ARP_SEND";
    }
    if(cmd == NX_LINK_ARP_RESPONSE_SEND)
    {
        return "ARP_REPLY";
    }
    if(cmd == NX_LINK_RARP_SEND)
    {
        return "RARP_SEND";
    }
    if(cmd == NX_LINK_PACKET_SEND)
    {
        return "IP_SEND";
    }
    if(cmd == NX_LINK_RAW_PACKET_SEND)
    {
        return "RAW_SEND";
    }
    return "OTHER_SEND";
}

static void nx_dump_tx_desc_snapshot(const ETH_HandleTypeDef *heth)
{
    uint32_t i;

    NX_NET_TRACE("NETX TXDUMP: cur=%lu rel=%lu inuse=%lu cur_pkt=0x%08lX dmacsr=0x%08lX\r\n",
                 (unsigned long)heth-&gt;TxDescList.CurTxDesc,
                 (unsigned long)heth-&gt;TxDescList.releaseIndex,
                 (unsigned long)heth-&gt;TxDescList.BuffersInUse,
                 (unsigned long)heth-&gt;TxDescList.CurrentPacketAddress,
                 (unsigned long)heth-&gt;Instance-&gt;DMACSR);

    for(i = 0; i &lt; ETH_TX_DESC_CNT; i++)
    {
        const ETH_DMADescTypeDef *desc = &heth-&gt;Init.TxDesc[i];
        const uint32_t            own  = ((desc-&gt;DESC3 & ETH_DMATXNDESCRF_OWN) != 0U) ? 1U : 0U;
        const uint32_t            fd   = ((desc-&gt;DESC3 & ETH_DMATXNDESCRF_FD) != 0U) ? 1U : 0U;
        const uint32_t            ld   = ((desc-&gt;DESC3 & ETH_DMATXNDESCRF_LD) != 0U) ? 1U : 0U;
        const uint32_t            b1l  = (desc-&gt;DESC2 & ETH_DMATXNDESCRF_B1L);
        const uint32_t            b2l  = (desc-&gt;DESC2 & ETH_DMATXNDESCRF_B2L) &gt;&gt; 16;

        NX_NET_TRACE("NETX TXD[%lu] D0=%08lX D1=%08lX D2=%08lX D3=%08lX own=%lu fd=%lu ld=%lu b1l=%lu b2l=%lu pkt=0x%08lX\r\n",
                     (unsigned long)i,
                     (unsigned long)desc-&gt;DESC0,
                     (unsigned long)desc-&gt;DESC1,
                     (unsigned long)desc-&gt;DESC2,
                     (unsigned long)desc-&gt;DESC3,
                     (unsigned long)own,
                     (unsigned long)fd,
                     (unsigned long)ld,
                     (unsigned long)b1l,
                     (unsigned long)b2l,
                     (unsigned long)heth-&gt;TxDescList.PacketAddress[i]);
    }
}
#else
#define NX_NET_TRACE(...)
#endif

/****** DRIVER SPECIFIC ****** End of part/vendor specific include file area!  */

/* Define the driver information structure that is only available within this file.  */
static NX_DRIVER_INFORMATION nx_driver_information __attribute__((section(".NxDriverInfo"), aligned(32)));

/* Rounded header size */
static ULONG               header_size;

ETH_TxPacketConfigTypeDef  TxPacketCfg;
ETH_MACFilterConfigTypeDef FilterConfig;
USHORT                     packet_type;

#ifdef NX_DRIVER_ENABLE_PTP
TIMESTAMP_CALLBACK timestamp_callback = NULL;
#define HAL_PTP_TIMEOUT 0xFU
#define PTP_REF_CLK     50000000UL
#endif
/****** DRIVER SPECIFIC ****** Start of part/vendor specific data area.  Include hardware-specific data here!  */

/****** DRIVER SPECIFIC ****** End of part/vendor specific data area!  */

/* Define the routines for processing each driver entry request.  The contents of these routines will change with
each driver. However, the main driver entry function will not change, except for the entry function name.  */

static VOID _nx_driver_interface_attach(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_initialize(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_enable(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_disable(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_multicast_join(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_multicast_leave(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_get_status(NX_IP_DRIVER *driver_req_ptr);
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
static VOID _nx_driver_capability_get(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_capability_set(NX_IP_DRIVER *driver_req_ptr);
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

static VOID _nx_driver_deferred_processing(NX_IP_DRIVER *driver_req_ptr);

#ifdef NX_DRIVER_ENABLE_PTP
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr, ULONG *ptp_ts_ptr);
#else
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
#endif /* NX_DRIVER_ENABLE_PTP */

/* Define the prototypes for the hardware implementation of this driver. The contents of these routines are
driver-specific.  */

static UINT _nx_driver_hardware_initialize(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_enable(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_disable(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr);
#ifdef MULTI_QUEUE_FEATURE
static UINT _nx_driver_hardware_packet_send_distribute(NX_PACKET *packet_ptr, UINT queue_number);
#endif
static UINT _nx_driver_hardware_multicast_join(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_multicast_leave(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_get_status(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_hardware_packet_received(VOID);
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
static UINT _nx_driver_hardware_capability_set(NX_IP_DRIVER *driver_req_ptr);
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    nx_stm32_eth_driver                                                 */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This is the entry point of the NetX Ethernet Driver. This driver    */
/*    function is responsible for initializing the Ethernet controller,   */
/*    enabling or disabling the controller as need, preparing             */
/*    a packet for transmission, and getting status information.          */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        The driver request from the   */
/*                                            IP layer.                   */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_interface_attach           Process attach request        */
/*    _nx_driver_initialize                 Process initialize request    */
/*    _nx_driver_enable                     Process link enable request   */
/*    _nx_driver_disable                    Process link disable request  */
/*    _nx_driver_packet_send                Process send packet requests  */
/*    _nx_driver_multicast_join             Process multicast join request*/
/*    _nx_driver_multicast_leave            Process multicast leave req   */
/*    _nx_driver_get_status                 Process get status request    */
/*    _nx_driver_deferred_processing        Drive deferred processing     */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    IP layer                                                            */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
/****** DRIVER SPECIFIC ****** Start of part/vendor specific global driver entry function name.  */
VOID nx_stm32_eth_driver(NX_IP_DRIVER *driver_req_ptr)
/****** DRIVER SPECIFIC ****** End of part/vendor specific global driver entry function name.  */
{
#ifdef NX_ENABLE_VLAN
    NX_INTERFACE *interface_ptr;
#endif /* NX_ENABLE_VLAN */

    /* Default to successful return.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;

#ifdef NX_ENABLE_VLAN
    /* Let link layer to preprocess the driver request and return actual interface.  */
    if(nx_link_driver_request_preprocess(driver_req_ptr, &interface_ptr) != NX_SUCCESS)
    {
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }
#endif /* NX_ENABLE_VLAN */

    /* Process according to the driver request type in the IP control
  block.  */
    switch(driver_req_ptr-&gt;nx_ip_driver_command)
    {
    case NX_LINK_INTERFACE_ATTACH:

        /* Process link interface attach requests.  */
        _nx_driver_interface_attach(driver_req_ptr);
        break;

    case NX_LINK_INITIALIZE:
        {
            /* Process link initialize requests.  */
            _nx_driver_initialize(driver_req_ptr);
            break;
        }

    case NX_LINK_ENABLE:
        {
            /* Process link enable requests.  */
            _nx_driver_enable(driver_req_ptr);
            break;
        }

    case NX_LINK_DISABLE:
        {
            /* Process link disable requests.  */
            _nx_driver_disable(driver_req_ptr);
            break;
        }

    case NX_LINK_ARP_SEND:
    case NX_LINK_ARP_RESPONSE_SEND:
    case NX_LINK_PACKET_BROADCAST:
    case NX_LINK_RARP_SEND:
    case NX_LINK_PACKET_SEND:
    case NX_LINK_RAW_PACKET_SEND:
        {
            /* Process packet send requests.  */
            _nx_driver_packet_send(driver_req_ptr);
            break;
        }

    case NX_LINK_MULTICAST_JOIN:
        {
            /* Process multicast join requests.  */
            _nx_driver_multicast_join(driver_req_ptr);
            break;
        }

    case NX_LINK_MULTICAST_LEAVE:
        {
            /* Process multicast leave requests.  */
            _nx_driver_multicast_leave(driver_req_ptr);
            break;
        }

    case NX_LINK_GET_STATUS:
        {
            /* Process get status requests.  */
            _nx_driver_get_status(driver_req_ptr);
            break;
        }

    case NX_LINK_DEFERRED_PROCESSING:
        {
            /* Process driver deferred requests.  */

            /* Process a device driver function on behave of the IP thread. */
            _nx_driver_deferred_processing(driver_req_ptr);

            break;
        }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    case NX_INTERFACE_CAPABILITY_GET:
        {
            /* Process get capability requests.  */
            _nx_driver_capability_get(driver_req_ptr);
            break;
        }

    case NX_INTERFACE_CAPABILITY_SET:
        {
            /* Process set capability requests.  */
            _nx_driver_capability_set(driver_req_ptr);
            break;
        }
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

    default:

        /* Invalid driver request.  */

        /* Return the unhandled command status.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_UNHANDLED_COMMAND;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_interface_attach                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the interface attach request.              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_interface_attach(NX_IP_DRIVER *driver_req_ptr)
{
    /* Setup the driver's interface.  This example is for a simple one-interface
  Ethernet driver. Additional logic is necessary for multiple port devices.  */
    nx_driver_information.nx_driver_information_interface = driver_req_ptr-&gt;nx_ip_driver_interface;

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    driver_req_ptr-&gt;nx_ip_driver_interface-&gt;nx_interface_capability_flag = NX_DRIVER_CAPABILITY;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

    /* Return successful status.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_initialize                                               */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the initialize request.  The processing    */
/*    in this function is generic. All ethernet controller logic is to    */
/*    be placed in _nx_driver_hardware_initialize.                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_initialize        Process initialize request    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_initialize(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP        *ip_ptr;
    NX_INTERFACE *interface_ptr;
    UINT          status;
    CHAR         *payload_address;    /* Address of the first payload*/
    VOID         *rounded_pool_start; /* Rounded stating address     */

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* Setup interface pointer.  */
    interface_ptr = driver_req_ptr-&gt;nx_ip_driver_interface;

    /* Initialize the driver's information structure.  */

    /* Default IP pointer to NULL.  */
    nx_driver_information.nx_driver_information_ip_ptr = NX_NULL;

    /* Setup the driver state to not initialized.  */
    nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_NOT_INITIALIZED;

    /* Setup the default packet pool for the driver's received packets.  */
    nx_driver_information.nx_driver_information_packet_pool_ptr = ip_ptr-&gt;nx_ip_default_packet_pool;

    /* Get the rounded start pool start. */
    rounded_pool_start = nx_driver_information.nx_driver_information_packet_pool_ptr-&gt;nx_packet_pool_start;

    /* Calculate the address of payload. */
    payload_address = (CHAR *)((ALIGN_TYPE)rounded_pool_start + sizeof(NX_PACKET));

    /* Align the address of payload. */
    payload_address = (CHAR *)((((ALIGN_TYPE)payload_address + NX_PACKET_ALIGNMENT - 1) / NX_PACKET_ALIGNMENT) * NX_PACKET_ALIGNMENT);

    /* Calculate the header size. */
    header_size = (ULONG)((ALIGN_TYPE)payload_address - (ALIGN_TYPE)rounded_pool_start);

    /* Clear the deferred events for the driver.  */
    nx_driver_information.nx_driver_information_deferred_events = 0;

    /* Call the hardware-specific ethernet controller initialization.  */
    status = _nx_driver_hardware_initialize(driver_req_ptr);

    /* Determine if the request was successful.  */
    if(status == NX_SUCCESS)
    {
        /* Successful hardware initialization.  */

        /* Setup driver information to point to IP pointer.  */
        nx_driver_information.nx_driver_information_ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

        /* Setup the link maximum transfer unit. */
        interface_ptr-&gt;nx_interface_ip_mtu_size = NX_DRIVER_ETHERNET_MTU - NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Setup the physical address of this IP instance.  Increment the
    physical address lsw to simulate multiple nodes hanging on the
    ethernet.  */
        interface_ptr-&gt;nx_interface_physical_address_msw = (ULONG)((eth_handle.Init.MACAddr[0] &lt;&lt; 8) | (eth_handle.Init.MACAddr[1]));
        interface_ptr-&gt;nx_interface_physical_address_lsw = (ULONG)((eth_handle.Init.MACAddr[2] &lt;&lt; 24) | (eth_handle.Init.MACAddr[3] &lt;&lt; 16) | (eth_handle.Init.MACAddr[4] &lt;&lt; 8) | (eth_handle.Init.MACAddr[5]));

        /* Indicate to the IP software that IP to physical mapping
    is required.  */
        interface_ptr-&gt;nx_interface_address_mapping_needed = NX_TRUE;

        /* Move the driver's state to initialized.  */
        nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_INITIALIZED;

        /* Indicate successful initialize.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
    else
    {
        /* Initialization failed.  Indicate that the request failed.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_enable                                                   */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the initialize request. The processing     */
/*    in this function is generic. All ethernet controller logic is to    */
/*    be placed in _nx_driver_hardware_enable.                            */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_enable            Process enable request        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_enable(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP               *ip_ptr;
    ETH_MACConfigTypeDef MACConf;
    UINT                 status, duplex, speed = 0;
    INT                  PHYLinkState;
    uint32_t             tickstart;

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* See if we can honor the NX_LINK_ENABLE request.  */
    if(nx_driver_information.nx_driver_information_state &lt; NX_DRIVER_STATE_INITIALIZED)
    {
        /* Mark the request as not successful.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }

    /* Check if it is enabled by someone already */
    if(nx_driver_information.nx_driver_information_state &gt;= NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* Yes, the request has already been made.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_ALREADY_ENABLED;
        return;
    }

    if(nx_eth_phy_init( ) != ETH_PHY_STATUS_OK)
    {
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }

    tickstart = HAL_GetTick( );

    do
    {
        PHYLinkState = nx_eth_phy_get_link_state( );
    }
    while((PHYLinkState &lt;= ETH_PHY_STATUS_LINK_DOWN) && ((HAL_GetTick( ) - tickstart) &lt; PHY_LINK_TIMEOUT));

    /* Get link state */
    if(PHYLinkState &lt;= ETH_PHY_STATUS_LINK_DOWN)
    {
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }
    else
    {
        switch(PHYLinkState)
        {
#if defined(ETH_PHY_1000MBITS_SUPPORTED)
        case ETH_PHY_STATUS_1000MBITS_FULLDUPLEX:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_1000M;
            break;
        case ETH_PHY_STATUS_1000MBITS_HALFDUPLEX:
            duplex = ETH_HALFDUPLEX_MODE;
            speed  = ETH_SPEED_1000M;
            break;
#endif
        case ETH_PHY_STATUS_100MBITS_FULLDUPLEX:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_100M;
            break;
        case ETH_PHY_STATUS_100MBITS_HALFDUPLEX:
            duplex = ETH_HALFDUPLEX_MODE;
            speed  = ETH_SPEED_100M;
            break;
        case ETH_PHY_STATUS_10MBITS_FULLDUPLEX:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_10M;
            break;
        case ETH_PHY_STATUS_10MBITS_HALFDUPLEX:
            duplex = ETH_HALFDUPLEX_MODE;
            speed  = ETH_SPEED_10M;
            break;
        default:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_100M;
            break;
        }

        /* Get MAC Config MAC */
        HAL_ETH_GetMACConfig(&eth_handle, &MACConf);
        MACConf.DuplexMode = duplex;
        MACConf.Speed      = speed;
#if defined(ETH_DMASBMR_BLEN4) /* ETH AXI support*/
        if(speed == ETH_SPEED_1000M)
            MACConf.PortSelect = DISABLE;
        else
            MACConf.PortSelect = ENABLE;
#endif
        HAL_ETH_SetMACConfig(&eth_handle, &MACConf);
        NX_NET_TRACE("NETX LINK up: phy_state=%ld mac_speed=%lu mac_duplex=%lu\r\n", (long)PHYLinkState, (unsigned long)speed, (unsigned long)duplex);
    }

    /* Call hardware specific enable.  */
    status = _nx_driver_hardware_enable(driver_req_ptr);

    /* Was the hardware enable successful?  */
    if(status == NX_SUCCESS)
    {
        /* Update the driver state to link enabled.  */
        nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_LINK_ENABLED;

        /* Mark request as successful.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;

        /* Mark the IP instance as link up.  */
        ip_ptr-&gt;nx_ip_driver_link_up = NX_TRUE;
    }
    else
    {
        /* Enable failed.  Indicate that the request failed.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_disable                                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the disable request. The processing        */
/*    in this function is generic. All ethernet controller logic is to    */
/*    be placed in _nx_driver_hardware_disable.                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_disable           Process disable request       */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_disable(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP *ip_ptr;
    UINT   status;

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* Check if the link is enabled.  */
    if(nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* The link is not enabled, so just return an error.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }

    /* Call hardware specific disable.  */
    status = _nx_driver_hardware_disable(driver_req_ptr);

    /* Was the hardware disable successful?  */
    if(status == NX_SUCCESS)
    {
        /* Mark the IP instance as link down.  */
        ip_ptr-&gt;nx_ip_driver_link_up = NX_FALSE;

        /* Update the driver state back to initialized.  */
        nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_INITIALIZED;

        /* Mark request as successful.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
    else
    {
        /* Disable failed, return an error.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_packet_send                                              */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the packet send request. The processing    */
/*    in this function is generic. All ethernet controller packet send    */
/*    logic is to be placed in _nx_driver_hardware_packet_send.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_packet_send       Process packet send request   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
#ifdef MULTI_QUEUE_FEATURE
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr)
{
    NX_PACKET *packet_ptr;
    UINT       status;
    USHORT     ether_type;
    NX_INTERFACE
    *interface_ptr;

    /* Check to make sure the link is up.  */
    if(nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* Inidate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(driver_req_ptr-&gt;nx_ip_driver_packet);
        return;
    }

    interface_ptr = driver_req_ptr-&gt;nx_ip_driver_interface;

    /* Process driver send packet.  */

    /* Place the ethernet frame at the front of the packet.  */
    packet_ptr = driver_req_ptr-&gt;nx_ip_driver_packet;

    if(driver_req_ptr-&gt;nx_ip_driver_command != NX_LINK_RAW_PACKET_SEND)
    {
        /* Get Ethernet type.  */
        switch(driver_req_ptr-&gt;nx_ip_driver_command)
        {
        case NX_LINK_ARP_SEND:
        case NX_LINK_ARP_RESPONSE_SEND:
            {
                ether_type = NX_DRIVER_ETHERNET_ARP;
                break;
            }
        case NX_LINK_RARP_SEND:
            {
                ether_type = NX_DRIVER_ETHERNET_RARP;
                break;
            }
        default:
            {
                if(packet_ptr-&gt;nx_packet_ip_version == 4)
                {
                    ether_type = NX_DRIVER_ETHERNET_IP;
                }
                else
                {
                    ether_type = NX_DRIVER_ETHERNET_IPV6;
                }
                break;
            }
        }

        /* Add Ethernet header.  */
        if(nx_link_ethernet_header_add(nx_driver_information.nx_driver_information_ip_ptr, interface_ptr-&gt;nx_interface_index, packet_ptr, driver_req_ptr-&gt;nx_ip_driver_physical_address_msw, driver_req_ptr-&gt;nx_ip_driver_physical_address_lsw, ether_type))
        {
            /* Release the packet.  */
            NX_NET_TRACE("NETX TX drop: header_add failed, cmd=%s\r\n", nx_cmd_to_str(driver_req_ptr-&gt;nx_ip_driver_command));
            nx_packet_transmit_release(packet_ptr);
            return;
        }

        NX_NET_TRACE("NETX TX: cmd=%s type=%s len=%lu\r\n", nx_cmd_to_str(driver_req_ptr-&gt;nx_ip_driver_command), nx_eth_type_to_str(ether_type), (unsigned long)packet_ptr-&gt;nx_packet_length);
    }

    /* Transmit the packet through the Ethernet controller low level access routine. */
    status = _nx_driver_hardware_packet_send(packet_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Driver's hardware send packet routine failed to send the packet.  */

        /* Remove the Ethernet header.  */
        NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

        /* Indicate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        NX_NET_TRACE("NETX TX fail: hw_send status=%u\r\n", (unsigned)status);
        nx_packet_transmit_release(packet_ptr);
    }
    else
    {
        /* Set the status of the request.  */
        NX_NET_TRACE("NETX TX ok\r\n");
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}
#else
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP     *ip_ptr;
    NX_PACKET *packet_ptr;
    ULONG     *ethernet_frame_ptr;
    UINT       status;

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* Check to make sure the link is up.  */
    if(nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* Inidate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(driver_req_ptr-&gt;nx_ip_driver_packet);
        return;
    }

    /* Process driver send packet.  */

    /* Place the ethernet frame at the front of the packet.  */
    packet_ptr = driver_req_ptr-&gt;nx_ip_driver_packet;

    /* Adjust the prepend pointer.  */
    packet_ptr-&gt;nx_packet_prepend_ptr = packet_ptr-&gt;nx_packet_prepend_ptr - NX_DRIVER_ETHERNET_FRAME_SIZE;

    /* Adjust the packet length.  */
    packet_ptr-&gt;nx_packet_length = packet_ptr-&gt;nx_packet_length + NX_DRIVER_ETHERNET_FRAME_SIZE;

    /* Setup the ethernet frame pointer to build the ethernet frame.  Backup another 2
  * bytes to get 32-bit word alignment.  */
    ethernet_frame_ptr = (ULONG *)(packet_ptr-&gt;nx_packet_prepend_ptr - 2);

    /* Set up the hardware addresses in the Ethernet header. */
    *ethernet_frame_ptr       = driver_req_ptr-&gt;nx_ip_driver_physical_address_msw;
    *(ethernet_frame_ptr + 1) = driver_req_ptr-&gt;nx_ip_driver_physical_address_lsw;

    *(ethernet_frame_ptr + 2) = (ip_ptr-&gt;nx_ip_arp_physical_address_msw &lt;&lt; 16) | (ip_ptr-&gt;nx_ip_arp_physical_address_lsw &gt;&gt; 16);
    *(ethernet_frame_ptr + 3) = (ip_ptr-&gt;nx_ip_arp_physical_address_lsw &lt;&lt; 16);

    /* Set up the frame type field in the Ethernet harder. */
    if((driver_req_ptr-&gt;nx_ip_driver_command == NX_LINK_ARP_SEND) || (driver_req_ptr-&gt;nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND))
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_ARP;
    }
    else if(driver_req_ptr-&gt;nx_ip_driver_command == NX_LINK_RARP_SEND)
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_RARP;
    }

#ifdef FEATURE_NX_IPV6
    else if(packet_ptr-&gt;nx_packet_ip_version == NX_IP_VERSION_V6)
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_IPV6;
    }
#endif /* FEATURE_NX_IPV6 */

    else
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_IP;
    }

    NX_NET_TRACE("NETX TX: cmd=%s type=%s len=%lu\r\n", nx_cmd_to_str(driver_req_ptr-&gt;nx_ip_driver_command), nx_eth_type_to_str((USHORT)(*(ethernet_frame_ptr + 3) & 0xFFFFU)), (unsigned long)packet_ptr-&gt;nx_packet_length);

    /* Endian swapping if NX_LITTLE_ENDIAN is defined.  */
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 1));
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 2));
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 3));

    /* Determine if the packet exceeds the driver's MTU.  */
    if(packet_ptr-&gt;nx_packet_length &gt; NX_DRIVER_ETHERNET_MTU)
    {
        /* This packet exceeds the size of the driver's MTU. Simply throw it away! */

        /* Remove the Ethernet header.  */
        NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

        /* Indicate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(packet_ptr);
        return;
    }

    /* Transmit the packet through the Ethernet controller low level access routine. */
    status = _nx_driver_hardware_packet_send(packet_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Driver's hardware send packet routine failed to send the packet.  */

        /* Remove the Ethernet header.  */
        NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

        /* Indicate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        NX_NET_TRACE("NETX TX fail: hw_send status=%u\r\n", (unsigned)status);
        nx_packet_transmit_release(packet_ptr);
    }
    else
    {
        /* Set the status of the request.  */
        NX_NET_TRACE("NETX TX ok\r\n");
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}
#endif

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_multicast_join                                           */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the multicast join request. The processing */
/*    in this function is generic. All ethernet controller multicast join */
/*    logic is to be placed in _nx_driver_hardware_multicast_join.        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_multicast_join    Process multicast join request*/
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_multicast_join(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific multicast join function. */
    status = _nx_driver_hardware_multicast_join(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_multicast_leave                                          */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the multicast leave request. The           */
/*    processing in this function is generic. All ethernet controller     */
/*    multicast leave logic is to be placed in                            */
/*    _nx_driver_hardware_multicast_leave.                                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_multicast_leave   Process multicast leave req   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_multicast_leave(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific multicast leave function. */
    status = _nx_driver_hardware_multicast_leave(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_get_status                                               */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the get status request. The processing     */
/*    in this function is generic. All ethernet controller get status     */
/*    logic is to be placed in _nx_driver_hardware_get_status.            */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_get_status        Process get status request    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_get_status(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific get status function. */
    status = _nx_driver_hardware_get_status(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_capability_get                                           */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the get capability request.                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_capability_get(NX_IP_DRIVER *driver_req_ptr)
{
    /* Return the capability of the Ethernet controller.  */
    *(driver_req_ptr-&gt;nx_ip_driver_return_ptr) = NX_DRIVER_CAPABILITY;

    /* Return the success status.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_capability_set                                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the set capability request.                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_capability_set(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific get status function. */
    status = _nx_driver_hardware_capability_set(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_deferred_processing                                      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    XC, Microsoft Corporation                                           */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the deferred ISR action within the context */
/*    of the IP thread.                                                   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_packet_transmitted        Clean up after transmission    */
/*    _nx_driver_packet_received           Process a received packet      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_deferred_processing(NX_IP_DRIVER *driver_req_ptr)
{
    TX_INTERRUPT_SAVE_AREA

    ULONG deferred_events;
#ifdef MULTI_QUEUE_FEATURE
    ULONG buff_in_use;
#endif
    /* Disable interrupts.  */
    TX_DISABLE

    /* Pickup deferred events.  */
    deferred_events                                             = nx_driver_information.nx_driver_information_deferred_events;
    nx_driver_information.nx_driver_information_deferred_events = 0;

    /* Restore interrupts.  */
    TX_RESTORE

#ifdef MULTI_QUEUE_FEATURE
    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH0)
    {
        eth_handle.TxOpCH = ETH_DMA_CH0_IDX;
        buff_in_use       = HAL_ETH_GetTxBuffersNumber(&eth_handle);

        if(buff_in_use &gt;= NX_DRIVER_TX_RELEASE_THRESHOLD)
        {
            HAL_ETH_ReleaseTxPacket(&eth_handle);
            nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use[ETH_DMA_CH0_IDX] = buff_in_use;
        }
    }

    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH1)
    {
        eth_handle.TxOpCH = ETH_DMA_CH1_IDX;
        buff_in_use       = HAL_ETH_GetTxBuffersNumber(&eth_handle);

        if(buff_in_use &gt;= NX_DRIVER_TX_RELEASE_THRESHOLD)
        {
            HAL_ETH_ReleaseTxPacket(&eth_handle);
            nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use[ETH_DMA_CH1_IDX] = buff_in_use;
        }
    }

    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH0)
    {
        eth_handle.RxOpCH = ETH_DMA_CH0_IDX;
        _nx_driver_hardware_packet_received( );
    }

    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH1)
    {
        eth_handle.RxOpCH = ETH_DMA_CH1_IDX;
        _nx_driver_hardware_packet_received( );
    }

#else
    /* Check for a transmit complete event.  */
    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_TRANSMITTED)
    {
        /* Process transmitted packet(s).  */
        HAL_ETH_ReleaseTxPacket(&eth_handle);
    }
    /* Check for received packet.  */
    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_RECEIVED)
    {
        /* Process received packet(s).  */
        _nx_driver_hardware_packet_received( );
    }
#endif
    /* Mark request as successful.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
}

#ifdef NX_DRIVER_ENABLE_PTP
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_transfer_to_netx                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing incoming packets.  This routine would      */
/*    be called from the driver-specific receive packet processing        */
/*    function _nx_driver_hardware.                                       */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ip_ptr                                Pointer to IP protocol block  */
/*    packet_ptr                            Packet pointer                */
/*    ptp_ts_ptr                            PTP timestamp pointer         */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Error indication                                                    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_ip_packet_receive                 NetX IP packet receive        */
/*    _nx_ip_packet_deferred_receive        NetX IP packet receive        */
/*    _nx_arp_packet_deferred_receive       NetX ARP packet receive       */
/*    _nx_rarp_packet_deferred_receive      NetX RARP packet receive      */
/*    _nx_packet_release                    Release packet                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_hardware_packet_received   Driver packet receive function*/
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr, ULONG *ptp_ts_ptr)
{
    NX_LINK_TIME link_time;

    link_time.nano_second = ptp_ts_ptr[0];
    link_time.second_high = 0;
    link_time.second_low  = ptp_ts_ptr[1];

    nx_link_ethernet_packet_received(ip_ptr, nx_driver_information.nx_driver_information_interface-&gt;nx_interface_index, packet_ptr, &link_time);
}
#else
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_transfer_to_netx                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing incoming packets.  This routine would      */
/*    be called from the driver-specific receive packet processing        */
/*    function _nx_driver_hardware.                              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ip_ptr                                Pointer to IP protocol block  */
/*    packet_ptr                            Packet pointer                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Error indication                                                    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_ip_packet_receive                 NetX IP packet receive        */
/*    _nx_ip_packet_deferred_receive        NetX IP packet receive        */
/*    _nx_arp_packet_deferred_receive       NetX ARP packet receive       */
/*    _nx_rarp_packet_deferred_receive      NetX RARP packet receive      */
/*    _nx_packet_release                    Release packet                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_hardware_packet_received   Driver packet receive function*/
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
{
    /* Set the interface for the incoming packet.  */
    packet_ptr-&gt;nx_packet_ip_interface = nx_driver_information.nx_driver_information_interface;

    /* Pickup the packet header to determine where the packet needs to be
  sent.  */
    packet_type = (USHORT)(((UINT)(*(packet_ptr-&gt;nx_packet_prepend_ptr + 12))) &lt;&lt; 8) | ((UINT)(*(packet_ptr-&gt;nx_packet_prepend_ptr + 13)));
    NX_NET_TRACE("NETX RX: type=%s(0x%04X) len=%lu\r\n", nx_eth_type_to_str(packet_type), (unsigned)packet_type, (unsigned long)packet_ptr-&gt;nx_packet_length);

    /* Route the incoming packet according to its ethernet type.  */
    if(packet_type == NX_DRIVER_ETHERNET_IP || packet_type == NX_DRIVER_ETHERNET_IPV6)
    {
        /* Note:  The length reported by some Ethernet hardware includes
    bytes after the packet as well as the Ethernet header.  In some
    cases, the actual packet length after the Ethernet header should
    be derived from the length in the IP header (lower 16 bits of
    the first 32-bit word).  */

        /* Clean off the Ethernet header.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Adjust the packet length.  */
        packet_ptr-&gt;nx_packet_length -= NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Route to the ip receive function.  */
        _nx_ip_packet_deferred_receive(ip_ptr, packet_ptr);
    }
    else if(packet_type == NX_DRIVER_ETHERNET_ARP)
    {
        /* Clean off the Ethernet header.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Adjust the packet length.  */
        packet_ptr-&gt;nx_packet_length -= NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Route to the ARP receive function.  */
        _nx_arp_packet_deferred_receive(ip_ptr, packet_ptr);
    }
    else if(packet_type == NX_DRIVER_ETHERNET_RARP)
    {
        /* Clean off the Ethernet header.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Adjust the packet length.  */
        packet_ptr-&gt;nx_packet_length -= NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Route to the RARP receive function.  */
        _nx_rarp_packet_deferred_receive(ip_ptr, packet_ptr);
    }
    else
    {
        /* Invalid ethernet header... release the packet.  */
        NX_NET_TRACE("NETX RX drop: unknown ethertype=0x%04X\r\n", (unsigned)packet_type);
        nx_packet_release(packet_ptr);
    }
}
#endif /* NX_DRIVER_ENABLE_PTP */

/****** DRIVER SPECIFIC ****** Start of part/vendor specific internal driver functions.  */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_initialize                                      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific initialization.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ETH_BSP_Config                        Configure Ethernet            */
/*    ETH_MACAddressConfig                  Setup MAC address             */
/*    ETH_DMARxDescReceiveITConfig          Enable receive descriptors    */
/*    nx_packet_allocate                    Allocate receive packet(s)    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_initialize                 Driver initialize processing  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_initialize(NX_IP_DRIVER *driver_req_ptr)
{
#ifdef ETH_MULTIQUEUE_SUPPORTED
    uint32_t ch;
#endif

    /* Default to successful return.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;

    /* Setup indices.  */
    nx_driver_information.nx_driver_information_receive_current_index  = 0;
    nx_driver_information.nx_driver_information_transmit_current_index = 0;
    nx_driver_information.nx_driver_information_transmit_release_index = 0;

    /* Clear the number of buffers in use counter.  */
#ifdef ETH_MULTIQUEUE_SUPPORTED
    for(ch = 0; ch &lt; ETH_DMA_TX_CH_CNT; ch++)
    {
        nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use[ch] = 0;
    }
#else
    nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use = 0;
#endif

    /* Make sure there are receive packets... otherwise, return an error.  */
    if(nx_driver_information.nx_driver_information_packet_pool_ptr == NULL)
    {
        /* There must be receive packets. If not, return an error!  */
        return (NX_DRIVER_ERROR);
    }

#ifdef NX_DRIVER_ETH_HW_IP_INIT
    nx_eth_init( );
#endif /* NX_DRIVER_ETH_HW_IP_INIT */

    ETH_DMAConfigTypeDef dmaDefaultConf;

    memset(&dmaDefaultConf, 0, sizeof(ETH_DMAConfigTypeDef));
    HAL_ETH_GetDMAConfig(&eth_handle, &dmaDefaultConf);

    /*--------------- ETHERNET DMA registers default Configuration --------------*/
#ifdef ETH_MULTIQUEUE_SUPPORTED
    /* Common DMA configuration */
    dmaDefaultConf.AddressAlignedBeats          = ENABLE;
    dmaDefaultConf.AXIBLENMaxSize               = ETH_BLEN_MAX_SIZE_4;
    dmaDefaultConf.BurstMode                    = ETH_BURSTLENGTH_FIXED;
    dmaDefaultConf.RxOSRLimit                   = ETH_RX_OSR_LIMIT_3;
    dmaDefaultConf.TxOSRLimit                   = ETH_TX_OSR_LIMIT_3;
    dmaDefaultConf.TransmitArbitrationAlgorithm = ETH_DMATXARBITRATION_FIXED_PRIO;
    dmaDefaultConf.TransmitPriority             = DISABLE;

    for(ch = 0; ch &lt; ETH_DMA_CH_CNT; ch++)
    {
        /* DMA CH configuration */
        dmaDefaultConf.DMACh[ch].FlushRxPacket        = DISABLE;
        dmaDefaultConf.DMACh[ch].PBLx8Mode            = DISABLE;
        dmaDefaultConf.DMACh[ch].RxDMABurstLength     = ETH_RXDMABURSTLENGTH_32BEAT;
        dmaDefaultConf.DMACh[ch].SecondPacketOperate  = DISABLE;
        dmaDefaultConf.DMACh[ch].TCPSegmentation      = DISABLE;
        dmaDefaultConf.DMACh[ch].TxDMABurstLength     = ETH_TXDMABURSTLENGTH_32BEAT;
        dmaDefaultConf.DMACh[ch].DescriptorSkipLength = ETH_DMA_DESC_SKIP_LENGTH_32;
        dmaDefaultConf.DMACh[ch].MaximumSegmentSize   = 0x218U;
    }
#else

#if defined(ETH_DMASBMR_BLEN4) /* ETH AXI support*/
    dmaDefaultConf.DMAArbitration                                                 = ETH_DMAARBITRATION_TX;
#else
    dmaDefaultConf.DMAArbitration = ETH_DMAARBITRATION_RX1_TX1;
#endif
    dmaDefaultConf.AddressAlignedBeats                                            = ENABLE;
    dmaDefaultConf.BurstMode                                                      = ETH_BURSTLENGTH_FIXED;
    dmaDefaultConf.TxDMABurstLength                                               = ETH_TXDMABURSTLENGTH_32BEAT;
    dmaDefaultConf.RxDMABurstLength                                               = ETH_RXDMABURSTLENGTH_32BEAT;
    dmaDefaultConf.FlushRxPacket                                                  = DISABLE;
#ifndef STM32_ETH_HAL_LEGACY
    dmaDefaultConf.PBLx8Mode                                                      = DISABLE;
#if defined(ETH_DMASBMR_BLEN4) /* ETH AXI support*/
    dmaDefaultConf.RxOSRLimit                                                     = ETH_RX_OSR_LIMIT_3;
    dmaDefaultConf.TxOSRLimit                                                     = ETH_TX_OSR_LIMIT_3;
    dmaDefaultConf.AXIBLENMaxSize                                                 = ETH_BLEN_MAX_SIZE_16;
#else
    dmaDefaultConf.RebuildINCRxBurst = DISABLE;
#endif
    dmaDefaultConf.SecondPacketOperate                                            = ENABLE;
    dmaDefaultConf.TCPSegmentation                                                = DISABLE;
    dmaDefaultConf.MaximumSegmentSize                                             = 536;
#endif

#ifdef STM32_ETH_HAL_LEGACY
    dmaDefaultConf.DropTCPIPChecksumErrorFrame                                    = ENABLE;
    dmaDefaultConf.ReceiveStoreForward                                            = DISABLE;
    dmaDefaultConf.TransmitStoreForward                                           = ENABLE;
    dmaDefaultConf.TransmitThresholdControl                                       = ENABLE;
    dmaDefaultConf.ForwardErrorFrames                                             = DISABLE;
    dmaDefaultConf.ReceiveThresholdControl                                        = DISABLE;
    dmaDefaultConf.SecondFrameOperate                                             = DISABLE;
    dmaDefaultConf.EnhancedDescriptorFormat                                       = DISABLE;
    dmaDefaultConf.DescriptorSkipLength                                           = DISABLE;
#endif
#endif /* ETH_MULTIQUEUE_SUPPORTED */

    /* enable OSF bit to enhance throughput */
    HAL_ETH_SetDMAConfig(&eth_handle, &dmaDefaultConf);
#ifdef STM32_ETH_PROMISCUOUS_ENABLE
    FilterConfig.PromiscuousMode = ENABLE;
#else
    FilterConfig.PromiscuousMode                                                  = DISABLE;
#endif
    FilterConfig.HashUnicast              = DISABLE;
    FilterConfig.HashMulticast            = DISABLE;
    FilterConfig.DestAddrInverseFiltering = DISABLE;
    FilterConfig.PassAllMulticast         = DISABLE;
    /* ARP 请求通常是广播帧，必须允许广播进入 MAC。 */
    FilterConfig.BroadcastFilter         = DISABLE;
    FilterConfig.SrcAddrInverseFiltering = DISABLE;
    FilterConfig.SrcAddrFiltering        = DISABLE;
    FilterConfig.HachOrPerfectFilter     = DISABLE;
    FilterConfig.ReceiveAllMode          = DISABLE;
    FilterConfig.ControlPacketsFilter    = 0x00;

    /* Set Tx packet config common parameters */
    memset(&TxPacketCfg, 0, sizeof(ETH_TxPacketConfigTypeDef));
    TxPacketCfg.Attributes = ETH_TX_PACKETS_FEATURES_CSUM;
    TxPacketCfg.CRCPadCtrl = ETH_CRC_PAD_DISABLE;

    /* Clear the number of buffers in use counter.  */
    nx_driver_information.nx_driver_information_multicast_count = 0;

    /* Return success!  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_enable                                          */
/*                                                            6.1         */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific link enable requests.     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ETH_Start                             Start Ethernet operation      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_enable                     Driver link enable processing */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_enable(NX_IP_DRIVER *driver_req_ptr)
{
    /* Call STM32 library to start Ethernet operation.  */
    HAL_ETH_Start_IT(&eth_handle);

    /* Return success!  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_disable                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific link disable requests.    */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ETH_MACTransmissionCmd                Disable transmit              */
/*    ETH_FlushTransmitFIFO                 Flush transmit FIFO           */
/*    ETH_MACReceptionCmd                   Disable receive               */
/*    ETH_DMATransmissionCmd                Stop DMA transmission         */
/*    ETH_DMAReceptionCmd                   Stop DMA reception            */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_disable                    Driver link disable processing*/
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_disable(NX_IP_DRIVER *driver_req_ptr)
{
    HAL_ETH_Stop(&eth_handle);

    /* Return success!  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_packet_send                                     */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific packet send requests.     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    packet_ptr                            Pointer to packet to send     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    [_nx_driver_transmit_packet_enqueue]  Optional internal transmit    */
/*                                            packet queue routine        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_packet_send                Driver packet send processing */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
#ifdef MULTI_QUEUE_FEATURE
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
{
    UINT          status;
    UCHAR         channel_number = 0;

    NX_INTERFACE *interface_ptr;

    interface_ptr = nx_driver_information.nx_driver_information_interface;

    status        = nx_shaper_hw_queue_id_get(interface_ptr, packet_ptr, &channel_number);

    status        = _nx_driver_hardware_packet_send_distribute(packet_ptr, channel_number);

    return status;
}

static UINT _nx_driver_hardware_packet_send_distribute(NX_PACKET *packet_ptr, UINT channel_number)
{
    NX_PACKET               *pktIdx;
    UINT                     buffLen = 0;
    int                      i       = 0;

    static ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];

    memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));

    for(pktIdx = packet_ptr; pktIdx != NX_NULL; pktIdx = pktIdx-&gt;nx_packet_next)
    {
        ULONG seg_len;

        if(i &gt;= ETH_TX_DESC_CNT)
        {
            return NX_DRIVER_ERROR;
        }

        if(pktIdx-&gt;nx_packet_append_ptr &lt; pktIdx-&gt;nx_packet_prepend_ptr)
        {
            NX_NET_TRACE("NETX TX invalid seg: append&lt;prepend pkt=0x%08lX pre=0x%08lX app=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr, (unsigned long)pktIdx-&gt;nx_packet_length);
            return NX_DRIVER_ERROR;
        }

        seg_len = (ULONG)(pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);
        if(seg_len == 0U)
        {
            if((pktIdx-&gt;nx_packet_length &gt; 0U) && (pktIdx-&gt;nx_packet_next == NX_NULL) && (pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length &lt;= pktIdx-&gt;nx_packet_data_end))
            {
                pktIdx-&gt;nx_packet_append_ptr = pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length;
                seg_len                      = pktIdx-&gt;nx_packet_length;
                NX_NET_TRACE("NETX TX repair seg: pkt=0x%08lX repaired_len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)seg_len);
            }
            else
            {
                NX_NET_TRACE("NETX TX skip empty seg: pkt=0x%08lX next=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_next, (unsigned long)pktIdx-&gt;nx_packet_length);
                continue;
            }
        }

        if(seg_len &gt; 0x3FFFU)
        {
            NX_NET_TRACE("NETX TX invalid seg: oversize pkt=0x%08lX seg_len=%lu pre=0x%08lX app=0x%08lX\r\n", (unsigned long)pktIdx, (unsigned long)seg_len, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr);
            return NX_DRIVER_ERROR;
        }

        Txbuffer[i].buffer = pktIdx-&gt;nx_packet_prepend_ptr;
        Txbuffer[i].len    = seg_len;
        buffLen += seg_len;

        if(i &gt; 0)
        {
            Txbuffer[i - 1].next = &Txbuffer[i];
        }

        if(pktIdx-&gt;nx_packet_next == NULL)
        {
            Txbuffer[i].next = NULL;
        }

        i++;
        clean_cache_by_addr((uint32_t *)(pktIdx-&gt;nx_packet_data_start), pktIdx-&gt;nx_packet_data_end - pktIdx-&gt;nx_packet_data_start);
    }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & (NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM))
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    }
    else if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_INSERT;
    }
#else
    TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_DISABLE;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

#ifdef NX_DRIVER_ENABLE_PTP
    /* Enable PTP timestamp */
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_PTP_TIMESTAMP)
    {
        HAL_ETH_PTP_InsertTxTimestamp(&eth_handle);
    }
#endif /* NX_DRIVER_ENABLE_PTP */

    if(buffLen == 0U)
    {
        NX_NET_TRACE("NETX TX invalid: no payload segments after filtering\r\n");
        return NX_DRIVER_ERROR;
    }

    TxPacketCfg.TxDMACh  = channel_number;
    TxPacketCfg.Length   = buffLen;
    TxPacketCfg.TxBuffer = Txbuffer;
    TxPacketCfg.pData    = (uint32_t *)packet_ptr;

    if(HAL_ETH_Transmit_IT(&eth_handle, &TxPacketCfg) != HAL_OK)
        return NX_DRIVER_ERROR;

    return NX_SUCCESS;
}

#else
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
{
    NX_PACKET               *pktIdx;
    UINT                     buffLen = 0;

    static ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
    memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));

    int i = 0;

    for(pktIdx = packet_ptr; pktIdx != NX_NULL; pktIdx = pktIdx-&gt;nx_packet_next)
    {
        ULONG seg_len;

        if(i &gt;= ETH_TX_DESC_CNT)
        {
            return NX_DRIVER_ERROR;
        }

        if(pktIdx-&gt;nx_packet_append_ptr &lt; pktIdx-&gt;nx_packet_prepend_ptr)
        {
            NX_NET_TRACE("NETX TX invalid seg: append&lt;prepend pkt=0x%08lX pre=0x%08lX app=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr, (unsigned long)pktIdx-&gt;nx_packet_length);
            return NX_DRIVER_ERROR;
        }

        seg_len = (ULONG)(pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);
        if(seg_len == 0U)
        {
            if((pktIdx-&gt;nx_packet_length &gt; 0U) && (pktIdx-&gt;nx_packet_next == NX_NULL) && (pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length &lt;= pktIdx-&gt;nx_packet_data_end))
            {
                pktIdx-&gt;nx_packet_append_ptr = pktIdx-&gt;nx_packet_prepend_ptr + pktIdx-&gt;nx_packet_length;
                seg_len                      = pktIdx-&gt;nx_packet_length;
                NX_NET_TRACE("NETX TX repair seg: pkt=0x%08lX repaired_len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)seg_len);
            }
            else
            {
                NX_NET_TRACE("NETX TX skip empty seg: pkt=0x%08lX next=0x%08lX len=%lu\r\n", (unsigned long)pktIdx, (unsigned long)pktIdx-&gt;nx_packet_next, (unsigned long)pktIdx-&gt;nx_packet_length);
                continue;
            }
        }

        if(seg_len &gt; 0x3FFFU)
        {
            NX_NET_TRACE("NETX TX invalid seg: oversize pkt=0x%08lX seg_len=%lu pre=0x%08lX app=0x%08lX\r\n", (unsigned long)pktIdx, (unsigned long)seg_len, (unsigned long)pktIdx-&gt;nx_packet_prepend_ptr, (unsigned long)pktIdx-&gt;nx_packet_append_ptr);
            return NX_DRIVER_ERROR;
        }

        Txbuffer[i].buffer = pktIdx-&gt;nx_packet_prepend_ptr;
        Txbuffer[i].len    = seg_len;
        buffLen += seg_len;

        if(i &gt; 0)
        {
            Txbuffer[i - 1].next = &Txbuffer[i];
        }

        if(pktIdx-&gt;nx_packet_next == NULL)
        {
            Txbuffer[i].next = NULL;
        }

        i++;
        clean_cache_by_addr((uint32_t *)(pktIdx-&gt;nx_packet_data_start), pktIdx-&gt;nx_packet_data_end - pktIdx-&gt;nx_packet_data_start);
    }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & (NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM))
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    }
    else if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_INSERT;
    }
#else
    TxPacketCfg.ChecksumCtrl      = ETH_CHECKSUM_DISABLE;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

    if(buffLen == 0U)
    {
        NX_NET_TRACE("NETX TX invalid: no payload segments after filtering\r\n");
        return NX_DRIVER_ERROR;
    }

    TxPacketCfg.Length   = buffLen;
    TxPacketCfg.TxBuffer = Txbuffer;
    TxPacketCfg.pData    = (uint32_t *)packet_ptr;

    if(HAL_ETH_Transmit_IT(&eth_handle, &TxPacketCfg))
    {
        return (NX_DRIVER_ERROR);
    }

    return (NX_SUCCESS);
}
#endif /* MULTI_QUEUE_FEATURE */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_multicast_join                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific multicast join requests.  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_multicast_join             Driver multicast join         */
/*                                            processing                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_multicast_join(NX_IP_DRIVER *driver_req_ptr)
{
    /* Increase the multicast count.  */
    nx_driver_information.nx_driver_information_multicast_count++;

    /* Enable multicast frame reception.  */
    FilterConfig.PassAllMulticast = ENABLE;
    HAL_ETH_SetMACFilterConfig(&eth_handle, &FilterConfig);

    /* Return success.  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_multicast_leave                                 */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific multicast leave requests. */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]*/
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_multicast_leave            Driver multicast leave        */
/*                                            processing                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_multicast_leave(NX_IP_DRIVER *driver_req_ptr)
{
    /* Decrease the multicast count.  */
    nx_driver_information.nx_driver_information_multicast_count--;

    /* If multicast count reaches zero, disable multicast frame reception.  */
    if(nx_driver_information.nx_driver_information_multicast_count == 0)
    {
        /* Disable multicast frame reception.  */
        FilterConfig.PassAllMulticast = DISABLE;
        HAL_ETH_SetMACFilterConfig(&eth_handle, &FilterConfig);
    }

    /* Return success.  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_get_status                                      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific get status requests.      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]*/
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_get_status                 Driver get status processing  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_get_status(NX_IP_DRIVER *driver_req_ptr)
{
    INT PHYLinkState;

    /* Get link status. */
    PHYLinkState = nx_eth_phy_get_link_state( );

    /* Check link status. */
    if(PHYLinkState &lt;= ETH_PHY_STATUS_LINK_DOWN)
    {
        /* Update Link status if physical link is down. */
        *(driver_req_ptr-&gt;nx_ip_driver_return_ptr) = NX_FALSE;
    }
    else
    {
        /* Update Link status if physical link is up. */
        *(driver_req_ptr-&gt;nx_ip_driver_return_ptr) = NX_TRUE;
    }

    /* Return success. */
    return NX_SUCCESS;
}

void HAL_ETH_TxFreeCallback(uint32_t *buff)
{
    NX_PACKET *release_packet = (NX_PACKET *)buff;

    /* Remove the Ethernet header and release the packet.  */
    NX_DRIVER_ETHERNET_HEADER_REMOVE(release_packet);

    /* Release the packet.  */
    nx_packet_transmit_release(release_packet);
}

#ifdef NX_DRIVER_ENABLE_PTP

void HAL_ETH_TxPtpCallback(uint32_t *buff, ETH_TimeStampTypeDef *timestamp)
{
    NX_PTP_TIME ts;
    NX_PACKET  *release_packet = (NX_PACKET *)buff;

    if(release_packet-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_PTP_TIMESTAMP)
    {
        /* store timestamp in NX_PTP_TIME structure */
        ts.second_high = 0;
        ts.second_low  = timestamp-&gt;TimeStampHigh;
        ts.nanosecond  = timestamp-&gt;TimeStampLow;

        /* call notification callback */
        nx_ptp_client_packet_timestamp_notify(nx_driver_information.nx_driver_ptp_ptr, release_packet, &ts);
    }
}
#endif /* NX_DRIVER_ENABLE_PTP */

static VOID _nx_driver_hardware_packet_received(VOID)
{
    NX_PACKET *received_packet_ptr;

#ifdef NX_DRIVER_ENABLE_PTP
    ULONG                ts[2] = {0, 0};
    ETH_TimeStampTypeDef timestamp;
#endif /* NX_DRIVER_ENABLE_PTP */

    while(HAL_ETH_ReadData(&eth_handle, (void **)&received_packet_ptr) == HAL_OK)
    {
#ifdef NX_DRIVER_ENABLE_PTP
        /* Save PTP timestamp */
        HAL_ETH_PTP_GetRxTimestamp(&eth_handle, &timestamp);
        ts[0] = timestamp.TimeStampLow;
        ts[1] = timestamp.TimeStampHigh;

        /* Transfer the packet to NetX.  */
        _nx_driver_transfer_to_netx(nx_driver_information.nx_driver_information_ip_ptr, received_packet_ptr, ts);
#else
        /* Transfer the packet to NetX.  */
        NX_NET_TRACE("NETX RX hw-&gt;stack\r\n");
        _nx_driver_transfer_to_netx(nx_driver_information.nx_driver_information_ip_ptr, received_packet_ptr);

#endif /* NX_DRIVER_ENABLE_PTP */
    }
}

void HAL_ETH_RxAllocateCallback(uint8_t **buff)
{
    NX_PACKET *packet_ptr;
    if(nx_packet_allocate(nx_driver_information.nx_driver_information_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_NO_WAIT) == NX_SUCCESS)
    {
        /* Adjust the packet.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += 2;
        packet_ptr-&gt;nx_packet_append_ptr = packet_ptr-&gt;nx_packet_prepend_ptr;
        invalidate_cache_by_addr((uint32_t *)packet_ptr-&gt;nx_packet_data_start, packet_ptr-&gt;nx_packet_data_end - packet_ptr-&gt;nx_packet_data_start);
        *buff = packet_ptr-&gt;nx_packet_prepend_ptr;
    }
    else
    {
        ULONG total_packets;
        ULONG free_packets;
        ULONG empty_pool_requests;
        ULONG empty_pool_suspensions;
        ULONG invalid_packet_releases;

        nx_packet_pool_info_get(nx_driver_information.nx_driver_information_packet_pool_ptr, &total_packets, &free_packets, &empty_pool_requests, &empty_pool_suspensions, &invalid_packet_releases);

        /* Rx Buffer Pool is exhausted. */
        NX_NET_TRACE("NETX RX alloc fail: pool exhausted (free=%lu total=%lu empty_req=%lu)\r\n", (unsigned long)free_packets, (unsigned long)total_packets, (unsigned long)empty_pool_requests);
        *buff = NULL;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                                              */
/*                                                                        */
/*    HAL_ETH_RxLinkCallback                                              */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function chains all received packets before passing            */
/*    the first one to NetXDuo stack.                                     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    first_packet_ptr           pointer to first received packet         */
/*    last_packet_ptr            pointer to last received packet          */
/*    buff                       pointer to received data                 */
/*    length                     received data length                     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    received packet pointer                                             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    HAL_ETH_ReadData              Read a received packet                */
/*                                                                        */
/**************************************************************************/
void HAL_ETH_RxLinkCallback(void **first_packet_ptr, void **last_packet_ptr, uint8_t *buff, uint16_t Length)
{
    NX_PACKET **first_nx_packet_ptr = (NX_PACKET **)first_packet_ptr;
    NX_PACKET **last_nx_packet_ptr  = (NX_PACKET **)last_packet_ptr;
    NX_PACKET  *received_packet_ptr;

    /* Indicate the offset of the received data.  */
    uint8_t *data_buffer_ptr                  = buff - 2U - header_size;

    received_packet_ptr                       = (NX_PACKET *)data_buffer_ptr;
    received_packet_ptr-&gt;nx_packet_next       = NX_NULL;
    received_packet_ptr-&gt;nx_packet_append_ptr = received_packet_ptr-&gt;nx_packet_prepend_ptr + Length;
    received_packet_ptr-&gt;nx_packet_length     = Length;

    /* Check whether this is the first packet. */
    if(*first_nx_packet_ptr == NULL)
    {
        /* Add the first buffer of the packet. */
        *first_nx_packet_ptr = received_packet_ptr;
    }
    /* This is not the first packet. */
    else
    {
        /* Add the rest of the buffer to the end of the packet. */
        (*last_nx_packet_ptr)-&gt;nx_packet_next = received_packet_ptr;
    }
    /* Save the current packet in order to use it in the next iteration. */
    *last_nx_packet_ptr = received_packet_ptr;
}

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_capability_set                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific capability set requests.  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                         Driver request pointer       */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_capability_set             Capability set processing     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_capability_set(NX_IP_DRIVER *driver_req_ptr)
{
    return NX_SUCCESS;
}
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
    ULONG deffered_events;
    NX_NET_TRACE("NETX ISR: RX complete\r\n");
    deffered_events = nx_driver_information.nx_driver_information_deferred_events;
#ifdef MULTI_QUEUE_FEATURE
    uint32_t channel = heth-&gt;RxCH;

    if((channel & ETH_DMA_CH0) == ETH_DMA_CH0)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH0;

    if((channel & ETH_DMA_CH1) == ETH_DMA_CH1)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH1;

#else
    nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_RECEIVED;
#endif /* MULTI_QUEUE_FEATURE */
    if(!deffered_events)
    {
        /* Call NetX deferred driver processing.  */
        _nx_ip_driver_deferred_processing(nx_driver_information.nx_driver_information_ip_ptr);
    }
}

void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth)
{
    ULONG deffered_events;
    NX_NET_TRACE("NETX ISR: TX complete\r\n");
    deffered_events = nx_driver_information.nx_driver_information_deferred_events;
#ifdef MULTI_QUEUE_FEATURE
    uint32_t channel = heth-&gt;TxCH;

    if((channel & ETH_DMA_CH0) == ETH_DMA_CH0)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH0;

    if((channel & ETH_DMA_CH1) == ETH_DMA_CH1)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH1;
#else
    nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_TRANSMITTED;
#endif /* MULTI_QUEUE_FEATURE */

    if(!deffered_events)
    {
        /* Call NetX deferred driver processing.  */
        _nx_ip_driver_deferred_processing(nx_driver_information.nx_driver_information_ip_ptr);
    }
}

void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth)
{
    uint32_t dma_err = heth-&gt;DMAErrorCode;
    uint32_t mac_err = heth-&gt;MACErrorCode;

    NX_NET_TRACE("NETX ETH err: gState=0x%02lX err=0x%02lX dma=0x%04lX mac=0x%04lX\r\n", (unsigned long)heth-&gt;gState, (unsigned long)heth-&gt;ErrorCode, (unsigned long)dma_err, (unsigned long)mac_err);
    nx_dump_tx_desc_snapshot(heth);

    /* Fatal bus error or HAL entered ERROR state: perform a soft restart. */
    if(((dma_err & ETH_DMACSR_FBE) != 0U) || (heth-&gt;gState == HAL_ETH_STATE_ERROR))
    {
        (void)HAL_ETH_Stop_IT(heth);
        if(HAL_ETH_Start_IT(heth) == HAL_OK)
        {
            NX_NET_TRACE("NETX ETH recover: restart ok\r\n");
            heth-&gt;ErrorCode    = HAL_ETH_ERROR_NONE;
            heth-&gt;DMAErrorCode = 0U;
            heth-&gt;MACErrorCode = 0U;
        }
        else
        {
            NX_NET_TRACE("NETX ETH recover: restart failed\r\n");
        }
    }
}

#ifdef NX_DRIVER_ENABLE_PTP
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    nx_driver_ptp_clock_callback                                        */
/*                                                           6.x          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function handles PTP clock operations.                         */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    client_ptr                                  Client pointer          */
/*    operation                                   operation               */
/*    time_ptr                                    Time pointer            */
/*    packet_ptr                                  Packet pointer          */
/*    callback_data                               callback data           */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    NetX PTP Client                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
UINT nx_driver_ptp_clock_callback(NX_PTP_CLIENT *client_ptr, UINT operation, NX_PTP_TIME *time_ptr, NX_PACKET *packet_ptr, VOID *callback_data)
{
    TX_INTERRUPT_SAVE_AREA
    ULONG           sec1, sec2, ns;
    ETH_TimeTypeDef time;
    uint32_t        tickstart;
    UINT            NX_PTP_Status = 0;
    ETH_TimeTypeDef time_offset;

    NX_PARAMETER_NOT_USED(callback_data);

    switch(operation)
    {
    /* Save pointer to PTP client.  */
    case NX_PTP_CLIENT_CLOCK_INIT:
        nx_driver_information.nx_driver_ptp_ptr = client_ptr;
        break;

    /* Set clock.  */
    case NX_PTP_CLIENT_CLOCK_SET:
        TX_DISABLE

        /* Get Start Tick*/
        tickstart = HAL_GetTick( );

        /* Wait to get PTP control or timeout occurred */
        while(((HAL_GetTick( ) - tickstart) &gt; HAL_PTP_TIMEOUT))
        {
            if(__HAL_ETH_GET_PTP_CONTROL(&eth_handle, ETH_MACTSCR_TSUPDT) == 0)
            {
                NX_PTP_Status = NX_WAIT_ERROR;
                break;
            }
        }

        time.Seconds     = time_ptr-&gt;second_low;
        time.NanoSeconds = time_ptr-&gt;nanosecond;
        HAL_ETH_PTP_SetTime(&eth_handle, &time);

        TX_RESTORE
        break;

    /* Extract timestamp from packet.  */
    case NX_PTP_CLIENT_CLOCK_PACKET_TS_EXTRACT:

        /* XXX second timestamp is only 32-bit */
        time_ptr-&gt;second_high = 0;

        /* Return timestamp stored at the beginning of the packet.  */
        time_ptr-&gt;nanosecond = ((ULONG *)packet_ptr-&gt;nx_packet_data_start)[0];
        time_ptr-&gt;second_low = ((LONG *)packet_ptr-&gt;nx_packet_data_start)[1];
        break;

    /* Get clock.  */
    case NX_PTP_CLIENT_CLOCK_GET:
        TX_DISABLE

        HAL_ETH_PTP_GetTime(&eth_handle, &time);
        sec1 = time.Seconds;
        ns   = time.NanoSeconds;
        HAL_ETH_PTP_GetTime(&eth_handle, &time);
        sec2                  = time.Seconds;
        time_ptr-&gt;second_high = 0;
        /* The offset standard deviation is below 50 ns */
        time_ptr-&gt;second_low = ns &lt; 500000000UL ? sec2 : sec1;
        time_ptr-&gt;nanosecond = (LONG)ns;

        TX_RESTORE
        break;

    /* Adjust clock.  */
    case NX_PTP_CLIENT_CLOCK_ADJUST:
        TX_DISABLE
        time_offset.Seconds = 0;
        if(time_ptr-&gt;nanosecond &lt; 0)
        {
            time_offset.NanoSeconds = -time_ptr-&gt;nanosecond;
            HAL_ETH_PTP_AddTimeOffset(&heth, HAL_ETH_PTP_NEGATIVE_UPDATE, &time_offset);
        }
        else
        {
            time_offset.NanoSeconds = time_ptr-&gt;nanosecond;
            HAL_ETH_PTP_AddTimeOffset(&heth, HAL_ETH_PTP_POSITIVE_UPDATE, &time_offset);
        }

        TX_RESTORE

        break;

    /* Prepare timestamp for current packet.  */
    case NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE:
        packet_ptr-&gt;nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_PTP_TIMESTAMP;
        break;

    /* Update soft timer. Not used by hardware callback function.  */
    case NX_PTP_CLIENT_CLOCK_SOFT_TIMER_UPDATE:
        break;

    default:
        NX_PTP_Status = NX_PTP_PARAM_ERROR;
    }

    return (NX_PTP_Status);
}

UINT nx_driver_set_timestamp_callback(USHORT type, TIMESTAMP_CALLBACK callback)
{
    timestamp_callback = callback;
    packet_type        = type;

    return 0;
}
#endif /* NX_DRIVER_ENABLE_PTP */

#ifdef MULTI_QUEUE_FEATURE
UINT nx_driver_shaper_config(NX_SHAPER_DRIVER_PARAMETER *parameter, UCHAR shaper_capability)
{
    UINT               status;
    NX_SHAPER_HW_QUEUE hw_queue[ETH_MTL_TX_Q_CNT];

    hw_queue[0].hw_queue_id = 0;
    hw_queue[0].priority    = 1;
    hw_queue[0].type        = NX_SHAPER_HW_QUEUE_NORMAL;

    hw_queue[1].hw_queue_id = 1;
    hw_queue[1].priority    = 2;
    hw_queue[1].type        = NX_SHAPER_HW_QUEUE_CBS;

    status                  = nx_shaper_config(parameter-&gt;nx_ip_driver_interface, PORT_RATE, shaper_capability, ETH_MTL_TX_Q_CNT, hw_queue);

    return status;
}
#endif /* MULTI_QUEUE_FEATURE */
#ifdef NX_DRIVER_ENABLE_CBS
UINT nx_driver_shaper_cbs_entry(NX_SHAPER_DRIVER_PARAMETER *parameter)
{
    UCHAR                    shaper_capability;
    UINT                     status = NX_SUCCESS;
    NX_SHAPER_CBS_PARAMETER *cbs_parameter;
    ETH_CBSConfigTypeDef     cbsconf;
    unsigned int             idle_slope;

    switch(parameter-&gt;nx_shaper_driver_command)
    {
    case NX_SHAPER_COMMAND_INIT:

        break;

    case NX_SHAPER_COMMAND_CONFIG:

        shaper_capability = NX_SHAPER_CAPABILITY_CBS_SUPPORTED;

        nx_driver_shaper_config(parameter, shaper_capability);

        break;

    case NX_SHAPER_COMMAND_PARAMETER_SET:

        cbs_parameter         = (NX_SHAPER_CBS_PARAMETER *)parameter-&gt;shaper_parameter;

        idle_slope            = cbs_parameter-&gt;idle_slope * 1000000; //bit per second

        cbsconf.QueueIdx      = cbs_parameter-&gt;hw_queue_id;
        cbsconf.SlotCount     = 0;
        cbsconf.CreditControl = 0;
        cbsconf.IdleSlope     = ((((uint64_t)idle_slope * 1024) + AVB_IDLE_SLOPE_CYCLE_FACTOR_100M - 1) / AVB_IDLE_SLOPE_CYCLE_FACTOR_100M);
        cbsconf.SendSlope     = (AVB_MAX_PORT_TRANSIT_RATE_100M - cbsconf.IdleSlope);
        cbsconf.HiCredit      = AVB_HI_CREDIT;
        cbsconf.LoCredit      = AVB_LO_CREDIT;

        /* Enable CBS feature */
        HAL_ETHEx_EnableCBS(&heth, cbsconf.QueueIdx);

        /* Set CBS Configuration */
        HAL_ETHEx_SetCBSConfig(&heth, &cbsconf);

        break;

    default:

        break;
    }

    return status;
}
#endif /* NX_DRIVER_ENABLE_CBS */

#ifdef NX_DRIVER_ENABLE_FPE
UINT nx_driver_shaper_fpe_entry(NX_SHAPER_DRIVER_PARAMETER *parameter)
{
    NX_SHAPER_FP_PARAMETER *fpe_parameter;
    UCHAR                   shaper_capability;
    ETH_FPEConfigTypeDef    fpeconf;

    switch(parameter-&gt;nx_shaper_driver_command)
    {
    case NX_SHAPER_COMMAND_INIT:

        /* Enable Tx Frame Preemption */
        HAL_ETHEx_EnableFPE(&heth);

        break;
    case NX_SHAPER_COMMAND_CONFIG:

        shaper_capability = NX_SHAPER_CAPABILITY_PREEMPTION_SUPPORTED;

        nx_driver_shaper_config(parameter, shaper_capability);

        break;
    case NX_SHAPER_COMMAND_PARAMETER_SET:

        memset(&fpeconf, 0, sizeof(ETH_FPEConfigTypeDef));

        fpe_parameter                    = (NX_SHAPER_FP_PARAMETER *)parameter-&gt;shaper_parameter;

        fpeconf.AdditionalFragmentSize   = 0;
        fpeconf.SendRespondmPacket       = DISABLE;
        fpeconf.SendVerifymPacket        = DISABLE;
        fpeconf.HoldReleaseStatus        = 0;
        fpeconf.PreemptionClassification = (((uint32_t)(((uint32_t)(~fpe_parameter-&gt;express_queue_bitmap)) &lt;&lt; ETH_MTLFPECSR_PEC_Pos)) & ETH_MTLFPECSR_PEC_Msk);
        fpeconf.ReleaseAdvance           = (fpe_parameter-&gt;ra &lt;&lt; 16);
        fpeconf.HoldAdvance              = fpe_parameter-&gt;ha;

        HAL_ETHEx_SetFPEConfig(&heth, &fpeconf);

        break;

    default:
        /* Wrong parameter, Disable FPE feature */
        HAL_ETHEx_DisableFPE(&heth);
        break;
    }

    return 0;
}
#endif /* NX_DRIVER_ENABLE_FPE */

#ifdef NX_DRIVER_ENABLE_TAS
#ifdef NX_DRIVER_ENABLE_FPE
void reconfig_fpe_gcl(NX_SHAPER_TAS_PARAMETER *parameter, UCHAR queue_bit)
{
    UINT i = 0;

    for(i = 0; i &lt; parameter-&gt;gcl_length; i++)
    {
        /*queue_bit: bit=1 means express; bit =0 means preemtable*/
        /*gata_control: 1 means open for express queue, 1 means hold(close)for express queue*/
        if(parameter-&gt;gcl[i].operation == NX_SHAPER_GATE_OPERATION_HOLD)
        {
            parameter-&gt;gcl[i].gate_control |= 1;
        }
        else if(parameter-&gt;gcl[i].operation == NX_SHAPER_GATE_OPERATION_RELEASE)
        {
            parameter-&gt;gcl[i].gate_control &= 0xfe;
        }
    }
}
#endif /* NX_DRIVER_ENABLE_FPE */
UINT nx_driver_shaper_tas_entry(NX_SHAPER_DRIVER_PARAMETER *parameter)
{
    UCHAR                         shaper_capability;
    ETH_TimeTypeDef               time;
    UINT                          status = NX_SUCCESS;
    NX_SHAPER_TAS_PARAMETER      *tas_parameter;
    UINT                          i;
    ETH_ESTConfigTypeDef          estconfig;
    ETH_GCLConfigTypeDef         *gate_ctl = &estconfig.GCLRegisters;
    ETH_TASOperationConfigTypeDef opconfig[NX_SHAPER_GCL_LENGTH_MAX];

    switch(parameter-&gt;nx_shaper_driver_command)
    {
    case NX_SHAPER_COMMAND_INIT:
        break;

    case NX_SHAPER_COMMAND_CONFIG:

        shaper_capability = NX_SHAPER_CAPABILITY_TAS_SUPPORTED;
        nx_driver_shaper_config(parameter, shaper_capability);
        break;

    case NX_SHAPER_COMMAND_PARAMETER_SET:

        memset(&estconfig, 0, sizeof(estconfig));

        tas_parameter = (NX_SHAPER_TAS_PARAMETER *)parameter-&gt;shaper_parameter;
#ifdef NX_DRIVER_ENABLE_FPE
        if(tas_parameter-&gt;fp_parameter)
        {
            reconfig_fpe_gcl(tas_parameter, ((NX_SHAPER_FP_PARAMETER *)tas_parameter-&gt;fp_parameter)-&gt;express_queue_bitmap);
        }
#endif /* NX_DRIVER_ENABLE_FPE */
        if(tas_parameter-&gt;gcl_length &gt; NX_SHAPER_GCL_LENGTH_MAX)
        {
            status = NX_NOT_SUCCESSFUL;
            return status;
        }

        gate_ctl-&gt;BaseTimeRegister      = tas_parameter-&gt;base_time;            /*! Base Time 32 bits seconds 32 bits nanoseconds */
        gate_ctl-&gt;CycleTimeRegister     = tas_parameter-&gt;cycle_time;           /*! Cycle Time 32 bits seconds 32 bits nanoseconds */
        gate_ctl-&gt;TimeExtensionRegister = tas_parameter-&gt;cycle_time_extension; /*! Time Extension 32 bits seconds 32 bits nanoseconds */
        gate_ctl-&gt;ListLengthRegister    = tas_parameter-&gt;gcl_length;           /*! Number of entries */
        gate_ctl-&gt;opList                = opconfig;

        memset(opconfig, 0, sizeof(opconfig));

        for(i = 0; i &lt; gate_ctl-&gt;ListLengthRegister; i++)
        {
            opconfig[i].Gate     = tas_parameter-&gt;gcl[i].gate_control;
            opconfig[i].Interval = tas_parameter-&gt;gcl[i].duration;
        }

        /*we will set the value added with a micro delay */
        if(gate_ctl-&gt;BaseTimeRegister == 0)
        {
            HAL_ETH_PTP_GetTime(&heth, &time);
            gate_ctl-&gt;BaseTimeRegister = (ULONG64)time.Seconds &lt;&lt; 32 | (ULONG64)time.NanoSeconds;
            /*add  1 second delay from now */
            gate_ctl-&gt;BaseTimeRegister += (ULONG64)1 &lt;&lt; 32;
        }

        estconfig.PTPTimeOffset = PTP_REF_CLK;
        estconfig.SwitchToSWOL  = 1;

        HAL_ETHEx_SetESTConfig(&heth, &estconfig);
        break;

    default:
        /* Wrong parameter, Disable TAS feature */
        HAL_ETHEx_DisableEST(&heth);

        break;
    }

    return status;
}
#endif /* NX_DRIVER_ENABLE_TAS */
/****** DRIVER SPECIFIC ****** Start of part/vendor specific internal driver functions.  */
</code></pre>&lt;/Tab&gt;&lt;Tab label="旧的文件"&gt;<pre><code class="language-c">/**************************************************************************/
/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/

/* Indicate that driver source is being compiled.  */

#define NX_DRIVER_SOURCE

/****** DRIVER SPECIFIC ****** Start of part/vendor specific include area.  Include driver-specific include file here!  */

#ifndef NX_STM32_ETH_DRIVER_H

/* Determine if the driver uses IP deferred processing or direct ISR processing.  */

#define NX_DRIVER_ENABLE_DEFERRED /* Define this to enable deferred ISR processing.  */

/* Include driver specific include file.  */
#include "nx_stm32_eth_driver.h"

/* Include the phy driver header */
#include "nx_stm32_phy_driver.h"

#endif /* NX_STM32_ETH_DRIVER_H */

/****** DRIVER SPECIFIC ****** End of part/vendor specific include file area!  */

/* Define the driver information structure that is only available within this file.  */
static NX_DRIVER_INFORMATION nx_driver_information;

/* Rounded header size */
static ULONG               header_size;

ETH_TxPacketConfigTypeDef  TxPacketCfg;
ETH_MACFilterConfigTypeDef FilterConfig;
USHORT                     packet_type;

#ifdef NX_DRIVER_ENABLE_PTP
TIMESTAMP_CALLBACK timestamp_callback = NULL;
#define HAL_PTP_TIMEOUT 0xFU
#define PTP_REF_CLK     50000000UL
#endif
/****** DRIVER SPECIFIC ****** Start of part/vendor specific data area.  Include hardware-specific data here!  */

/****** DRIVER SPECIFIC ****** End of part/vendor specific data area!  */

/* Define the routines for processing each driver entry request.  The contents of these routines will change with
each driver. However, the main driver entry function will not change, except for the entry function name.  */

static VOID _nx_driver_interface_attach(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_initialize(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_enable(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_disable(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_multicast_join(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_multicast_leave(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_get_status(NX_IP_DRIVER *driver_req_ptr);
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
static VOID _nx_driver_capability_get(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_capability_set(NX_IP_DRIVER *driver_req_ptr);
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

static VOID _nx_driver_deferred_processing(NX_IP_DRIVER *driver_req_ptr);

#ifdef NX_DRIVER_ENABLE_PTP
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr, ULONG *ptp_ts_ptr);
#else
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr);
#endif /* NX_DRIVER_ENABLE_PTP */

/* Define the prototypes for the hardware implementation of this driver. The contents of these routines are
driver-specific.  */

static UINT _nx_driver_hardware_initialize(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_enable(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_disable(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr);
#ifdef MULTI_QUEUE_FEATURE
static UINT _nx_driver_hardware_packet_send_distribute(NX_PACKET *packet_ptr, UINT queue_number);
#endif
static UINT _nx_driver_hardware_multicast_join(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_multicast_leave(NX_IP_DRIVER *driver_req_ptr);
static UINT _nx_driver_hardware_get_status(NX_IP_DRIVER *driver_req_ptr);
static VOID _nx_driver_hardware_packet_received(VOID);
#ifdef NX_ENABLE_INTERFACE_CAPABILITY
static UINT _nx_driver_hardware_capability_set(NX_IP_DRIVER *driver_req_ptr);
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    nx_stm32_eth_driver                                                 */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This is the entry point of the NetX Ethernet Driver. This driver    */
/*    function is responsible for initializing the Ethernet controller,   */
/*    enabling or disabling the controller as need, preparing             */
/*    a packet for transmission, and getting status information.          */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        The driver request from the   */
/*                                            IP layer.                   */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_interface_attach           Process attach request        */
/*    _nx_driver_initialize                 Process initialize request    */
/*    _nx_driver_enable                     Process link enable request   */
/*    _nx_driver_disable                    Process link disable request  */
/*    _nx_driver_packet_send                Process send packet requests  */
/*    _nx_driver_multicast_join             Process multicast join request*/
/*    _nx_driver_multicast_leave            Process multicast leave req   */
/*    _nx_driver_get_status                 Process get status request    */
/*    _nx_driver_deferred_processing        Drive deferred processing     */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    IP layer                                                            */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
/****** DRIVER SPECIFIC ****** Start of part/vendor specific global driver entry function name.  */
VOID nx_stm32_eth_driver(NX_IP_DRIVER *driver_req_ptr)
/****** DRIVER SPECIFIC ****** End of part/vendor specific global driver entry function name.  */
{
#ifdef NX_ENABLE_VLAN
    NX_INTERFACE *interface_ptr;
#endif /* NX_ENABLE_VLAN */

    /* Default to successful return.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;

#ifdef NX_ENABLE_VLAN
    /* Let link layer to preprocess the driver request and return actual interface.  */
    if(nx_link_driver_request_preprocess(driver_req_ptr, &interface_ptr) != NX_SUCCESS)
    {
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }
#endif /* NX_ENABLE_VLAN */

    /* Process according to the driver request type in the IP control
  block.  */
    switch(driver_req_ptr-&gt;nx_ip_driver_command)
    {
    case NX_LINK_INTERFACE_ATTACH:

        /* Process link interface attach requests.  */
        _nx_driver_interface_attach(driver_req_ptr);
        break;

    case NX_LINK_INITIALIZE:
        {
            /* Process link initialize requests.  */
            _nx_driver_initialize(driver_req_ptr);
            break;
        }

    case NX_LINK_ENABLE:
        {
            /* Process link enable requests.  */
            _nx_driver_enable(driver_req_ptr);
            break;
        }

    case NX_LINK_DISABLE:
        {
            /* Process link disable requests.  */
            _nx_driver_disable(driver_req_ptr);
            break;
        }

    case NX_LINK_ARP_SEND:
    case NX_LINK_ARP_RESPONSE_SEND:
    case NX_LINK_PACKET_BROADCAST:
    case NX_LINK_RARP_SEND:
    case NX_LINK_PACKET_SEND:
    case NX_LINK_RAW_PACKET_SEND:
        {
            /* Process packet send requests.  */
            _nx_driver_packet_send(driver_req_ptr);
            break;
        }

    case NX_LINK_MULTICAST_JOIN:
        {
            /* Process multicast join requests.  */
            _nx_driver_multicast_join(driver_req_ptr);
            break;
        }

    case NX_LINK_MULTICAST_LEAVE:
        {
            /* Process multicast leave requests.  */
            _nx_driver_multicast_leave(driver_req_ptr);
            break;
        }

    case NX_LINK_GET_STATUS:
        {
            /* Process get status requests.  */
            _nx_driver_get_status(driver_req_ptr);
            break;
        }

    case NX_LINK_DEFERRED_PROCESSING:
        {
            /* Process driver deferred requests.  */

            /* Process a device driver function on behave of the IP thread. */
            _nx_driver_deferred_processing(driver_req_ptr);

            break;
        }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    case NX_INTERFACE_CAPABILITY_GET:
        {
            /* Process get capability requests.  */
            _nx_driver_capability_get(driver_req_ptr);
            break;
        }

    case NX_INTERFACE_CAPABILITY_SET:
        {
            /* Process set capability requests.  */
            _nx_driver_capability_set(driver_req_ptr);
            break;
        }
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

    default:

        /* Invalid driver request.  */

        /* Return the unhandled command status.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_UNHANDLED_COMMAND;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_interface_attach                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the interface attach request.              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_interface_attach(NX_IP_DRIVER *driver_req_ptr)
{
    /* Setup the driver's interface.  This example is for a simple one-interface
  Ethernet driver. Additional logic is necessary for multiple port devices.  */
    nx_driver_information.nx_driver_information_interface = driver_req_ptr-&gt;nx_ip_driver_interface;

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    driver_req_ptr-&gt;nx_ip_driver_interface-&gt;nx_interface_capability_flag = NX_DRIVER_CAPABILITY;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

    /* Return successful status.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_initialize                                               */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the initialize request.  The processing    */
/*    in this function is generic. All ethernet controller logic is to    */
/*    be placed in _nx_driver_hardware_initialize.                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_initialize        Process initialize request    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_initialize(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP        *ip_ptr;
    NX_INTERFACE *interface_ptr;
    UINT          status;
    CHAR         *payload_address;    /* Address of the first payload*/
    VOID         *rounded_pool_start; /* Rounded stating address     */

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* Setup interface pointer.  */
    interface_ptr = driver_req_ptr-&gt;nx_ip_driver_interface;

    /* Initialize the driver's information structure.  */

    /* Default IP pointer to NULL.  */
    nx_driver_information.nx_driver_information_ip_ptr = NX_NULL;

    /* Setup the driver state to not initialized.  */
    nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_NOT_INITIALIZED;

    /* Setup the default packet pool for the driver's received packets.  */
    nx_driver_information.nx_driver_information_packet_pool_ptr = ip_ptr-&gt;nx_ip_default_packet_pool;

    /* Get the rounded start pool start. */
    rounded_pool_start = nx_driver_information.nx_driver_information_packet_pool_ptr-&gt;nx_packet_pool_start;

    /* Calculate the address of payload. */
    payload_address = (CHAR *)((ALIGN_TYPE)rounded_pool_start + sizeof(NX_PACKET));

    /* Align the address of payload. */
    payload_address = (CHAR *)((((ALIGN_TYPE)payload_address + NX_PACKET_ALIGNMENT - 1) / NX_PACKET_ALIGNMENT) * NX_PACKET_ALIGNMENT);

    /* Calculate the header size. */
    header_size = (ULONG)((ALIGN_TYPE)payload_address - (ALIGN_TYPE)rounded_pool_start);

    /* Clear the deferred events for the driver.  */
    nx_driver_information.nx_driver_information_deferred_events = 0;

    /* Call the hardware-specific ethernet controller initialization.  */
    status = _nx_driver_hardware_initialize(driver_req_ptr);

    /* Determine if the request was successful.  */
    if(status == NX_SUCCESS)
    {
        /* Successful hardware initialization.  */

        /* Setup driver information to point to IP pointer.  */
        nx_driver_information.nx_driver_information_ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

        /* Setup the link maximum transfer unit. */
        interface_ptr-&gt;nx_interface_ip_mtu_size = NX_DRIVER_ETHERNET_MTU - NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Setup the physical address of this IP instance.  Increment the
    physical address lsw to simulate multiple nodes hanging on the
    ethernet.  */
        interface_ptr-&gt;nx_interface_physical_address_msw = (ULONG)((eth_handle.Init.MACAddr[0] &lt;&lt; 8) | (eth_handle.Init.MACAddr[1]));
        interface_ptr-&gt;nx_interface_physical_address_lsw = (ULONG)((eth_handle.Init.MACAddr[2] &lt;&lt; 24) | (eth_handle.Init.MACAddr[3] &lt;&lt; 16) | (eth_handle.Init.MACAddr[4] &lt;&lt; 8) | (eth_handle.Init.MACAddr[5]));

        /* Indicate to the IP software that IP to physical mapping
    is required.  */
        interface_ptr-&gt;nx_interface_address_mapping_needed = NX_TRUE;

        /* Move the driver's state to initialized.  */
        nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_INITIALIZED;

        /* Indicate successful initialize.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
    else
    {
        /* Initialization failed.  Indicate that the request failed.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_enable                                                   */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the initialize request. The processing     */
/*    in this function is generic. All ethernet controller logic is to    */
/*    be placed in _nx_driver_hardware_enable.                            */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_enable            Process enable request        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_enable(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP               *ip_ptr;
    ETH_MACConfigTypeDef MACConf;
    UINT                 status, duplex, speed = 0;
    INT                  PHYLinkState;
    uint32_t             tickstart;

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* See if we can honor the NX_LINK_ENABLE request.  */
    if(nx_driver_information.nx_driver_information_state &lt; NX_DRIVER_STATE_INITIALIZED)
    {
        /* Mark the request as not successful.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }

    /* Check if it is enabled by someone already */
    if(nx_driver_information.nx_driver_information_state &gt;= NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* Yes, the request has already been made.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_ALREADY_ENABLED;
        return;
    }

    if(nx_eth_phy_init( ) != ETH_PHY_STATUS_OK)
    {
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }

    tickstart = HAL_GetTick( );

    do
    {
        PHYLinkState = nx_eth_phy_get_link_state( );
    }
    while((PHYLinkState &lt;= ETH_PHY_STATUS_LINK_DOWN) && ((HAL_GetTick( ) - tickstart) &lt; PHY_LINK_TIMEOUT));

    /* Get link state */
    if(PHYLinkState &lt;= ETH_PHY_STATUS_LINK_DOWN)
    {
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }
    else
    {
        switch(PHYLinkState)
        {
#if defined(ETH_PHY_1000MBITS_SUPPORTED)
        case ETH_PHY_STATUS_1000MBITS_FULLDUPLEX:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_1000M;
            break;
        case ETH_PHY_STATUS_1000MBITS_HALFDUPLEX:
            duplex = ETH_HALFDUPLEX_MODE;
            speed  = ETH_SPEED_1000M;
            break;
#endif
        case ETH_PHY_STATUS_100MBITS_FULLDUPLEX:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_100M;
            break;
        case ETH_PHY_STATUS_100MBITS_HALFDUPLEX:
            duplex = ETH_HALFDUPLEX_MODE;
            speed  = ETH_SPEED_100M;
            break;
        case ETH_PHY_STATUS_10MBITS_FULLDUPLEX:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_10M;
            break;
        case ETH_PHY_STATUS_10MBITS_HALFDUPLEX:
            duplex = ETH_HALFDUPLEX_MODE;
            speed  = ETH_SPEED_10M;
            break;
        default:
            duplex = ETH_FULLDUPLEX_MODE;
            speed  = ETH_SPEED_100M;
            break;
        }

        /* Get MAC Config MAC */
        HAL_ETH_GetMACConfig(&eth_handle, &MACConf);
        MACConf.DuplexMode = duplex;
        MACConf.Speed      = speed;
#if defined(ETH_DMASBMR_BLEN4) /* ETH AXI support*/
        if(speed == ETH_SPEED_1000M)
            MACConf.PortSelect = DISABLE;
        else
            MACConf.PortSelect = ENABLE;
#endif
        HAL_ETH_SetMACConfig(&eth_handle, &MACConf);
    }

    /* Call hardware specific enable.  */
    status = _nx_driver_hardware_enable(driver_req_ptr);

    /* Was the hardware enable successful?  */
    if(status == NX_SUCCESS)
    {
        /* Update the driver state to link enabled.  */
        nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_LINK_ENABLED;

        /* Mark request as successful.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;

        /* Mark the IP instance as link up.  */
        ip_ptr-&gt;nx_ip_driver_link_up = NX_TRUE;
    }
    else
    {
        /* Enable failed.  Indicate that the request failed.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_disable                                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the disable request. The processing        */
/*    in this function is generic. All ethernet controller logic is to    */
/*    be placed in _nx_driver_hardware_disable.                           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_disable           Process disable request       */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_disable(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP *ip_ptr;
    UINT   status;

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* Check if the link is enabled.  */
    if(nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* The link is not enabled, so just return an error.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
        return;
    }

    /* Call hardware specific disable.  */
    status = _nx_driver_hardware_disable(driver_req_ptr);

    /* Was the hardware disable successful?  */
    if(status == NX_SUCCESS)
    {
        /* Mark the IP instance as link down.  */
        ip_ptr-&gt;nx_ip_driver_link_up = NX_FALSE;

        /* Update the driver state back to initialized.  */
        nx_driver_information.nx_driver_information_state = NX_DRIVER_STATE_INITIALIZED;

        /* Mark request as successful.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
    else
    {
        /* Disable failed, return an error.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_packet_send                                              */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the packet send request. The processing    */
/*    in this function is generic. All ethernet controller packet send    */
/*    logic is to be placed in _nx_driver_hardware_packet_send.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_packet_send       Process packet send request   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
#ifdef MULTI_QUEUE_FEATURE
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr)
{
    NX_PACKET *packet_ptr;
    UINT       status;
    USHORT     ether_type;
    NX_INTERFACE
    *interface_ptr;

    /* Check to make sure the link is up.  */
    if(nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* Inidate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(driver_req_ptr-&gt;nx_ip_driver_packet);
        return;
    }

    interface_ptr = driver_req_ptr-&gt;nx_ip_driver_interface;

    /* Process driver send packet.  */

    /* Place the ethernet frame at the front of the packet.  */
    packet_ptr = driver_req_ptr-&gt;nx_ip_driver_packet;

    if(driver_req_ptr-&gt;nx_ip_driver_command != NX_LINK_RAW_PACKET_SEND)
    {
        /* Get Ethernet type.  */
        switch(driver_req_ptr-&gt;nx_ip_driver_command)
        {
        case NX_LINK_ARP_SEND:
        case NX_LINK_ARP_RESPONSE_SEND:
            {
                ether_type = NX_DRIVER_ETHERNET_ARP;
                break;
            }
        case NX_LINK_RARP_SEND:
            {
                ether_type = NX_DRIVER_ETHERNET_RARP;
                break;
            }
        default:
            {
                if(packet_ptr-&gt;nx_packet_ip_version == 4)
                {
                    ether_type = NX_DRIVER_ETHERNET_IP;
                }
                else
                {
                    ether_type = NX_DRIVER_ETHERNET_IPV6;
                }
                break;
            }
        }

        /* Add Ethernet header.  */
        if(nx_link_ethernet_header_add(nx_driver_information.nx_driver_information_ip_ptr, interface_ptr-&gt;nx_interface_index, packet_ptr, driver_req_ptr-&gt;nx_ip_driver_physical_address_msw, driver_req_ptr-&gt;nx_ip_driver_physical_address_lsw, ether_type))
        {
            /* Release the packet.  */
            nx_packet_transmit_release(packet_ptr);
            return;
        }
    }

    /* Transmit the packet through the Ethernet controller low level access routine. */
    status = _nx_driver_hardware_packet_send(packet_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Driver's hardware send packet routine failed to send the packet.  */

        /* Remove the Ethernet header.  */
        NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

        /* Indicate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(packet_ptr);
    }
    else
    {
        /* Set the status of the request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}
#else
static VOID _nx_driver_packet_send(NX_IP_DRIVER *driver_req_ptr)
{
    NX_IP     *ip_ptr;
    NX_PACKET *packet_ptr;
    ULONG     *ethernet_frame_ptr;
    UINT       status;

    /* Setup the IP pointer from the driver request.  */
    ip_ptr = driver_req_ptr-&gt;nx_ip_driver_ptr;

    /* Check to make sure the link is up.  */
    if(nx_driver_information.nx_driver_information_state != NX_DRIVER_STATE_LINK_ENABLED)
    {
        /* Inidate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(driver_req_ptr-&gt;nx_ip_driver_packet);
        return;
    }

    /* Process driver send packet.  */

    /* Place the ethernet frame at the front of the packet.  */
    packet_ptr = driver_req_ptr-&gt;nx_ip_driver_packet;

    /* Adjust the prepend pointer.  */
    packet_ptr-&gt;nx_packet_prepend_ptr = packet_ptr-&gt;nx_packet_prepend_ptr - NX_DRIVER_ETHERNET_FRAME_SIZE;

    /* Adjust the packet length.  */
    packet_ptr-&gt;nx_packet_length = packet_ptr-&gt;nx_packet_length + NX_DRIVER_ETHERNET_FRAME_SIZE;

    /* Setup the ethernet frame pointer to build the ethernet frame.  Backup another 2
  * bytes to get 32-bit word alignment.  */
    ethernet_frame_ptr = (ULONG *)(packet_ptr-&gt;nx_packet_prepend_ptr - 2);

    /* Set up the hardware addresses in the Ethernet header. */
    *ethernet_frame_ptr       = driver_req_ptr-&gt;nx_ip_driver_physical_address_msw;
    *(ethernet_frame_ptr + 1) = driver_req_ptr-&gt;nx_ip_driver_physical_address_lsw;

    *(ethernet_frame_ptr + 2) = (ip_ptr-&gt;nx_ip_arp_physical_address_msw &lt;&lt; 16) | (ip_ptr-&gt;nx_ip_arp_physical_address_lsw &gt;&gt; 16);
    *(ethernet_frame_ptr + 3) = (ip_ptr-&gt;nx_ip_arp_physical_address_lsw &lt;&lt; 16);

    /* Set up the frame type field in the Ethernet harder. */
    if((driver_req_ptr-&gt;nx_ip_driver_command == NX_LINK_ARP_SEND) || (driver_req_ptr-&gt;nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND))
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_ARP;
    }
    else if(driver_req_ptr-&gt;nx_ip_driver_command == NX_LINK_RARP_SEND)
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_RARP;
    }

#ifdef FEATURE_NX_IPV6
    else if(packet_ptr-&gt;nx_packet_ip_version == NX_IP_VERSION_V6)
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_IPV6;
    }
#endif /* FEATURE_NX_IPV6 */

    else
    {
        *(ethernet_frame_ptr + 3) |= NX_DRIVER_ETHERNET_IP;
    }

    /* Endian swapping if NX_LITTLE_ENDIAN is defined.  */
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr));
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 1));
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 2));
    NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 3));

    /* Determine if the packet exceeds the driver's MTU.  */
    if(packet_ptr-&gt;nx_packet_length &gt; NX_DRIVER_ETHERNET_MTU)
    {
        /* This packet exceeds the size of the driver's MTU. Simply throw it away! */

        /* Remove the Ethernet header.  */
        NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

        /* Indicate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(packet_ptr);
        return;
    }

    /* Transmit the packet through the Ethernet controller low level access routine. */
    status = _nx_driver_hardware_packet_send(packet_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Driver's hardware send packet routine failed to send the packet.  */

        /* Remove the Ethernet header.  */
        NX_DRIVER_ETHERNET_HEADER_REMOVE(packet_ptr);

        /* Indicate an unsuccessful packet send.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;

        /* Link is not up, simply free the packet.  */
        nx_packet_transmit_release(packet_ptr);
    }
    else
    {
        /* Set the status of the request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}
#endif

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_multicast_join                                           */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the multicast join request. The processing */
/*    in this function is generic. All ethernet controller multicast join */
/*    logic is to be placed in _nx_driver_hardware_multicast_join.        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_multicast_join    Process multicast join request*/
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_multicast_join(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific multicast join function. */
    status = _nx_driver_hardware_multicast_join(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_multicast_leave                                          */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the multicast leave request. The           */
/*    processing in this function is generic. All ethernet controller     */
/*    multicast leave logic is to be placed in                            */
/*    _nx_driver_hardware_multicast_leave.                                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_multicast_leave   Process multicast leave req   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_multicast_leave(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific multicast leave function. */
    status = _nx_driver_hardware_multicast_leave(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_get_status                                               */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the get status request. The processing     */
/*    in this function is generic. All ethernet controller get status     */
/*    logic is to be placed in _nx_driver_hardware_get_status.            */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_hardware_get_status        Process get status request    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_get_status(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific get status function. */
    status = _nx_driver_hardware_get_status(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_capability_get                                           */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the get capability request.                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_capability_get(NX_IP_DRIVER *driver_req_ptr)
{
    /* Return the capability of the Ethernet controller.  */
    *(driver_req_ptr-&gt;nx_ip_driver_return_ptr) = NX_DRIVER_CAPABILITY;

    /* Return the success status.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_capability_set                                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the set capability request.                */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_capability_set(NX_IP_DRIVER *driver_req_ptr)
{
    UINT status;

    /* Call hardware specific get status function. */
    status = _nx_driver_hardware_capability_set(driver_req_ptr);

    /* Determine if there was an error.  */
    if(status != NX_SUCCESS)
    {
        /* Indicate an unsuccessful request.  */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_DRIVER_ERROR;
    }
    else
    {
        /* Indicate the request was successful.   */
        driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
    }
}
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_deferred_processing                                      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    XC, Microsoft Corporation                                           */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing the deferred ISR action within the context */
/*    of the IP thread.                                                   */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver command from the IP    */
/*                                            thread                      */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_driver_packet_transmitted        Clean up after transmission    */
/*    _nx_driver_packet_received           Process a received packet      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Driver entry function                                               */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_deferred_processing(NX_IP_DRIVER *driver_req_ptr)
{
    TX_INTERRUPT_SAVE_AREA

    ULONG deferred_events;
#ifdef MULTI_QUEUE_FEATURE
    ULONG buff_in_use;
#endif
    /* Disable interrupts.  */
    TX_DISABLE

    /* Pickup deferred events.  */
    deferred_events                                             = nx_driver_information.nx_driver_information_deferred_events;
    nx_driver_information.nx_driver_information_deferred_events = 0;

    /* Restore interrupts.  */
    TX_RESTORE

#ifdef MULTI_QUEUE_FEATURE
    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH0)
    {
        eth_handle.TxOpCH = ETH_DMA_CH0_IDX;
        buff_in_use       = HAL_ETH_GetTxBuffersNumber(&eth_handle);

        if(buff_in_use &gt;= NX_DRIVER_TX_RELEASE_THRESHOLD)
        {
            HAL_ETH_ReleaseTxPacket(&eth_handle);
            nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use[ETH_DMA_CH0_IDX] = buff_in_use;
        }
    }

    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH1)
    {
        eth_handle.TxOpCH = ETH_DMA_CH1_IDX;
        buff_in_use       = HAL_ETH_GetTxBuffersNumber(&eth_handle);

        if(buff_in_use &gt;= NX_DRIVER_TX_RELEASE_THRESHOLD)
        {
            HAL_ETH_ReleaseTxPacket(&eth_handle);
            nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use[ETH_DMA_CH1_IDX] = buff_in_use;
        }
    }

    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH0)
    {
        eth_handle.RxOpCH = ETH_DMA_CH0_IDX;
        _nx_driver_hardware_packet_received( );
    }

    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH1)
    {
        eth_handle.RxOpCH = ETH_DMA_CH1_IDX;
        _nx_driver_hardware_packet_received( );
    }

#else
    /* Check for a transmit complete event.  */
    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_TRANSMITTED)
    {
        /* Process transmitted packet(s).  */
        HAL_ETH_ReleaseTxPacket(&eth_handle);
    }
    /* Check for received packet.  */
    if(deferred_events & NX_DRIVER_DEFERRED_PACKET_RECEIVED)
    {
        /* Process received packet(s).  */
        _nx_driver_hardware_packet_received( );
    }
#endif
    /* Mark request as successful.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;
}

#ifdef NX_DRIVER_ENABLE_PTP
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_transfer_to_netx                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing incoming packets.  This routine would      */
/*    be called from the driver-specific receive packet processing        */
/*    function _nx_driver_hardware.                                       */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ip_ptr                                Pointer to IP protocol block  */
/*    packet_ptr                            Packet pointer                */
/*    ptp_ts_ptr                            PTP timestamp pointer         */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Error indication                                                    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_ip_packet_receive                 NetX IP packet receive        */
/*    _nx_ip_packet_deferred_receive        NetX IP packet receive        */
/*    _nx_arp_packet_deferred_receive       NetX ARP packet receive       */
/*    _nx_rarp_packet_deferred_receive      NetX RARP packet receive      */
/*    _nx_packet_release                    Release packet                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_hardware_packet_received   Driver packet receive function*/
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr, ULONG *ptp_ts_ptr)
{
    NX_LINK_TIME link_time;

    link_time.nano_second = ptp_ts_ptr[0];
    link_time.second_high = 0;
    link_time.second_low  = ptp_ts_ptr[1];

    nx_link_ethernet_packet_received(ip_ptr, nx_driver_information.nx_driver_information_interface-&gt;nx_interface_index, packet_ptr, &link_time);
}
#else
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_transfer_to_netx                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processing incoming packets.  This routine would      */
/*    be called from the driver-specific receive packet processing        */
/*    function _nx_driver_hardware.                              */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    ip_ptr                                Pointer to IP protocol block  */
/*    packet_ptr                            Packet pointer                */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Error indication                                                    */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_ip_packet_receive                 NetX IP packet receive        */
/*    _nx_ip_packet_deferred_receive        NetX IP packet receive        */
/*    _nx_arp_packet_deferred_receive       NetX ARP packet receive       */
/*    _nx_rarp_packet_deferred_receive      NetX RARP packet receive      */
/*    _nx_packet_release                    Release packet                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_hardware_packet_received   Driver packet receive function*/
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static VOID _nx_driver_transfer_to_netx(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
{
    /* Set the interface for the incoming packet.  */
    packet_ptr-&gt;nx_packet_ip_interface = nx_driver_information.nx_driver_information_interface;

    /* Pickup the packet header to determine where the packet needs to be
  sent.  */
    packet_type = (USHORT)(((UINT)(*(packet_ptr-&gt;nx_packet_prepend_ptr + 12))) &lt;&lt; 8) | ((UINT)(*(packet_ptr-&gt;nx_packet_prepend_ptr + 13)));

    /* Route the incoming packet according to its ethernet type.  */
    if(packet_type == NX_DRIVER_ETHERNET_IP || packet_type == NX_DRIVER_ETHERNET_IPV6)
    {
        /* Note:  The length reported by some Ethernet hardware includes
    bytes after the packet as well as the Ethernet header.  In some
    cases, the actual packet length after the Ethernet header should
    be derived from the length in the IP header (lower 16 bits of
    the first 32-bit word).  */

        /* Clean off the Ethernet header.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Adjust the packet length.  */
        packet_ptr-&gt;nx_packet_length -= NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Route to the ip receive function.  */
        _nx_ip_packet_deferred_receive(ip_ptr, packet_ptr);
    }
    else if(packet_type == NX_DRIVER_ETHERNET_ARP)
    {
        /* Clean off the Ethernet header.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Adjust the packet length.  */
        packet_ptr-&gt;nx_packet_length -= NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Route to the ARP receive function.  */
        _nx_arp_packet_deferred_receive(ip_ptr, packet_ptr);
    }
    else if(packet_type == NX_DRIVER_ETHERNET_RARP)
    {
        /* Clean off the Ethernet header.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Adjust the packet length.  */
        packet_ptr-&gt;nx_packet_length -= NX_DRIVER_ETHERNET_FRAME_SIZE;

        /* Route to the RARP receive function.  */
        _nx_rarp_packet_deferred_receive(ip_ptr, packet_ptr);
    }
    else
    {
        /* Invalid ethernet header... release the packet.  */
        nx_packet_release(packet_ptr);
    }
}
#endif /* NX_DRIVER_ENABLE_PTP */

/****** DRIVER SPECIFIC ****** Start of part/vendor specific internal driver functions.  */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_initialize                                      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific initialization.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ETH_BSP_Config                        Configure Ethernet            */
/*    ETH_MACAddressConfig                  Setup MAC address             */
/*    ETH_DMARxDescReceiveITConfig          Enable receive descriptors    */
/*    nx_packet_allocate                    Allocate receive packet(s)    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_initialize                 Driver initialize processing  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_initialize(NX_IP_DRIVER *driver_req_ptr)
{
#ifdef ETH_MULTIQUEUE_SUPPORTED
    uint32_t ch;
#endif

    /* Default to successful return.  */
    driver_req_ptr-&gt;nx_ip_driver_status = NX_SUCCESS;

    /* Setup indices.  */
    nx_driver_information.nx_driver_information_receive_current_index  = 0;
    nx_driver_information.nx_driver_information_transmit_current_index = 0;
    nx_driver_information.nx_driver_information_transmit_release_index = 0;

    /* Clear the number of buffers in use counter.  */
#ifdef ETH_MULTIQUEUE_SUPPORTED
    for(ch = 0; ch &lt; ETH_DMA_TX_CH_CNT; ch++)
    {
        nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use[ch] = 0;
    }
#else
    nx_driver_information.nx_driver_information_number_of_transmit_buffers_in_use = 0;
#endif

    /* Make sure there are receive packets... otherwise, return an error.  */
    if(nx_driver_information.nx_driver_information_packet_pool_ptr == NULL)
    {
        /* There must be receive packets. If not, return an error!  */
        return (NX_DRIVER_ERROR);
    }

#ifdef NX_DRIVER_ETH_HW_IP_INIT
    nx_eth_init( );
#endif /* NX_DRIVER_ETH_HW_IP_INIT */

    ETH_DMAConfigTypeDef dmaDefaultConf;

    memset(&dmaDefaultConf, 0, sizeof(ETH_DMAConfigTypeDef));
    HAL_ETH_GetDMAConfig(&eth_handle, &dmaDefaultConf);

    /*--------------- ETHERNET DMA registers default Configuration --------------*/
#ifdef ETH_MULTIQUEUE_SUPPORTED
    /* Common DMA configuration */
    dmaDefaultConf.AddressAlignedBeats          = ENABLE;
    dmaDefaultConf.AXIBLENMaxSize               = ETH_BLEN_MAX_SIZE_4;
    dmaDefaultConf.BurstMode                    = ETH_BURSTLENGTH_FIXED;
    dmaDefaultConf.RxOSRLimit                   = ETH_RX_OSR_LIMIT_3;
    dmaDefaultConf.TxOSRLimit                   = ETH_TX_OSR_LIMIT_3;
    dmaDefaultConf.TransmitArbitrationAlgorithm = ETH_DMATXARBITRATION_FIXED_PRIO;
    dmaDefaultConf.TransmitPriority             = DISABLE;

    for(ch = 0; ch &lt; ETH_DMA_CH_CNT; ch++)
    {
        /* DMA CH configuration */
        dmaDefaultConf.DMACh[ch].FlushRxPacket        = DISABLE;
        dmaDefaultConf.DMACh[ch].PBLx8Mode            = DISABLE;
        dmaDefaultConf.DMACh[ch].RxDMABurstLength     = ETH_RXDMABURSTLENGTH_32BEAT;
        dmaDefaultConf.DMACh[ch].SecondPacketOperate  = DISABLE;
        dmaDefaultConf.DMACh[ch].TCPSegmentation      = DISABLE;
        dmaDefaultConf.DMACh[ch].TxDMABurstLength     = ETH_TXDMABURSTLENGTH_32BEAT;
        dmaDefaultConf.DMACh[ch].DescriptorSkipLength = ETH_DMA_DESC_SKIP_LENGTH_32;
        dmaDefaultConf.DMACh[ch].MaximumSegmentSize   = 0x218U;
    }
#else

#if defined(ETH_DMASBMR_BLEN4) /* ETH AXI support*/
    dmaDefaultConf.DMAArbitration                                                 = ETH_DMAARBITRATION_TX;
#else
    dmaDefaultConf.DMAArbitration = ETH_DMAARBITRATION_RX1_TX1;
#endif
    dmaDefaultConf.AddressAlignedBeats                                            = ENABLE;
    dmaDefaultConf.BurstMode                                                      = ETH_BURSTLENGTH_FIXED;
    dmaDefaultConf.TxDMABurstLength                                               = ETH_TXDMABURSTLENGTH_32BEAT;
    dmaDefaultConf.RxDMABurstLength                                               = ETH_RXDMABURSTLENGTH_32BEAT;
    dmaDefaultConf.FlushRxPacket                                                  = DISABLE;
#ifndef STM32_ETH_HAL_LEGACY
    dmaDefaultConf.PBLx8Mode                                                      = DISABLE;
#if defined(ETH_DMASBMR_BLEN4) /* ETH AXI support*/
    dmaDefaultConf.RxOSRLimit                                                     = ETH_RX_OSR_LIMIT_3;
    dmaDefaultConf.TxOSRLimit                                                     = ETH_TX_OSR_LIMIT_3;
    dmaDefaultConf.AXIBLENMaxSize                                                 = ETH_BLEN_MAX_SIZE_16;
#else
    dmaDefaultConf.RebuildINCRxBurst = DISABLE;
#endif
    dmaDefaultConf.SecondPacketOperate                                            = ENABLE;
    dmaDefaultConf.TCPSegmentation                                                = DISABLE;
    dmaDefaultConf.MaximumSegmentSize                                             = 536;
#endif

#ifdef STM32_ETH_HAL_LEGACY
    dmaDefaultConf.DropTCPIPChecksumErrorFrame                                    = ENABLE;
    dmaDefaultConf.ReceiveStoreForward                                            = DISABLE;
    dmaDefaultConf.TransmitStoreForward                                           = ENABLE;
    dmaDefaultConf.TransmitThresholdControl                                       = ENABLE;
    dmaDefaultConf.ForwardErrorFrames                                             = DISABLE;
    dmaDefaultConf.ReceiveThresholdControl                                        = DISABLE;
    dmaDefaultConf.SecondFrameOperate                                             = DISABLE;
    dmaDefaultConf.EnhancedDescriptorFormat                                       = DISABLE;
    dmaDefaultConf.DescriptorSkipLength                                           = DISABLE;
#endif
#endif /* ETH_MULTIQUEUE_SUPPORTED */

    /* enable OSF bit to enhance throughput */
    HAL_ETH_SetDMAConfig(&eth_handle, &dmaDefaultConf);
#ifdef STM32_ETH_PROMISCUOUS_ENABLE
    FilterConfig.PromiscuousMode = ENABLE;
#else
    FilterConfig.PromiscuousMode                                                  = DISABLE;
#endif
    FilterConfig.HashUnicast              = DISABLE;
    FilterConfig.HashMulticast            = DISABLE;
    FilterConfig.DestAddrInverseFiltering = DISABLE;
    FilterConfig.PassAllMulticast         = DISABLE;
    FilterConfig.BroadcastFilter          = ENABLE;
    FilterConfig.SrcAddrInverseFiltering  = DISABLE;
    FilterConfig.SrcAddrFiltering         = DISABLE;
    FilterConfig.HachOrPerfectFilter      = DISABLE;
    FilterConfig.ReceiveAllMode           = DISABLE;
    FilterConfig.ControlPacketsFilter     = 0x00;

    /* Set Tx packet config common parameters */
    memset(&TxPacketCfg, 0, sizeof(ETH_TxPacketConfigTypeDef));
    TxPacketCfg.Attributes = ETH_TX_PACKETS_FEATURES_CSUM;
    TxPacketCfg.CRCPadCtrl = ETH_CRC_PAD_DISABLE;

    /* Clear the number of buffers in use counter.  */
    nx_driver_information.nx_driver_information_multicast_count = 0;

    /* Return success!  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_enable                                          */
/*                                                            6.1         */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific link enable requests.     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ETH_Start                             Start Ethernet operation      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_enable                     Driver link enable processing */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_enable(NX_IP_DRIVER *driver_req_ptr)
{
    /* Call STM32 library to start Ethernet operation.  */
    HAL_ETH_Start_IT(&eth_handle);

    /* Return success!  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_disable                                         */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific link disable requests.    */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    ETH_MACTransmissionCmd                Disable transmit              */
/*    ETH_FlushTransmitFIFO                 Flush transmit FIFO           */
/*    ETH_MACReceptionCmd                   Disable receive               */
/*    ETH_DMATransmissionCmd                Stop DMA transmission         */
/*    ETH_DMAReceptionCmd                   Stop DMA reception            */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_disable                    Driver link disable processing*/
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_disable(NX_IP_DRIVER *driver_req_ptr)
{
    HAL_ETH_Stop(&eth_handle);

    /* Return success!  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_packet_send                                     */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific packet send requests.     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    packet_ptr                            Pointer to packet to send     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    [_nx_driver_transmit_packet_enqueue]  Optional internal transmit    */
/*                                            packet queue routine        */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_packet_send                Driver packet send processing */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
#ifdef MULTI_QUEUE_FEATURE
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
{
    UINT          status;
    UCHAR         channel_number = 0;

    NX_INTERFACE *interface_ptr;

    interface_ptr = nx_driver_information.nx_driver_information_interface;

    status        = nx_shaper_hw_queue_id_get(interface_ptr, packet_ptr, &channel_number);

    status        = _nx_driver_hardware_packet_send_distribute(packet_ptr, channel_number);

    return status;
}

static UINT _nx_driver_hardware_packet_send_distribute(NX_PACKET *packet_ptr, UINT channel_number)
{
    NX_PACKET               *pktIdx;
    UINT                     buffLen = 0;
    int                      i       = 0;

    static ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];

    memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));

    for(pktIdx = packet_ptr; pktIdx != NX_NULL; pktIdx = pktIdx-&gt;nx_packet_next)
    {
        if(i &gt;= ETH_TX_DESC_CNT)
        {
            return NX_DRIVER_ERROR;
        }

        Txbuffer[i].buffer = pktIdx-&gt;nx_packet_prepend_ptr;
        Txbuffer[i].len    = (pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);
        buffLen += (pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);

        if(i &gt; 0)
        {
            Txbuffer[i - 1].next = &Txbuffer[i];
        }

        if(pktIdx-&gt;nx_packet_next == NULL)
        {
            Txbuffer[i].next = NULL;
        }

        i++;
        clean_cache_by_addr((uint32_t *)(pktIdx-&gt;nx_packet_data_start), pktIdx-&gt;nx_packet_data_end - pktIdx-&gt;nx_packet_data_start);
    }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & (NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM))
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    }
    else if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_INSERT;
    }
#else
    TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_DISABLE;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

#ifdef NX_DRIVER_ENABLE_PTP
    /* Enable PTP timestamp */
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_PTP_TIMESTAMP)
    {
        HAL_ETH_PTP_InsertTxTimestamp(&eth_handle);
    }
#endif /* NX_DRIVER_ENABLE_PTP */

    TxPacketCfg.TxDMACh  = channel_number;
    TxPacketCfg.Length   = buffLen;
    TxPacketCfg.TxBuffer = Txbuffer;
    TxPacketCfg.pData    = (uint32_t *)packet_ptr;

    if(HAL_ETH_Transmit_IT(&eth_handle, &TxPacketCfg) != HAL_OK)
        return NX_DRIVER_ERROR;

    return NX_SUCCESS;
}

#else
static UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr)
{
    NX_PACKET               *pktIdx;
    UINT                     buffLen = 0;

    static ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
    memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));

    int i = 0;

    for(pktIdx = packet_ptr; pktIdx != NX_NULL; pktIdx = pktIdx-&gt;nx_packet_next)
    {
        if(i &gt;= ETH_TX_DESC_CNT)
        {
            return NX_DRIVER_ERROR;
        }

        Txbuffer[i].buffer = pktIdx-&gt;nx_packet_prepend_ptr;
        Txbuffer[i].len    = (pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);
        buffLen += (pktIdx-&gt;nx_packet_append_ptr - pktIdx-&gt;nx_packet_prepend_ptr);

        if(i &gt; 0)
        {
            Txbuffer[i - 1].next = &Txbuffer[i];
        }

        if(pktIdx-&gt;nx_packet_next == NULL)
        {
            Txbuffer[i].next = NULL;
        }

        i++;
        clean_cache_by_addr((uint32_t *)(pktIdx-&gt;nx_packet_data_start), pktIdx-&gt;nx_packet_data_end - pktIdx-&gt;nx_packet_data_start);
    }

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
    if(packet_ptr-&gt;nx_packet_interface_capability_flag & (NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM | NX_INTERFACE_CAPABILITY_ICMPV6_TX_CHECKSUM))
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    }
    else if(packet_ptr-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
    {
        TxPacketCfg.ChecksumCtrl = ETH_CHECKSUM_IPHDR_INSERT;
    }
#else
    TxPacketCfg.ChecksumCtrl      = ETH_CHECKSUM_DISABLE;
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

    TxPacketCfg.Length   = buffLen;
    TxPacketCfg.TxBuffer = Txbuffer;
    TxPacketCfg.pData    = (uint32_t *)packet_ptr;

    if(HAL_ETH_Transmit_IT(&eth_handle, &TxPacketCfg))
    {
        return (NX_DRIVER_ERROR);
    }

    return (NX_SUCCESS);
}
#endif /* MULTI_QUEUE_FEATURE */

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_multicast_join                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific multicast join requests.  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_multicast_join             Driver multicast join         */
/*                                            processing                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_multicast_join(NX_IP_DRIVER *driver_req_ptr)
{
    /* Increase the multicast count.  */
    nx_driver_information.nx_driver_information_multicast_count++;

    /* Enable multicast frame reception.  */
    FilterConfig.PassAllMulticast = ENABLE;
    HAL_ETH_SetMACFilterConfig(&eth_handle, &FilterConfig);

    /* Return success.  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_multicast_leave                                 */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific multicast leave requests. */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]*/
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_multicast_leave            Driver multicast leave        */
/*                                            processing                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_multicast_leave(NX_IP_DRIVER *driver_req_ptr)
{
    /* Decrease the multicast count.  */
    nx_driver_information.nx_driver_information_multicast_count--;

    /* If multicast count reaches zero, disable multicast frame reception.  */
    if(nx_driver_information.nx_driver_information_multicast_count == 0)
    {
        /* Disable multicast frame reception.  */
        FilterConfig.PassAllMulticast = DISABLE;
        HAL_ETH_SetMACFilterConfig(&eth_handle, &FilterConfig);
    }

    /* Return success.  */
    return (NX_SUCCESS);
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_get_status                                      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific get status requests.      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                        Driver request pointer        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]*/
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_get_status                 Driver get status processing  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_get_status(NX_IP_DRIVER *driver_req_ptr)
{
    INT PHYLinkState;

    /* Get link status. */
    PHYLinkState = nx_eth_phy_get_link_state( );

    /* Check link status. */
    if(PHYLinkState &lt;= ETH_PHY_STATUS_LINK_DOWN)
    {
        /* Update Link status if physical link is down. */
        *(driver_req_ptr-&gt;nx_ip_driver_return_ptr) = NX_FALSE;
    }
    else
    {
        /* Update Link status if physical link is up. */
        *(driver_req_ptr-&gt;nx_ip_driver_return_ptr) = NX_TRUE;
    }

    /* Return success. */
    return NX_SUCCESS;
}

void HAL_ETH_TxFreeCallback(uint32_t *buff)
{
    NX_PACKET *release_packet = (NX_PACKET *)buff;

    /* Remove the Ethernet header and release the packet.  */
    NX_DRIVER_ETHERNET_HEADER_REMOVE(release_packet);

    /* Release the packet.  */
    nx_packet_transmit_release(release_packet);
}

#ifdef NX_DRIVER_ENABLE_PTP

void HAL_ETH_TxPtpCallback(uint32_t *buff, ETH_TimeStampTypeDef *timestamp)
{
    NX_PTP_TIME ts;
    NX_PACKET  *release_packet = (NX_PACKET *)buff;

    if(release_packet-&gt;nx_packet_interface_capability_flag & NX_INTERFACE_CAPABILITY_PTP_TIMESTAMP)
    {
        /* store timestamp in NX_PTP_TIME structure */
        ts.second_high = 0;
        ts.second_low  = timestamp-&gt;TimeStampHigh;
        ts.nanosecond  = timestamp-&gt;TimeStampLow;

        /* call notification callback */
        nx_ptp_client_packet_timestamp_notify(nx_driver_information.nx_driver_ptp_ptr, release_packet, &ts);
    }
}
#endif /* NX_DRIVER_ENABLE_PTP */

static VOID _nx_driver_hardware_packet_received(VOID)
{
    NX_PACKET *received_packet_ptr;

#ifdef NX_DRIVER_ENABLE_PTP
    ULONG                ts[2] = {0, 0};
    ETH_TimeStampTypeDef timestamp;
#endif /* NX_DRIVER_ENABLE_PTP */

    while(HAL_ETH_ReadData(&eth_handle, (void **)&received_packet_ptr) == HAL_OK)
    {
#ifdef NX_DRIVER_ENABLE_PTP
        /* Save PTP timestamp */
        HAL_ETH_PTP_GetRxTimestamp(&eth_handle, &timestamp);
        ts[0] = timestamp.TimeStampLow;
        ts[1] = timestamp.TimeStampHigh;

        /* Transfer the packet to NetX.  */
        _nx_driver_transfer_to_netx(nx_driver_information.nx_driver_information_ip_ptr, received_packet_ptr, ts);
#else
        /* Transfer the packet to NetX.  */
        _nx_driver_transfer_to_netx(nx_driver_information.nx_driver_information_ip_ptr, received_packet_ptr);

#endif /* NX_DRIVER_ENABLE_PTP */
    }
}

void HAL_ETH_RxAllocateCallback(uint8_t **buff)
{
    NX_PACKET *packet_ptr;
    if(nx_packet_allocate(nx_driver_information.nx_driver_information_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_NO_WAIT) == NX_SUCCESS)
    {
        /* Adjust the packet.  */
        packet_ptr-&gt;nx_packet_prepend_ptr += 2;
        invalidate_cache_by_addr((uint32_t *)packet_ptr-&gt;nx_packet_data_start, packet_ptr-&gt;nx_packet_data_end - packet_ptr-&gt;nx_packet_data_start);
        *buff = packet_ptr-&gt;nx_packet_prepend_ptr;
    }
    else
    {
        /* Rx Buffer Pool is exhausted. */
        *buff = NULL;
    }
}

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                                              */
/*                                                                        */
/*    HAL_ETH_RxLinkCallback                                              */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function chains all received packets before passing            */
/*    the first one to NetXDuo stack.                                     */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    first_packet_ptr           pointer to first received packet         */
/*    last_packet_ptr            pointer to last received packet          */
/*    buff                       pointer to received data                 */
/*    length                     received data length                     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    received packet pointer                                             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    HAL_ETH_ReadData              Read a received packet                */
/*                                                                        */
/**************************************************************************/
void HAL_ETH_RxLinkCallback(void **first_packet_ptr, void **last_packet_ptr, uint8_t *buff, uint16_t Length)
{
    NX_PACKET **first_nx_packet_ptr = (NX_PACKET **)first_packet_ptr;
    NX_PACKET **last_nx_packet_ptr  = (NX_PACKET **)last_packet_ptr;
    NX_PACKET  *received_packet_ptr;

    /* Indicate the offset of the received data.  */
    uint8_t *data_buffer_ptr                  = buff - 2U - header_size;

    received_packet_ptr                       = (NX_PACKET *)data_buffer_ptr;
    received_packet_ptr-&gt;nx_packet_append_ptr = received_packet_ptr-&gt;nx_packet_prepend_ptr + Length;
    received_packet_ptr-&gt;nx_packet_length     = Length;

    /* Check whether this is the first packet. */
    if(*first_nx_packet_ptr == NULL)
    {
        /* Add the first buffer of the packet. */
        *first_nx_packet_ptr = received_packet_ptr;
    }
    /* This is not the first packet. */
    else
    {
        /* Add the rest of the buffer to the end of the packet. */
        (*last_nx_packet_ptr)-&gt;nx_packet_next = received_packet_ptr;
    }
    /* Save the current packet in order to use it in the next iteration. */
    *last_nx_packet_ptr = received_packet_ptr;
}

#ifdef NX_ENABLE_INTERFACE_CAPABILITY
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_driver_hardware_capability_set                                  */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function processes hardware-specific capability set requests.  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    driver_req_ptr                         Driver request pointer       */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_driver_capability_set             Capability set processing     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
static UINT _nx_driver_hardware_capability_set(NX_IP_DRIVER *driver_req_ptr)
{
    return NX_SUCCESS;
}
#endif /* NX_ENABLE_INTERFACE_CAPABILITY */

void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
    ULONG deffered_events;
    deffered_events = nx_driver_information.nx_driver_information_deferred_events;
#ifdef MULTI_QUEUE_FEATURE
    uint32_t channel = heth-&gt;RxCH;

    if((channel & ETH_DMA_CH0) == ETH_DMA_CH0)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH0;

    if((channel & ETH_DMA_CH1) == ETH_DMA_CH1)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_RECEIVED_CH1;

#else
    nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_RECEIVED;
#endif /* MULTI_QUEUE_FEATURE */
    if(!deffered_events)
    {
        /* Call NetX deferred driver processing.  */
        _nx_ip_driver_deferred_processing(nx_driver_information.nx_driver_information_ip_ptr);
    }
}

void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth)
{
    ULONG deffered_events;
    deffered_events = nx_driver_information.nx_driver_information_deferred_events;
#ifdef MULTI_QUEUE_FEATURE
    uint32_t channel = heth-&gt;TxCH;

    if((channel & ETH_DMA_CH0) == ETH_DMA_CH0)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH0;

    if((channel & ETH_DMA_CH1) == ETH_DMA_CH1)
        nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_TRANSMITTED_CH1;
#else
    nx_driver_information.nx_driver_information_deferred_events |= NX_DRIVER_DEFERRED_PACKET_TRANSMITTED;
#endif /* MULTI_QUEUE_FEATURE */

    if(!deffered_events)
    {
        /* Call NetX deferred driver processing.  */
        _nx_ip_driver_deferred_processing(nx_driver_information.nx_driver_information_ip_ptr);
    }
}

#ifdef NX_DRIVER_ENABLE_PTP
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    nx_driver_ptp_clock_callback                                        */
/*                                                           6.x          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function handles PTP clock operations.                         */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    client_ptr                                  Client pointer          */
/*    operation                                   operation               */
/*    time_ptr                                    Time pointer            */
/*    packet_ptr                                  Packet pointer          */
/*    callback_data                               callback data           */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                [NX_SUCCESS|NX_DRIVER_ERROR]  */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    NetX PTP Client                                                     */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*  xx-xx-xxxx     Yuxin Zhou               Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
UINT nx_driver_ptp_clock_callback(NX_PTP_CLIENT *client_ptr, UINT operation, NX_PTP_TIME *time_ptr, NX_PACKET *packet_ptr, VOID *callback_data)
{
    TX_INTERRUPT_SAVE_AREA
    ULONG           sec1, sec2, ns;
    ETH_TimeTypeDef time;
    uint32_t        tickstart;
    UINT            NX_PTP_Status = 0;
    ETH_TimeTypeDef time_offset;

    NX_PARAMETER_NOT_USED(callback_data);

    switch(operation)
    {
    /* Save pointer to PTP client.  */
    case NX_PTP_CLIENT_CLOCK_INIT:
        nx_driver_information.nx_driver_ptp_ptr = client_ptr;
        break;

    /* Set clock.  */
    case NX_PTP_CLIENT_CLOCK_SET:
        TX_DISABLE

        /* Get Start Tick*/
        tickstart = HAL_GetTick( );

        /* Wait to get PTP control or timeout occurred */
        while(((HAL_GetTick( ) - tickstart) &gt; HAL_PTP_TIMEOUT))
        {
            if(__HAL_ETH_GET_PTP_CONTROL(&eth_handle, ETH_MACTSCR_TSUPDT) == 0)
            {
                NX_PTP_Status = NX_WAIT_ERROR;
                break;
            }
        }

        time.Seconds     = time_ptr-&gt;second_low;
        time.NanoSeconds = time_ptr-&gt;nanosecond;
        HAL_ETH_PTP_SetTime(&eth_handle, &time);

        TX_RESTORE
        break;

    /* Extract timestamp from packet.  */
    case NX_PTP_CLIENT_CLOCK_PACKET_TS_EXTRACT:

        /* XXX second timestamp is only 32-bit */
        time_ptr-&gt;second_high = 0;

        /* Return timestamp stored at the beginning of the packet.  */
        time_ptr-&gt;nanosecond = ((ULONG *)packet_ptr-&gt;nx_packet_data_start)[0];
        time_ptr-&gt;second_low = ((LONG *)packet_ptr-&gt;nx_packet_data_start)[1];
        break;

    /* Get clock.  */
    case NX_PTP_CLIENT_CLOCK_GET:
        TX_DISABLE

        HAL_ETH_PTP_GetTime(&eth_handle, &time);
        sec1 = time.Seconds;
        ns   = time.NanoSeconds;
        HAL_ETH_PTP_GetTime(&eth_handle, &time);
        sec2                  = time.Seconds;
        time_ptr-&gt;second_high = 0;
        /* The offset standard deviation is below 50 ns */
        time_ptr-&gt;second_low = ns &lt; 500000000UL ? sec2 : sec1;
        time_ptr-&gt;nanosecond = (LONG)ns;

        TX_RESTORE
        break;

    /* Adjust clock.  */
    case NX_PTP_CLIENT_CLOCK_ADJUST:
        TX_DISABLE
        time_offset.Seconds = 0;
        if(time_ptr-&gt;nanosecond &lt; 0)
        {
            time_offset.NanoSeconds = -time_ptr-&gt;nanosecond;
            HAL_ETH_PTP_AddTimeOffset(&heth, HAL_ETH_PTP_NEGATIVE_UPDATE, &time_offset);
        }
        else
        {
            time_offset.NanoSeconds = time_ptr-&gt;nanosecond;
            HAL_ETH_PTP_AddTimeOffset(&heth, HAL_ETH_PTP_POSITIVE_UPDATE, &time_offset);
        }

        TX_RESTORE

        break;

    /* Prepare timestamp for current packet.  */
    case NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE:
        packet_ptr-&gt;nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_PTP_TIMESTAMP;
        break;

    /* Update soft timer. Not used by hardware callback function.  */
    case NX_PTP_CLIENT_CLOCK_SOFT_TIMER_UPDATE:
        break;

    default:
        NX_PTP_Status = NX_PTP_PARAM_ERROR;
    }

    return (NX_PTP_Status);
}

UINT nx_driver_set_timestamp_callback(USHORT type, TIMESTAMP_CALLBACK callback)
{
    timestamp_callback = callback;
    packet_type        = type;

    return 0;
}
#endif /* NX_DRIVER_ENABLE_PTP */

#ifdef MULTI_QUEUE_FEATURE
UINT nx_driver_shaper_config(NX_SHAPER_DRIVER_PARAMETER *parameter, UCHAR shaper_capability)
{
    UINT               status;
    NX_SHAPER_HW_QUEUE hw_queue[ETH_MTL_TX_Q_CNT];

    hw_queue[0].hw_queue_id = 0;
    hw_queue[0].priority    = 1;
    hw_queue[0].type        = NX_SHAPER_HW_QUEUE_NORMAL;

    hw_queue[1].hw_queue_id = 1;
    hw_queue[1].priority    = 2;
    hw_queue[1].type        = NX_SHAPER_HW_QUEUE_CBS;

    status                  = nx_shaper_config(parameter-&gt;nx_ip_driver_interface, PORT_RATE, shaper_capability, ETH_MTL_TX_Q_CNT, hw_queue);

    return status;
}
#endif /* MULTI_QUEUE_FEATURE */
#ifdef NX_DRIVER_ENABLE_CBS
UINT nx_driver_shaper_cbs_entry(NX_SHAPER_DRIVER_PARAMETER *parameter)
{
    UCHAR                    shaper_capability;
    UINT                     status = NX_SUCCESS;
    NX_SHAPER_CBS_PARAMETER *cbs_parameter;
    ETH_CBSConfigTypeDef     cbsconf;
    unsigned int             idle_slope;

    switch(parameter-&gt;nx_shaper_driver_command)
    {
    case NX_SHAPER_COMMAND_INIT:

        break;

    case NX_SHAPER_COMMAND_CONFIG:

        shaper_capability = NX_SHAPER_CAPABILITY_CBS_SUPPORTED;

        nx_driver_shaper_config(parameter, shaper_capability);

        break;

    case NX_SHAPER_COMMAND_PARAMETER_SET:

        cbs_parameter         = (NX_SHAPER_CBS_PARAMETER *)parameter-&gt;shaper_parameter;

        idle_slope            = cbs_parameter-&gt;idle_slope * 1000000; //bit per second

        cbsconf.QueueIdx      = cbs_parameter-&gt;hw_queue_id;
        cbsconf.SlotCount     = 0;
        cbsconf.CreditControl = 0;
        cbsconf.IdleSlope     = ((((uint64_t)idle_slope * 1024) + AVB_IDLE_SLOPE_CYCLE_FACTOR_100M - 1) / AVB_IDLE_SLOPE_CYCLE_FACTOR_100M);
        cbsconf.SendSlope     = (AVB_MAX_PORT_TRANSIT_RATE_100M - cbsconf.IdleSlope);
        cbsconf.HiCredit      = AVB_HI_CREDIT;
        cbsconf.LoCredit      = AVB_LO_CREDIT;

        /* Enable CBS feature */
        HAL_ETHEx_EnableCBS(&heth, cbsconf.QueueIdx);

        /* Set CBS Configuration */
        HAL_ETHEx_SetCBSConfig(&heth, &cbsconf);

        break;

    default:

        break;
    }

    return status;
}
#endif /* NX_DRIVER_ENABLE_CBS */

#ifdef NX_DRIVER_ENABLE_FPE
UINT nx_driver_shaper_fpe_entry(NX_SHAPER_DRIVER_PARAMETER *parameter)
{
    NX_SHAPER_FP_PARAMETER *fpe_parameter;
    UCHAR                   shaper_capability;
    ETH_FPEConfigTypeDef    fpeconf;

    switch(parameter-&gt;nx_shaper_driver_command)
    {
    case NX_SHAPER_COMMAND_INIT:

        /* Enable Tx Frame Preemption */
        HAL_ETHEx_EnableFPE(&heth);

        break;
    case NX_SHAPER_COMMAND_CONFIG:

        shaper_capability = NX_SHAPER_CAPABILITY_PREEMPTION_SUPPORTED;

        nx_driver_shaper_config(parameter, shaper_capability);

        break;
    case NX_SHAPER_COMMAND_PARAMETER_SET:

        memset(&fpeconf, 0, sizeof(ETH_FPEConfigTypeDef));

        fpe_parameter                    = (NX_SHAPER_FP_PARAMETER *)parameter-&gt;shaper_parameter;

        fpeconf.AdditionalFragmentSize   = 0;
        fpeconf.SendRespondmPacket       = DISABLE;
        fpeconf.SendVerifymPacket        = DISABLE;
        fpeconf.HoldReleaseStatus        = 0;
        fpeconf.PreemptionClassification = (((uint32_t)(((uint32_t)(~fpe_parameter-&gt;express_queue_bitmap)) &lt;&lt; ETH_MTLFPECSR_PEC_Pos)) & ETH_MTLFPECSR_PEC_Msk);
        fpeconf.ReleaseAdvance           = (fpe_parameter-&gt;ra &lt;&lt; 16);
        fpeconf.HoldAdvance              = fpe_parameter-&gt;ha;

        HAL_ETHEx_SetFPEConfig(&heth, &fpeconf);

        break;

    default:
        /* Wrong parameter, Disable FPE feature */
        HAL_ETHEx_DisableFPE(&heth);
        break;
    }

    return 0;
}
#endif /* NX_DRIVER_ENABLE_FPE */

#ifdef NX_DRIVER_ENABLE_TAS
#ifdef NX_DRIVER_ENABLE_FPE
void reconfig_fpe_gcl(NX_SHAPER_TAS_PARAMETER *parameter, UCHAR queue_bit)
{
    UINT i = 0;

    for(i = 0; i &lt; parameter-&gt;gcl_length; i++)
    {
        /*queue_bit: bit=1 means express; bit =0 means preemtable*/
        /*gata_control: 1 means open for express queue, 1 means hold(close)for express queue*/
        if(parameter-&gt;gcl[i].operation == NX_SHAPER_GATE_OPERATION_HOLD)
        {
            parameter-&gt;gcl[i].gate_control |= 1;
        }
        else if(parameter-&gt;gcl[i].operation == NX_SHAPER_GATE_OPERATION_RELEASE)
        {
            parameter-&gt;gcl[i].gate_control &= 0xfe;
        }
    }
}
#endif /* NX_DRIVER_ENABLE_FPE */
UINT nx_driver_shaper_tas_entry(NX_SHAPER_DRIVER_PARAMETER *parameter)
{
    UCHAR                         shaper_capability;
    ETH_TimeTypeDef               time;
    UINT                          status = NX_SUCCESS;
    NX_SHAPER_TAS_PARAMETER      *tas_parameter;
    UINT                          i;
    ETH_ESTConfigTypeDef          estconfig;
    ETH_GCLConfigTypeDef         *gate_ctl = &estconfig.GCLRegisters;
    ETH_TASOperationConfigTypeDef opconfig[NX_SHAPER_GCL_LENGTH_MAX];

    switch(parameter-&gt;nx_shaper_driver_command)
    {
    case NX_SHAPER_COMMAND_INIT:
        break;

    case NX_SHAPER_COMMAND_CONFIG:

        shaper_capability = NX_SHAPER_CAPABILITY_TAS_SUPPORTED;
        nx_driver_shaper_config(parameter, shaper_capability);
        break;

    case NX_SHAPER_COMMAND_PARAMETER_SET:

        memset(&estconfig, 0, sizeof(estconfig));

        tas_parameter = (NX_SHAPER_TAS_PARAMETER *)parameter-&gt;shaper_parameter;
#ifdef NX_DRIVER_ENABLE_FPE
        if(tas_parameter-&gt;fp_parameter)
        {
            reconfig_fpe_gcl(tas_parameter, ((NX_SHAPER_FP_PARAMETER *)tas_parameter-&gt;fp_parameter)-&gt;express_queue_bitmap);
        }
#endif /* NX_DRIVER_ENABLE_FPE */
        if(tas_parameter-&gt;gcl_length &gt; NX_SHAPER_GCL_LENGTH_MAX)
        {
            status = NX_NOT_SUCCESSFUL;
            return status;
        }

        gate_ctl-&gt;BaseTimeRegister      = tas_parameter-&gt;base_time;            /*! Base Time 32 bits seconds 32 bits nanoseconds */
        gate_ctl-&gt;CycleTimeRegister     = tas_parameter-&gt;cycle_time;           /*! Cycle Time 32 bits seconds 32 bits nanoseconds */
        gate_ctl-&gt;TimeExtensionRegister = tas_parameter-&gt;cycle_time_extension; /*! Time Extension 32 bits seconds 32 bits nanoseconds */
        gate_ctl-&gt;ListLengthRegister    = tas_parameter-&gt;gcl_length;           /*! Number of entries */
        gate_ctl-&gt;opList                = opconfig;

        memset(opconfig, 0, sizeof(opconfig));

        for(i = 0; i &lt; gate_ctl-&gt;ListLengthRegister; i++)
        {
            opconfig[i].Gate     = tas_parameter-&gt;gcl[i].gate_control;
            opconfig[i].Interval = tas_parameter-&gt;gcl[i].duration;
        }

        /*we will set the value added with a micro delay */
        if(gate_ctl-&gt;BaseTimeRegister == 0)
        {
            HAL_ETH_PTP_GetTime(&heth, &time);
            gate_ctl-&gt;BaseTimeRegister = (ULONG64)time.Seconds &lt;&lt; 32 | (ULONG64)time.NanoSeconds;
            /*add  1 second delay from now */
            gate_ctl-&gt;BaseTimeRegister += (ULONG64)1 &lt;&lt; 32;
        }

        estconfig.PTPTimeOffset = PTP_REF_CLK;
        estconfig.SwitchToSWOL  = 1;

        HAL_ETHEx_SetESTConfig(&heth, &estconfig);
        break;

    default:
        /* Wrong parameter, Disable TAS feature */
        HAL_ETHEx_DisableEST(&heth);

        break;
    }

    return status;
}
#endif /* NX_DRIVER_ENABLE_TAS */
/****** DRIVER SPECIFIC ****** Start of part/vendor specific internal driver functions.  */
</code></pre>&lt;/Tab&gt;&lt;Tab label="AI 可用的关键修复提示"&gt;<pre><code class="language-"># NetX Duo + STM32H7 ETH Ping Stability Porting Guide

## 1. Background and Symptoms

Target symptom during bring-up/porting:

- Ping works intermittently, then timeout/unreachable.
- Sometimes recovers after reset.
- Occasionally enters `HAL_ETH_ErrorCallback` with:
  - `HAL_ETH_ERROR_MAC` (`err=0x10`)
  - `MACErrorCode=0x0001` (TJT, Transmit Jabber Timeout)
- In severe cases, TX descriptor dump may show invalid length like `b1l=16382`.
- Runtime may print RX pool exhaustion (`pool exhausted`).

Core conclusion: this issue is usually not a single PHY problem. It is often a combined effect of:

- TX packet metadata inconsistency (`prepend/append/length/chain`)
- Weak TX segment legality checks before handing data to DMA
- RX packet pointer initialization/linking issues
- Packet pool/byte pool waterline too low

---

## 2. Root Cause Mapping (Old behavior -&gt; Correct behavior)

### 2.1 TX packet send path

Functions:

- `_nx_driver_hardware_packet_send`
- `_nx_driver_hardware_packet_send_distribute` (multi-queue path)

Old behavior problems:

- Segment length was derived directly from `append - prepend`, but invalid pointer states were not fully guarded.
- `seg_len == 0` was not handled robustly for all cases.
- Corrupted metadata could propagate to DMA descriptors and trigger MAC/TJT errors.

Correct behavior now:

- Reject invalid pointer order: `append &lt; prepend` -&gt; return driver error.
- Reject oversized segment: `seg_len &gt; 0x3FFF` -&gt; return driver error.
- For `seg_len == 0`, apply conservative repair only when all are true:
  - `nx_packet_length &gt; 0`
  - single segment (`nx_packet_next == NX_NULL`)
  - boundary valid (`prepend + length &lt;= data_end`)
- If above repair condition is met:
  - set `append = prepend + length`
- Else:
  - skip empty segment and continue
- If all segments are filtered out (`buffLen == 0`), fail fast.

Why this is correct:

- Prevents invalid TX descriptor lengths from reaching ETH DMA.
- Allows safe recovery for a known benign metadata pattern (`append == prepend` with valid `length`).
- Avoids sending malformed/empty payloads.

### 2.2 RX packet allocation callback (optional hardening)

Function:

- `HAL_ETH_RxAllocateCallback`

Original assumption:

- After `prepend += 2` alignment, `append` might not be synchronized.
- This was considered a potential source of metadata inconsistency.

Current verified conclusion:

- This synchronization is **not a required fix** for this issue closure.
- In this project, removing
  - `packet_ptr-&gt;nx_packet_append_ptr = packet_ptr-&gt;nx_packet_prepend_ptr;`
  and rerunning 100 ping tests did not reproduce instability.
- Therefore, classify it as an optional defensive hardening item, not a root-cause fix.

Why this classification is correct:

- It can improve pointer-state clarity, but it is not necessary to achieve stable ping in the validated scenario.

### 2.3 RX packet linking callback

Function:

- `HAL_ETH_RxLinkCallback`

Old behavior problem:

- If `nx_packet_next` is not explicitly reset, stale links can survive and create chain contamination.

Correct behavior now:

- Force chain tail hygiene on each linked packet:
  - `received_packet_ptr-&gt;nx_packet_next = NX_NULL;`

Why this is correct:

- Ensures every frame chain is rebuilt cleanly and does not accidentally connect to historical packets.

### 2.4 Error observability and recovery

Function:

- `HAL_ETH_ErrorCallback`

Old behavior problem:

- Error visibility was insufficient at the failure instant.
- Hard to distinguish MAC/DMA/root descriptor issues.

Correct behavior now:

- Print full error context (`gState`, `ErrorCode`, `DMAErrorCode`, `MACErrorCode`).
- Dump TX descriptor snapshot when error occurs.
- Soft restart ETH when fatal bus error or HAL error state is detected.

Why this is correct:

- Gives deterministic evidence for root-cause analysis.
- Improves resilience when transient fatal states occur.

### 2.5 Packet pool and byte pool sizing

Related files:

- `4_Driver/NetXDriver/inc/app_netxduo_device.h`
- `4_Driver/NetXDriver/src/NetxduoDrviceStdio.c`

Old behavior problem:

- Packet pool count was too low at one stage, causing frequent allocation failures.
- Pool starvation looked like random ping instability.

Correct behavior now:

- Increase packet pool capacity (project validated with 24 packets).
- Compute byte pool sizing based on configured pool usage, not too-small fixed constants.

Why this is correct:

- Removes resource starvation as an intermittent failure source.

---

## 3. Porting Checklist (Do this in order)

1. Add TX segment legality guards in both send paths:
   - single queue and multi-queue.
2. Add conservative `seg_len == 0` repair logic with strict boundary checks.
3. In `HAL_ETH_RxAllocateCallback`, `append = prepend` after alignment is optional hardening (not mandatory for this issue).
4. In `HAL_ETH_RxLinkCallback`, always set `nx_packet_next = NX_NULL` before chaining.
5. Add rich logs and descriptor snapshot in `HAL_ETH_ErrorCallback`.
6. Ensure packet pool/byte pool sizes are sufficient for your traffic profile.
7. Keep ARP broadcast reception enabled in MAC filter config.

---

## 4. Validation Procedure

### 4.1 Build validation

- Ensure both firmware targets link successfully.
- Confirm no new warnings/errors around ETH/NetX driver paths.

### 4.2 Runtime validation

- Single ping burst from PC:
  - `ping -n 1 &lt;board_ip&gt;` repeated many times
- Continuous ping window:
  - `ping &lt;board_ip&gt;` for several minutes

Expected result:

- Stable responses with no progressive degradation.
- No recurring `HAL_ETH_ErrorCallback`.
- No frequent `pool exhausted` logs.

### 4.3 If instability remains

Collect and correlate in one timestamp window:

- `NETX TX repair seg`
- `NETX TX skip empty seg`
- `NETX ETH err` and TX descriptor dump
- ping timeout moments

Then decide next path:

- If `repair` is frequent: investigate upstream packet metadata producer.
- If `skip` is frequent: investigate chain fragmentation/empty-segment generation.
- If ETH errors still appear: inspect MAC/DMA timing, descriptor ownership transitions, and cache maintenance coverage.

---

## 5. Practical Notes for Migration

- Prioritize mandatory fixes first (TX segment legality, TX empty-segment handling, RX link chain hygiene, pool sizing, error observability). Apply optional hardening items afterward.
- Do not remove descriptor/error logs too early; keep them during burn-in.
- Treat `append/prepend/length/next` as a strict invariant set. One inconsistency is enough to destabilize TX.
- Recheck cache clean/invalidate boundaries whenever packet layout changes.

---

## 6. Minimal Success Criteria

Your port can be considered stable when all are true:

- Long-run ping remains stable.
- `HAL_ETH_ErrorCallback` no longer triggers in normal operation.
- No pool exhaustion under expected traffic.
- TX descriptor lengths remain sane (no outlier values like `b1l=16382`).
</code></pre>&lt;/Tab&gt;&lt;/Tabs&gt;
          <p style='text-align: right'>
          <a href='https://www.yono233.cn/notes/52#comments'>Finished reading? Leave a comment</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">161317383669563438</guid>
  <category>note</category>
false
 </item>
  
</channel>
</rss>