文章目录

  • 写在前面
  • 一、源码分析

写在前面

移植瑞芯微px30 网卡RTL8363的时候,不能识别到网卡 日志打印No found PHY, 前面的硬件确认无误之后,调试代码 ,最后发现源码有一点小问题,结论为

int __mdiobus_register(struct mii_bus *bus, struct module *owner)struct phy_device *phydev;phydev = mdiobus_scan(bus, i);
-                       if (IS_ERR(phydev)) {+                       //  fix BUG
+                       if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) {err = PTR_ERR(phydev);goto error;}

按以前的源码会报错直接走goto err了,我看新的kernel版本判断条件变了,更改之后,解决,相应源码分析如下

一、源码分析

当设备中匹配到相应的gmac之后,调用rk_gmac_probe函数

static const struct of_device_id rk_gmac_dwmac_match[] = {{ .compatible = "rockchip,px30-gmac",  .data = &px30_ops   },{ .compatible = "rockchip,rk1808-gmac", .data = &rk1808_ops },{ .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },{ .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },{ .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },{ .compatible = "rockchip,rk3308-mac",  .data = &rk3308_ops },{ .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },{ .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },{ .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },{ .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },{ .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },{ }
};
MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
static int rk_gmac_probe(struct platform_device *pdev)
{struct plat_stmmacenet_data *plat_dat;struct stmmac_resources stmmac_res;const struct rk_gmac_ops *data;int ret;data = of_device_get_match_data(&pdev->dev);if (!data) {dev_err(&pdev->dev, "no of match data provided\n");return -EINVAL;}ret = stmmac_get_platform_resources(pdev, &stmmac_res);if (ret)return ret;plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);if (IS_ERR(plat_dat))return PTR_ERR(plat_dat);plat_dat->has_gmac = true;plat_dat->fix_mac_speed = rk_fix_speed;plat_dat->get_eth_addr = rk_get_eth_addr;plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data);if (IS_ERR(plat_dat->bsp_priv))return PTR_ERR(plat_dat->bsp_priv);ret = rk_gmac_clk_init(plat_dat);if (ret)return ret;ret = rk_gmac_powerup(plat_dat->bsp_priv);if (ret)return ret;//探测函数ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);if (ret)goto err_gmac_powerdown;return 0;err_gmac_powerdown:rk_gmac_powerdown(plat_dat->bsp_priv);return ret;
}

gmac驱动程序探测

int stmmac_dvr_probe(struct device *device,struct plat_stmmacenet_data *plat_dat,struct stmmac_resources *res)
{int ret = 0;struct net_device *ndev = NULL;struct stmmac_priv *priv;ndev = alloc_etherdev(sizeof(struct stmmac_priv));if (!ndev)return -ENOMEM;SET_NETDEV_DEV(ndev, device);priv = netdev_priv(ndev);priv->device = device;priv->dev = ndev;stmmac_set_ethtool_ops(ndev);priv->pause = pause;priv->plat = plat_dat;priv->ioaddr = res->addr;priv->dev->base_addr = (unsigned long)res->addr;priv->dev->irq = res->irq;priv->wol_irq = res->wol_irq;priv->lpi_irq = res->lpi_irq;if (res->mac)memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);dev_set_drvdata(device, priv->dev);/* Verify driver arguments */stmmac_verify_args();/* Override with kernel parameters if supplied XXX CRS XXX* this needs to have multiple instances*/if ((phyaddr >= 0) && (phyaddr <= 31))priv->plat->phy_addr = phyaddr;priv->stmmac_clk = devm_clk_get(priv->device, STMMAC_RESOURCE_NAME);if (IS_ERR(priv->stmmac_clk)) {dev_warn(priv->device, "%s: warning: cannot get CSR clock\n",__func__);/* If failed to obtain stmmac_clk and specific clk_csr value* is NOT passed from the platform, probe fail.*/if (!priv->plat->clk_csr) {ret = PTR_ERR(priv->stmmac_clk);goto error_clk_get;} else {priv->stmmac_clk = NULL;}}clk_prepare_enable(priv->stmmac_clk);priv->pclk = devm_clk_get(priv->device, "pclk_mac");if (IS_ERR(priv->pclk)) {if (PTR_ERR(priv->pclk) == -EPROBE_DEFER) {ret = -EPROBE_DEFER;goto error_pclk_get;}priv->pclk = NULL;}clk_prepare_enable(priv->pclk);priv->stmmac_rst = devm_reset_control_get(priv->device,STMMAC_RESOURCE_NAME);if (IS_ERR(priv->stmmac_rst)) {if (PTR_ERR(priv->stmmac_rst) == -EPROBE_DEFER) {ret = -EPROBE_DEFER;goto error_hw_init;}dev_info(priv->device, "no reset control found\n");priv->stmmac_rst = NULL;}if (priv->stmmac_rst)reset_control_deassert(priv->stmmac_rst);/* Init MAC and get the capabilities */ret = stmmac_hw_init(priv);if (ret)goto error_hw_init;ndev->netdev_ops = &stmmac_netdev_ops;ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |NETIF_F_RXCSUM;ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED/* Both mac100 and gmac support receive VLAN tag detection */ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
#endifpriv->msg_enable = netif_msg_init(debug, default_msg_level);if (flow_ctrl)priv->flow_ctrl = FLOW_AUTO;    /* RX/TX pause on *//* Rx Watchdog is available in the COREs newer than the 3.40.* In some case, for example on bugged HW this feature* has to be disable and this can be done by passing the* riwt_off field from the platform.*/if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) {priv->use_riwt = 1;pr_info(" Enable RX Mitigation via HW Watchdog Timer\n");}netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);mutex_init(&priv->lock);spin_lock_init(&priv->tx_lock);/* If a specific clk_csr value is passed from the platform* this means that the CSR Clock Range selection cannot be* changed at run-time and it is fixed. Viceversa the driver'll try to* set the MDC clock dynamically according to the csr actual* clock input.*/if (!priv->plat->clk_csr)stmmac_clk_csr_set(priv);elsepriv->clk_csr = priv->plat->clk_csr;stmmac_check_pcs_mode(priv);if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&priv->pcs != STMMAC_PCS_RTBI) {/* MDIO bus Registration *///注册mdio总线ret = stmmac_mdio_register(ndev);//rtk_switch_reg1b03();if (ret < 0) {pr_debug("%s: MDIO bus (id: %d) registration failed",__func__, priv->plat->bus_id);goto error_mdio_register;}}ret = register_netdev(ndev);if (ret) {netdev_err(priv->dev, "%s: ERROR %i registering the device\n",__func__, ret);goto error_netdev_register;}return ret;error_netdev_register:if (priv->pcs != STMMAC_PCS_RGMII &&priv->pcs != STMMAC_PCS_TBI &&priv->pcs != STMMAC_PCS_RTBI)stmmac_mdio_unregister(ndev);
error_mdio_register:netif_napi_del(&priv->napi);
error_hw_init:clk_disable_unprepare(priv->pclk);
error_pclk_get:clk_disable_unprepare(priv->stmmac_clk);
error_clk_get:free_netdev(ndev);return ret;
}
EXPORT_SYMBOL_GPL(stmmac_dvr_probe);

mdio总线注册函数

int stmmac_mdio_register(struct net_device *ndev)
{int err = 0;struct mii_bus *new_bus;int *irqlist;struct stmmac_priv *priv = netdev_priv(ndev);struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;int addr, found;if (!mdio_bus_data)return 0;rtl8761_bus=new_bus;new_bus = mdiobus_alloc();if (new_bus == NULL)return -ENOMEM;if (mdio_bus_data->irqs) {irqlist = mdio_bus_data->irqs;} else {for (addr = 0; addr < PHY_MAX_ADDR; addr++)priv->mii_irq[addr] = PHY_POLL;irqlist = priv->mii_irq;}#ifdef CONFIG_OFif (priv->device->of_node)mdio_bus_data->reset_gpio = -1;
#endifnew_bus->name = "stmmac";//mdio的读写函数new_bus->read = &stmmac_mdio_read;new_bus->write = &stmmac_mdio_write;new_bus->reset = &stmmac_mdio_reset;snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",new_bus->name, priv->plat->bus_id);new_bus->priv = ndev;new_bus->irq = irqlist;new_bus->phy_mask = mdio_bus_data->phy_mask;new_bus->parent = priv->device; //注册mdio总线err = mdiobus_register(new_bus);if (err != 0) {pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);goto bus_register_fail;}found = 0;for (addr = 0; addr < PHY_MAX_ADDR; addr++) {struct phy_device *phydev = new_bus->phy_map[addr];if (phydev) {int act = 0;char irq_num[4];char *irq_str;/** If an IRQ was provided to be assigned after* the bus probe, do it here.*/if ((mdio_bus_data->irqs == NULL) &&(mdio_bus_data->probed_phy_irq > 0)) {irqlist[addr] = mdio_bus_data->probed_phy_irq;phydev->irq = mdio_bus_data->probed_phy_irq;}/** If we're going to bind the MAC to this PHY bus,* and no PHY number was provided to the MAC,* use the one probed here.*/if (priv->plat->phy_addr == -1)priv->plat->phy_addr = addr;act = (priv->plat->phy_addr == addr);switch (phydev->irq) {case PHY_POLL:irq_str = "POLL";break;case PHY_IGNORE_INTERRUPT:irq_str = "IGNORE";break;default:sprintf(irq_num, "%d", phydev->irq);irq_str = irq_num;break;}pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",ndev->name, phydev->phy_id, addr,irq_str, dev_name(&phydev->dev),act ? " active" : "");found = 1;}}if (!found) {pr_warn("%s: No PHY found\n", ndev->name);mdiobus_unregister(new_bus);mdiobus_free(new_bus);return -ENODEV;}priv->mii = new_bus;rtl8761_bus=new_bus; return 0;bus_register_fail:mdiobus_free(new_bus);return err;
}
#define mdiobus_register(bus) __mdiobus_register(bus, THIS_MODULE)

主要是将扫描到的设备加入到mdio_bus上做管理

int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{int i, err;if (NULL == bus || NULL == bus->name ||NULL == bus->read || NULL == bus->write)return -EINVAL;BUG_ON(bus->state != MDIOBUS_ALLOCATED &&bus->state != MDIOBUS_UNREGISTERED);bus->owner = owner;bus->dev.parent = bus->parent;bus->dev.class = &mdio_bus_class;bus->dev.groups = NULL;dev_set_name(&bus->dev, "%s", bus->id);err = device_register(&bus->dev);if (err) {pr_err("mii_bus %s failed to register\n", bus->id);put_device(&bus->dev);return -EINVAL;}mutex_init(&bus->mdio_lock);if (bus->reset)bus->reset(bus);for (i = 0; i < PHY_MAX_ADDR; i++) {if ((bus->phy_mask & (1 << i)) == 0) {struct phy_device *phydev;//扫描设备,将扫描到的设备加入到phy_mapphydev = mdiobus_scan(bus, i);if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) {err = PTR_ERR(phydev);goto error;}}}bus->state = MDIOBUS_REGISTERED;pr_info("%s: probed\n", bus->name);return 0;error:while (--i >= 0) {struct phy_device *phydev = bus->phy_map[i];if (phydev) {phy_device_remove(phydev);phy_device_free(phydev);}}device_del(&bus->dev);return err;
}

通过mdio总线得到phy设备id

struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{struct phy_c45_device_ids c45_ids = {0};u32 phy_id = 0;int r;//通过mdio接口读取硬件的phy id ,判断掩码有没有设置忽略.r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);if (r)return ERR_PTR(r);/* If the phy_id is mostly Fs, there is no device there */if ((phy_id & 0x1fffffff) == 0x1fffffff)return ERR_PTR(-ENODEV);return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
}
EXPORT_SYMBOL(get_phy_device);
static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,bool is_c45, struct phy_c45_device_ids *c45_ids)
{int phy_reg;if (is_c45)return get_phy_c45_ids(bus, addr, phy_id, c45_ids);/* Grab the bits from PHYIR1, and put them in the upper half */phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);if (phy_reg < 0)return -EIO;*phy_id = (phy_reg & 0xffff) << 16;/* Grab the bits from PHYIR2, and put them in the lower half */// 通过mdio总线读取设备idphy_reg = mdiobus_read(bus, addr, MII_PHYSID2);if (phy_reg < 0)return -EIO;*phy_id |= (phy_reg & 0xffff);return 0;
}

最终还是使用mdio_bus提供的函数去读取PHY芯片寄存器地址

int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{int retval;BUG_ON(in_interrupt());mutex_lock(&bus->mdio_lock);retval = bus->read(bus, addr, regnum);mutex_unlock(&bus->mdio_lock);return retval;
}
EXPORT_SYMBOL(mdiobus_read);

1.4 px30驱动移植-网卡驱动找不到网卡解决相关推荐

  1. 【华为云技术分享】小熊派华为物联网操作系统LiteOS裸机驱动移植02-LCD驱动移植及使用

    1. LCD裸机驱动 小熊派开发板使用的LCD屏幕为1.3寸的TFT彩屏,色彩深度16bit,分辨率240*240,使用 SPI 接口与 MCU 之间通信. 如果你对裸机玩转LCD屏幕还不熟悉,请先阅 ...

  2. uboot 下spinand 驱动移植 ———1.驱动接口的添加到uboot中

    前面有篇文章谈到:https://blog.csdn.net/clam_zxf/article/details/108834541 平台驱动和单片机驱动异同,同样可以将uboot 除去它的引导加载:所 ...

  3. android nfc驱动,移植NFC驱动到android系统

    1>>>进入kernel目录,替换driver层文件: kernel/drivers/nfc/pn544.c kernel/include/linux/nfc/pn544.h 更新n ...

  4. 初识Linux Kernel 移植 之 dm9621网卡驱动移植

    初识Linux 驱动移植 -- dm921 概述 配置内核 dm9621 网卡驱动编译配置选项 问题探索 读 dm9621 MAC 地址失败 网卡反复断开重连 概述 将kernel移植到开发板并能正常 ...

  5. BH1750 传感器实战教学 —— 驱动移植篇

    前言 上一篇 BH1750 的实战教学我们说明的实际应用中传感器的硬件设计 : BH1750 传感器实战教学 -- 硬件设计篇 我们提到过在本次使用的芯片为 51 内核,I2C 通讯驱动实现与 STM ...

  6. 4G模块 EC20 R2.0 USB Serial/GobiNet/QMI WWAN 驱动移植过程

    4G模块 EC20 R2.0 USB Serial/GobiNet/QMI WWAN 驱动移植过程 一.开发环境 二.确定 EC20 R2.0 的基本信息 三.USB Serial 驱动移植 opti ...

  7. GD32F4xx 以太网芯片(enc28j60)驱动移植

    1.enc28j60 简介 ENC28J60 是带有行业标准串行外设接口(SPI)的独立以太网控制器. 主要特性: (1)SPI最高通信速率:10Mb/s.只支持SPI的模式0,0,且SPI端口要求S ...

  8. 基于I.MX6UL平台的WIFI模块AP6214A 驱动移植

    基于I.MX6UL平台的WIFI模块AP6214A 驱动移植 IoT-6ULX简要介绍 IoT-6ULX,主要面向Internet Of Things应用,该产品集成了 ARM Cortex-A7 9 ...

  9. A20 wifi驱动移植

    A20 wifi驱动移植 本驱动移植是在ak27的平台上移植8089wifi驱动,驱动名字为eagle 一.lichee部分移植 测试模式部分: dragonboard下的文件主要是针对wifi在测试 ...

  10. enc28j60 linux 驱动_linux enc28j60网卡驱动移植(硬件spi和模拟spi)

    本来想移植DM9000网卡的驱动,无奈硬件出了点问题,通过杜邦线链接开发板和DM9000网卡模块,系统上电,还没加载网卡驱动就直接崩溃了,找不到原因...刚好手上有一个enc28j60的网卡模块,于是 ...

最新文章

  1. 计算机网络技术与计算机应用技术,计算机网络技术和计算机应用技术.pdf
  2. 09_EGIT插件的安装,Eclipse中克隆(clone),commit,push,pull操作演示
  3. Jest 测试框架 beforeEach 的设计原理解析
  4. [资源分享] TensorFlow 官方中文版教程来了
  5. 【网络】c++ socket 学习笔记(一)
  6. Codeforces Testing Round #1_C. Circular RMQ
  7. js php c语言for循环,JS for循环语句
  8. java+整合handwrite_解决java.lang.UnsatisfiedLinkError: JNI_ERR returned from JNI_OnLoad
  9. 手机上什么App能连接mysql_这款APP让你的手机瞬间变身服务器,php+mysql,太硬核了!...
  10. 长尾效应--Long Tail Effect
  11. 计算机考试工作表怎么做表格步骤,计算机考试Excel表格中换行的方法
  12. 最好的在线PDF转换工具服务
  13. 互联网公司常用术语简写
  14. java统计excel数据_数据分析实战——EXCEL实现复购率计算
  15. 宝马计划明年推出智能助手,将其添加到车辆中
  16. 垂直供应链电子商务平台-未来电子商务战略趋势
  17. c语言实验一,c语言实验-实验一.doc
  18. 小白易语言post培训day02
  19. 公安大学c语言真题,2016年中国人民公安大学网络安全与执法C语言程序设计(同等学力加试)复试笔试最后押题五套卷...
  20. 从一个视频摘录的感悟

热门文章

  1. nod32 升级方法
  2. 向SqlParameter内动态添加参数
  3. JAVA编程用什么软件最好_Java编程软件有哪些,Java编程用什么软件好?
  4. win10桌面管理文件收纳_放心的电脑桌面收纳工具必备,电脑桌面win10应用商店
  5. 解决vcard乱码批量导入outlook
  6. 微信小程序 — — 实现微信公众号留言功能(附前、后端源码)
  7. Windows 驱动开发 之 WinDbg调试(一)
  8. requests+正则表达式爬取豆瓣读书top250
  9. DockerFile的编写构建镜像步骤,常用命令和案例
  10. 外链检测工具,反链友链检测工具