热度 23
2016-4-10 17:05
1369 次阅读|
2 个评论
Zynq7000 的网络控制器与 Atmel 公司的 SAMA5D3x 处理器的千兆网控制器是相同的均是 Cadence 公司的的 IP ,很奇怪两个公司各自设计了一套驱动程序。不过看着 Zynq7000 中 Linux 的设备树文件, Zynq7000 并没有使用自己的驱动程序,而是使用 Atmel 编写的驱动程序 macb.c 。 在裸机代码上, Atmel 提供的裸机代码可阅读性比 Xilinx 的好很多(这里不得不吐槽下 Xilinx 的裸机程序代码,一个驱动程序竟然拆分在多个文件中,十分不方便阅读)。 通过参考 Atmel 的裸机代码很方便的将网络驱动移植到了 SylixOS 下,需要注意 Zynq7000 的中断需要手动清除,而 Atmel 的中断读取状态时就会自动清除。当然这个方便的前提是对 SylixOS 的驱动已经有了一定的了解,对 SylixOS 下的驱动建议参考 imx283 的驱动作为模板进行设计。不过由于是千兆网,这里没有使用 SylixOS 自带的 MII 库,而是根据 Atmel 裸机代码库自行编写了网络链接检测线程,具体方法可以参考 AM335x 的驱动文件。 但在网络完成基本的通信后,出现了两个较大的问题: l 对 GEM 的 DMA 发送描述符,总会莫名其妙的出现问题; l 不能实现 1000 和 100 状态切换,固化后发现如果 uboot 不初始化连通信都实现不了。 经过长时间调试,偶然间发现通过在网络发送函数里面加入 100us 延时,即触发网络发送数据后,延时 100us 。发送函数就工作正常了,这是一个巨大的进步,原来一直以为是 DMA 描述符的使用上有问题,这个现象说明在 DMA 描述符使用上是没有问题的。这个问题最终是由一个同事帮助解决,他查看了这个问题后,有听取了我之前各种测试方法。果断做了两个改动,一个是在 DMA 描述符中增加 volatile 关键字,随后将发送后延时更改为发送前检测,检测当前 DMA 是否是否能够使用。结果系统可以正常工作(之前测试时也有类似检查,但仍然是存在问题,因此总体分析应该是 volatile 起到了作用)。 在检测当前发送描述符是否可用时需要注意一个细节,如果当前不可以,可以使用 API_TimeSleep 函数等待一段时间,但不要将函数返回,频繁调用发送函数也会让网络无法正常工作,很奇怪这个问题,但现象就是这样。 对于 1000M 和 100M 状态切换问题,包括不使用 uboot 初始化就无法通信问题,开始一直以为是 PHY 的问题,以至于将 Linux 的 PHY 读写函数内加入调试信息,全程跟踪 Linux 的 PHY 初始化过程。并没有什么收获。同样是那个同事提醒, uboot 在探测网络连接后,不仅更改了 MAC 控制器的相关标志位,还更改了一个时钟类型的寄存器。经过跟着代码了解到, Zynq7000 的以太网控制器在状态切换时需要在 SCLR 控制器中更改其参考时钟频率。否则无法正常工作。由于代码配置十分复杂,这里通过读取相应状态的数据,在链接状态改变时写入相应寄存器。之后测试网络可以正常实现链接状态改变。 这里附上查找资料时的一个博客内容(根据博客内容,对 Zynq7000 的 GEM 就不要求那么高了): 使用 iperf 对 zynq 进行单 socket tcp 传输速率测试;无网络损伤时,单向网络带宽约为 600Mbps ,双向网络带宽相加约 400Mbps ; 50ms 延时, 1ms 抖动,无丢包时,单向网络带宽约为 155Mbps ,双向网络带宽相加约 40Mbps ;和内核版本无关,经技术支持确定为 PS GEM DMA 的双向传输存在缺陷。 总结 zynq7000 的 bsp 调试过程中历时较长,从年前到年后历时近 2 个月,除去中间一段时间做 IMX6Q 处理器的驱动, Zynq7000 的驱动共花费时间近 2 个月,而网络暂用了一多半的时间,前后请了两位同事协助也没能解决,最终在第三位同事的协助下仅仅使用三天时间得以完美解决。得到的最大的教训是第三位同事做事的严谨程度远高于我们,正式对一些细节抓住不放,是问题得到了很好的理解。而自己由于对细节把握不仔细,虽然考虑到过类似问题,竟然傻乎乎的认为关闭 Cache 能起到 volatile 相同的作用。