问题描述:上电初始化前将网口插入,然后上电初始化网口能够正常使用,且能够找到PHY,ifconfig 查看能够有eth0 产生,网口正常使用且能够热插拔,但上电初始化时,不插入网口,就会报DMA engine initialization failed 错误,DMA 初始化的时候出错了。

分析:一般产生这个问题可以认为是GMAC 的工作时钟出问题了。先测量时钟引脚是否有时钟,时钟频率以及幅度等指标是否正常,主要确认以下几个方面:

1.IOMUX 出错,检查时钟脚寄存器值是否正确。

2.时钟方向以及配置与硬件不匹配。

3.检查 clock tree 和 CRU 寄存器,确认时钟频率大小和时钟是否有使能。

DMA:每一个网卡上都有一块FIFO存储器,对于NIC(Network Interface Controller),FIFO存储器是用来通过系统总线传送数据到系统存储器之前,缓存从LAN上接收到的数据。对与快速以太网还有一个直接内存存取(DMA:Directly Memory Access)控制器,用于提供对系统存储器的可靠访问。驱动为网卡分配一个环形缓冲区,在一段连续的物理内存中实现。网卡上存在一定大小的FIFO存储器,DMA缓冲区是由系统/驱动程序分配的一段连续的物理内存。

总结:网卡有一个循环缓冲区(通常叫做 DMA 环形缓冲区)建立在与处理器共享的内存中。每一个输入数据包被放置在环形缓冲区中下一个可用缓冲区,并且发出中断。然后驱动程序将网络数据包传给内核的其它部分处理,并在环形缓冲区中放置一个新的 DMA 缓冲区。DMA就是代码上的一个缓冲器buffer。DMA就是Direct Memory Access,意思是I/O设备直接存储器访问,几乎不消耗CPU的资源。在I/O设备和主存传递数据的时候,CPU可以处理其他事。

代码分析:通过查找,找到报错位置

文件路径:kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c


/*** stmmac_hw_setup - setup mac in a usable state.*  @dev : pointer to the device structure.*  Description:*  this is the main function to setup the HW in a usable state because the*  dma engine is reset, the core registers are configured (e.g. AXI,*  Checksum features, timers). The DMA is ready to start receiving and*  transmitting.*  Return value:*  0 on success and an appropriate (-)ve integer as defined in errno.h*  file on failure.*/
static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
{struct stmmac_priv *priv = netdev_priv(dev);u32 rx_cnt = priv->plat->rx_queues_to_use;u32 tx_cnt = priv->plat->tx_queues_to_use;u32 chan;int ret;/* DMA initialization and SW reset */ret = stmmac_init_dma_engine(priv); //该函数返回值为-16 DMA 软件初始化失败。if (ret < 0) {netdev_err(priv->dev, "%s: DMA engine initialization failed\n",__func__);return ret;}/* Copy the MAC addr into the HW  */stmmac_set_umac_addr(priv, priv->hw, dev->dev_addr, 0);..................

继续追代码。。。。。。

 stmmac_init_dma_engine - DMA init.* @priv: driver private structure* Description:* It inits the DMA invoking the specific MAC/GMAC callback.* Some DMA parameters can be passed from the platform;* in case of these are not passed a default is kept for the MAC or GMAC.*/
static int stmmac_init_dma_engine(struct stmmac_priv *priv)
{u32 rx_channels_count = priv->plat->rx_queues_to_use;u32 tx_channels_count = priv->plat->tx_queues_to_use;u32 dma_csr_ch = max(rx_channels_count, tx_channels_count);struct stmmac_rx_queue *rx_q;struct stmmac_tx_queue *tx_q;u32 chan = 0;int atds = 0;int ret = 0;if (!priv->plat->dma_cfg || !priv->plat->dma_cfg->pbl) {dev_err(priv->device, "Invalid DMA configuration\n");return -EINVAL;}if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE))atds = 1;ret = stmmac_reset(priv, priv->ioaddr);//该函数返回-16if (ret) {dev_err(priv->device, "Failed to reset the dma\n");return ret;}后面初始化DMA 相关的操作都没有执行了/* DMA Configuration */stmmac_dma_init(priv, priv->ioaddr, priv->plat->dma_cfg, atds);

stmmac_reset 该函数返回错误的原因主要是由于PHY初始化失败造成的。

好像没有办法继续跟踪代码,我们先来看一下相关的配置。

&gmac1 {phy-mode = "rgmii"; //使用的接口,一般千兆网使用的是该接口,我的项目是一个千兆网口clock_in_out = "input"; //这里是使用的input,意思是使用PHY所产生的时钟供給Gmac.而不是使用的RK的内部时钟。snps,reset-gpio = <&gpio0 RK_PC2 GPIO_ACTIVE_LOW>; //复位引脚snps,reset-active-low;//低电平有效/* Reset time is 20ms, 100ms for rtl8211f */snps,reset-delays-us = <0 20000 100000>;//复位时序assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>, <&cru CLK_MAC1_OUT>;assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&gmac1_clkin>;assigned-clock-rates = <0>, <125000000>, <25000000>;pinctrl-names = "default";pinctrl-0 = <&gmac1m1_miim&gmac1m1_tx_bus2&gmac1m1_rx_bus2&gmac1m1_rgmii_clk&gmac1m1_rgmii_bus/*&eth1m1_pins*/&gmac1m1_clkinout>;tx_delay = <0x28>;rx_delay = <0x11>;phy-handle = <&rgmii_phy1>;status = "okay";
};
&mdio1 {status = "okay";rgmii_phy1: phy@4 {compatible = "ethernet-phy-ieee802.3-c22";reg = <0x4>;clocks = <&cru CLK_MAC1_OUT>;};
};

配置解读:RGMII 上分别有 TX_CLK 和 RX_CLK 两个时钟,这两个时钟分别由 MAC 和 PHY 产生,这两个时钟频率的大小和网速的大小相关,千兆网速的时候,时钟频率为 125MHz,百兆为 25MHz, 十兆为 2.5MHz。TX_CLK 可以由 RK 内部的 PLL 分频产生,也可以由外部的时钟输入经过分频后产生。目前我们使用的是由外部输入的时钟,这样的时钟相对于内部 PLL 产生的时钟更加独立,不受 RK 内部分频策略的影响,因此更加稳定。而对于 PHY 来说,本身就需要一个25M 的晶振作为时钟源,因此 RX_CLK 正是由这个时钟源倍频或分频得到的。绝大多数 PHY 还有这样的一个输出管脚,可以输出一个时钟给 MAC,也就是上面描述的相对于 MAC 来说的外部时钟,这个时钟大小为 125MHz,作为 MAC 端 TX_CLK 的时钟源。时钟方向正是指的是用内部时钟 output 或是外部时钟 input(这个见代码中的注释)。

分析:进一步的来分析问题,由于我们上电初始化的时候插入网线可以初始化成功,且可以正常使用且能够进行热插拔,没有报错,网口的速率也能够达到千兆网的要求,所以我们的配置,以及驱动代码是没有问题的。当我们没有查入网线进行上电时,网口会初始化失败,报上面的错误,而我们上面分析到了DMA是什么,这里不在讲,所以可以确定的是时钟出现了问题,而我经过查阅资料,PHY内部与网口之间,会有一个自动协商的机制,就是当我们插入网线与不插入网线的硬件状态是不同的,目前我怀疑的是供給GMAC的时钟在插入网线的后,由于这种机制导致了其时候达到了125M,达到了GMAC的初始化要求,而不插入网线时其,PHY默认供给GMAC的时钟只有25M,其导致不能够初始化成功。使用 100M PHY 时,其频率是 50M,使用 1000M PHY 时,其频率是 125M。

接下来我们来继续分析PHY的数据手册,我这里用的是AR8035。

我又叫硬件工程师量了一下时钟速率:

这是不接网线时上电初始化的的RX_CLK的时钟速率。只有2.5M很明显是不符合要求的。

这是初始化上电时插入网线时的一个时钟速率为125M。(该状态下网口可以初始化成功,并正常使用)

由于可以看到PHY的一个输出时钟是可以控制的,默认的它是一个25M的一个时钟供给GMAC。而GMAC需要的是一个125M的时钟,所以会导致GMAC初始化失败,也就验证了我们之前的分析想法。

原因找到了,接下来就是实践操作的时候了。show time ~~~~~~  我们现在做的就是需要在不t插入网线的时候,让PHY输出给GMAC为125M,(或许大于25M就行,我这里没有去试)

 // To enable AR8035 ouput a 125MHz clk from CLK_25M phy_write(phydev, 0xd, 0x7);phy_write(phydev, 0xe, 0x8016);phy_write(phydev, 0xd, 0x4007);val = phy_read(phydev, 0xe);val &= 0xffe3;val |= 0x18;phy_write(phydev, 0xe, val);

添加:

有如下报错:

[   26.033159] rk_gmac-dwmac fe010000.ethernet: Failed to reset the dma
[   26.033174] rk_gmac-dwmac fe010000.ethernet eth0: stmmac_hw_setup: DMA engine initialization failed
[   26.033197] rk_gmac-dwmac fe010000.ethernet eth0: stmmac_open: Hw setup failed

分析:Failed to reset the dma

目前是 DMA HW reset 失败了。!!

而其DMA init 初始化成功了。先看一下代码:

   /*ret = stmmac_reset(priv, priv->ioaddr);if (ret) {dev_err(priv->device, "Failed to reset the dma\n");return ret;}经过好一阵的查找,发现该函数其实是通过结构体函数指针赋值的,其赋值的函数如下:
const struct stmmac_dma_ops dwmac4_dma_ops = {.reset = dwmac4_dma_reset,.init = dwmac4_dma_init,.init_chan = dwmac4_dma_init_channel,.init_rx_chan = dwmac4_dma_init_rx_chan,.init_tx_chan = dwmac4_dma_init_tx_chan,...................int dwmac4_dma_reset(void __iomem *ioaddr)
{u32 value = readl(ioaddr + DMA_BUS_MODE);int limit;/* DMA SW reset */value |= DMA_BUS_MODE_SFT_RESET;writel(value, ioaddr + DMA_BUS_MODE);limit = 10;while (limit--) {if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))break;mdelay(10);}if (limit < 0)return -EBUSY; //DMA 复位失败,最终返回-16 表示设备忙!!return 0;
}

分析:它这段代码其实就是写读,ioaddr 相关的值,我目前也不知道它相关寄存器的手册,不知道它相关寄存器位表示什么,由于我的项目是DMA 复位失败了 ,但是DMA 是初始化成功了的,

stmmac_dma_init(priv, priv->ioaddr, priv->plat->dma_cfg, atds); //该函数执行成功。

具体DMA 复位的操作是什么作用。

我这里的处理方法是直接将DMA rest 注释掉了,不让它DMA复位。

/*Removing DMA reset does not affect the use of functions *//*ret = stmmac_reset(priv, priv->ioaddr);if (ret) {dev_err(priv->device, "Failed to reset the dma\n");return ret;}*/

然后再测试网口功能,上电插入初始化等,都可以正常使用,以及热插拔,以及网速的相关测试都正常。目前我能想到的办法是这个,由于无法查看相关寄存器的值代表什么意思,所以无法追查,如您有更好的方法,欢迎留言分享。

总结:遇见问题不要慌,不要做无头的苍蝇,首先根据现象来推算我们的哪里错了,哪里没有问题,然后去推测问题的所在,再去仔细的查看,通过硬件状态来分析。

rockchip rk3566 android11 网口log报错: DMA engine initialization failed相关推荐

  1. RK3399 GMAC驱动失败,打印如下log,DMA engine initialization failed 原因

    公众号 欢迎扫码关注本人微信公众号:公众号上分享更多嵌入式知识和资料,分享个人学习嵌入式的心得体会.欢迎大家一起来玩呀. RK3399 GMAC驱动失败,打印如下log,DMA engine init ...

  2. hive 任务查询报错 Reduce operator initialization failed

    问题 : hive on spark任务报错Reduce operator initialization failed 语句 : 报错 : 解决 : 默认开启了hive.auto.convert.jo ...

  3. 安装MHA中清理Relay log报错

    安装MHA中清理Relay log报错 [root@MHA3 ~]#  /usr/bin/purge_relay_logs --user=root --password=123456 -disable ...

  4. Communication error with Jack server , try ‘jack-diagnose‘ or see Jack server log 报错解决办法

    创作不易,请尊重原创,转载注明出处: https://blog.csdn.net/An_Times/article/details/121334749 Communication error with ...

  5. 普元 AppServer 7.0 执行startServer.cmd启动,命令行一直启动中,server.log报错:com.primeton.appserver.l7e.exception.Impr

    [问题] AppServer 7.0 JDK1.8.0_251   执行startServer.cmd启动,命令行一直启动中,server.log报错: [2020-06-11T10:21:33.53 ...

  6. ESlint中console.log报错问题

    ESlint中console.log报错问题 由于ESlint规范化,导致console.log的使用也会报错,下面是设置允许console.log控制台输出 描述:打开 package.json 文 ...

  7. 报错:Gradle build failed.See the Console for details.(已解决)

    CSDN话题挑战赛第2期 参赛话题:面试宝典 报错:Gradle build failed.See the Console for details.(已解决) 1.出现问题: 2.报错信息: 3.总结 ...

  8. MongoDB启动报错 ERROR: child process failed, exited with 1

    1.启动报错 ERROR: child process failed, exited with 1 2.报错的原因 使用kill关闭进程导致的错误 3.解决 3.1.进入data中的目录,删除lock ...

  9. 单点登录(十)-----遇到问题-----cas启用mongodb验证方式报错com.mongodb.CommandFailureException---Authentication failed

    cas启用mongodb验证方式报错com.mongodb.CommandFailureException---Authentication failed. 完整报错信息: 二月 08, 2017 5 ...

最新文章

  1. 深度无盘服务器网卡,无盘服务器网卡
  2. Nagios监控部署(四)--被监控主机配置
  3. 如何高性能的给UIImageView加个圆角
  4. leeds计算机科学理学硕士,利兹大学数学及计算机科学理学硕士研究生申请要求及申请材料要求清单...
  5. 聊聊rocketmq的BrokerHousekeepingService
  6. TensorFlow中RNN实现的正确打开方式
  7. 对症下药教你清除电脑中的木马
  8. 从零搭建nginx服务器
  9. QLive EULA
  10. 超好看的动态流量卡官网源码多功能集成式源码
  11. S5PV210 软件实现电阻屏两点触摸
  12. 第13章 Swing程序组件----常用布局管理器
  13. 计算机或可编程控制器,浅谈可编程控制器的应用
  14. JIRA上根据前置任务自动计算到期日之automation实现实例
  15. html5页面嵌入视频播放,使用HTML5在网页中嵌入音频和视频播放的基本方法
  16. ssh远程连接发送命令行
  17. Python 频数直方图
  18. JavaScript飞机大战知识点
  19. Python爬虫 BeautifulSoup(bs4)-- bs4介绍、安装bs4、bs4基础语法
  20. getElementsByClassName用法

热门文章

  1. JavaScript中的ReferenceError和TypeError两种错误的区别
  2. XXE漏洞介绍及利用
  3. 英文手写墨水艺术字体
  4. vmstat命令详解!看了很多vmstat的详解,自己总结的
  5. Java list.toArray()和list.toArray(T[] a)
  6. 100个Python实战练手项目(附源码+素材),学习必备
  7. commit your changes or stash them before you can merge 解决方法
  8. 上位机软件开发流程是怎样的?上位机开发软件分享
  9. 8年老码农现身说法:大龄程序员找工作,为什么这么难?
  10. SLAM基础- 题目:基础矩阵F、本质矩阵E和单应矩阵H的自由度和秩