probe

主要分析一下驱动的主要框架,必要地方细致分析下

文件位置:

  • drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
    从文件的最后看起:
    module_pci_driver(stmmac_pci_driver);

stmmac_pci_driver结构体如下,里面包含了id_table、probe、remove。id_table里包含了支持设备的vender id、device id,当扫描到支持的pcie设备时(把venderid 和device id 和table里的id对比)就调用probe函数

static struct pci_driver stmmac_pci_driver = { .name = STMMAC_RESOURCE_NAME,.id_table = stmmac_id_table,.probe = stmmac_pci_probe,.remove = stmmac_pci_remove,.driver         = { .pm     = &stmmac_pm_ops,},
};

以下是stmmac_pci_probe函数的一些主要调用

主要执行了以下操作

  1. 为plat_stmmacenet_data分配了空间
  2. 填充plat_stmmacenet_data
  3. 使能pci
  4. 填充plat_stmmacenet_data中一些网卡参数信息
  5. 获取pci的base address
  6. 调用stmmac_dvr_probe

接下来就进入到stmmac_dvr_probe函数,在此函数中主要完成net_device结构体的分配,和填充,填充中最重要的是设置了net_device结构体中的netdev_ops,最后使用register_netdev(ndev)注册到内核

stmmac_dvr_probe

int stmmac_dvr_probe(struct device *device,struct plat_stmmacenet_data *plat_dat,struct stmmac_resources *res)
{struct net_device *ndev = NULL;struct stmmac_priv *priv;u32 queue, maxq;int ret = 0;ndev = alloc_etherdev_mqs(sizeof(struct stmmac_priv),MTL_MAX_TX_QUEUES,MTL_MAX_RX_QUEUES);SET_NETDEV_DEV(ndev, device);/*对priv的填充*/priv = netdev_priv(ndev);priv->device = device;priv->dev = ndev;//对ethtool的支持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();/* Allocate workqueue */priv->wq = create_singlethread_workqueue("stmmac_wq");if (!priv->wq) {dev_err(priv->device, "failed to create workqueue\n");ret = -ENOMEM;goto error_wq;}INIT_WORK(&priv->service_task, stmmac_service_task);/* 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;/* Init MAC and get the capabilities */ret = stmmac_hw_init(priv);if (ret)goto error_hw_init;/* Configure real RX and TX queues */netif_set_real_num_rx_queues(ndev, priv->plat->rx_queues_to_use);netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);//设置网卡的opsndev->netdev_ops = &stmmac_netdev_ops;ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |NETIF_F_RXCSUM;ret = stmmac_tc_init(priv, priv);if (!ret) {ndev->hw_features |= NETIF_F_HW_TC;}if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;priv->tso = true;dev_info(priv->device, "TSO feature enabled\n");}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 | NETIF_F_HW_VLAN_STAG_RX;
#endif
priv->msg_enable = netif_msg_init(debug, default_msg_level);/* MTU range: 46 - hw-specific max */ndev->min_mtu = ETH_ZLEN - ETH_HLEN;if ((priv->plat->enh_desc) || (priv->synopsys_id >= DWMAC_CORE_4_00))ndev->max_mtu = JUMBO_LEN;else if (priv->plat->has_xgmac)ndev->max_mtu = XGMAC_JUMBO_LEN;elsendev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);/* Will not overwrite ndev->max_mtu if plat->maxmtu > ndev->max_mtu* as well as plat->maxmtu < ndev->min_mtu which is a invalid range.*/if ((priv->plat->maxmtu < ndev->max_mtu) &&(priv->plat->maxmtu >= ndev->min_mtu))ndev->max_mtu = priv->plat->maxmtu;else if (priv->plat->maxmtu < ndev->min_mtu)dev_warn(priv->device,"%s: warning: maxmtu having invalid value (%d)\n",__func__, priv->plat->maxmtu);if (flow_ctrl)priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on *//* Setup channels NAPI */maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use);for (queue = 0; queue < maxq; queue++) {struct stmmac_channel *ch = &priv->channel[queue];ch->priv_data = priv;ch->index = queue;if (queue < priv->plat->rx_queues_to_use)ch->has_rx = true;if (queue < priv->plat->tx_queues_to_use)ch->has_tx = true;netif_napi_add(ndev, &ch->napi, stmmac_napi_poll,NAPI_POLL_WEIGHT);}mutex_init(&priv->lock);/*如果设置了plat->clk_csr那么CSR clock在运行中将会是固定不变的,如果没有设置,那么click会根据csr实际的时钟输入动态的设置*/if (!priv->plat->clk_csr)stmmac_clk_csr_set(priv);elsepriv->clk_csr = priv->plat->clk_csr;//检查是否支持Physical Coding Sublayerstmmac_check_pcs_mode(priv);if (priv->hw->pcs != STMMAC_PCS_RGMII  &&priv->hw->pcs != STMMAC_PCS_TBI &&priv->hw->pcs != STMMAC_PCS_RTBI) {/* MDIO bus Registration */ret = stmmac_mdio_register(ndev);if (ret < 0) {dev_err(priv->device,"%s: MDIO bus (id: %d) registration failed",__func__, priv->plat->bus_id);goto error_mdio_register;}}ret = register_netdev(ndev);return ret;
error_netdev_register:if (priv->hw->pcs != STMMAC_PCS_RGMII &&priv->hw->pcs != STMMAC_PCS_TBI &&priv->hw->pcs != STMMAC_PCS_RTBI)stmmac_mdio_unregister(ndev);
error_mdio_register:for (queue = 0; queue < maxq; queue++) {struct stmmac_channel *ch = &priv->channel[queue];netif_napi_del(&ch->napi);}
error_hw_init:destroy_workqueue(priv->wq);
error_wq:free_netdev(ndev);return ret;
}
EXPORT_SYMBOL_GPL(stmmac_dvr_probe);

下面看看stmmac_hw_init(priv),这里有硬件相关的设置,特别是设置了操作硬件的ops,函数中主要调用了stmmac_hwif_init函数。

int stmmac_hwif_init(struct stmmac_priv *priv)
{bool needs_xgmac = priv->plat->has_xgmac;bool needs_gmac4 = priv->plat->has_gmac4;bool needs_gmac = priv->plat->has_gmac;const struct stmmac_hwif_entry *entry;struct mac_device_info *mac;bool needs_setup = true;int i, ret;u32 id;if (needs_gmac) {id = stmmac_get_id(priv, GMAC_VERSION);} else if (needs_gmac4 || needs_xgmac) {id = stmmac_get_id(priv, GMAC4_VERSION);} else {id = 0;}/* Save ID for later use */priv->synopsys_id = id;/* Lets assume some safe values first */priv->ptpaddr = priv->ioaddr +(needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);priv->mmcaddr = priv->ioaddr +(needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);/* Check for HW specific setup first */if (priv->plat->setup) {mac = priv->plat->setup(priv);needs_setup = false;} else {mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);}if (!mac)return -ENOMEM;/* 为网卡设置硬件操作相关的回调函数*/for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {/*在stmmac_hw数组中选取一个entry*/entry = &stmmac_hw[i];/*进行筛选*/if (needs_gmac ^ entry->gmac)continue;if (needs_gmac4 ^ entry->gmac4)continue;if (needs_xgmac ^ entry->xgmac)continue;/* Use synopsys_id var because some setups can override this */if (priv->synopsys_id < entry->min_id)continue;/* 到这里表示已经选到合适的entry,将它保存到mac结构体 */mac->desc = mac->desc ? : entry->desc;mac->dma = mac->dma ? : entry->dma;mac->mac = mac->mac ? : entry->mac;mac->ptp = mac->ptp ? : entry->hwtimestamp;mac->mode = mac->mode ? : entry->mode;mac->tc = mac->tc ? : entry->tc;/*把mac挂接到priv->hw*/priv->hw = mac;priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;/* Save quirks, if needed for posterior use */priv->hwif_quirks = entry->quirks;return 0;}dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",id, needs_gmac, needs_gmac4);return -EINVAL;
}

以下是对上述代码用到的数据结构的一个整理,以便于把握整体脉络

Linux stmac网卡代码分析----probe相关推荐

  1. Linux stmac网卡代码分析 -- open

    Open stmmac_open是在stmmac_netdev_ops结构体里的,这个ops在probe时就已经注册到了net_device结构体里,在网卡对于stmmac_open函数调用的时间我还 ...

  2. Linux内核汇编代码分析

    Linux内核汇编代码分析 1.vmlinux.lds.S文件分析 1.2 vmlinux.lds.S文件总体框架 1.3 代码段 1.4 只读数据段 1.5 init段 1.6 数据段 1.7 未初 ...

  3. Linux PCI网卡驱动分析

    http://www.uplinux.com/shizi/wenxian/4429.html Linux网卡驱动分析 学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难 ...

  4. linux 网卡驱动分析,基于linux下网卡驱动分析及实现技术研究

    摘    要 Linux技术是当前计算机技术中最大的一个热点,在我国以及全世界得到了迅猛的发展,被广泛的应用于嵌入式系统.服务器.网络系统.安全等领域.从而使得掌握在 Linux环境下的开发技术,成为 ...

  5. linux 按键驱动代码分析

    原文地址:http://blog.csdn.NET/woshidahuaidan2011/article/details/51695147 二.按键驱动 1.对按键驱动添加设备信息 linux-3.1 ...

  6. linux的watchdog代码分析,Watchdog机制以及问题分析

    目录 1. 概览 Watchdog的中文的"看门狗",有保护的意思.最早引入Watchdog是在单片机系统中,由于单片机的工作环境容易受到外界磁场的干扰,导致程序"跑飞& ...

  7. Linux操作系统的权限代码分析【转】

    转自:http://blog.csdn.net/lixuyuan/article/details/6217502 现在关于内核的书很少涉及到Linux内核的安全,内核安全大概包括了密码学实现(cryp ...

  8. Linux LKM suterusu代码分析(一)

    suterusu lkm 代码下载路径: https://github.com/mncoppola/suterusu 虽然这个LKM开发的时间是好几年前的,但是也是值得好好研究其中的hook原理,我这 ...

  9. linux网络-网卡驱动分析(基于imx6ul和ZYNQ分析)

    0.说明 内核网络驱动总结,从设备树到内核驱动加载初始化及网卡通信整个流程. 1.环境 1.1 硬件环境 NXP imx6ul 平台 1.2 参考资料 IMX6ULLRM.pdf   22 章 10/ ...

最新文章

  1. C++——String类超详细介绍
  2. java htmlparser 使用教程_Java解析HTML之HTMLParser使用与详解
  3. linux 安装 tao环境,linux环境安装hbase------不一定需要hadoop
  4. typec四线焊接图_实物图+电气图纸讲解:教你学会看配电系统图,不收藏,可惜了...
  5. pip升级python版本_GEE学习笔记 六十八:【GEE之Python版教程二】配置Python开发环境...
  6. 如何用法向量求点到平面距离_支持向量机(SVM)
  7. 问道五周年服务器维护公告,问道五周年 欢乐嘉年华
  8. (08)System Verilog 队列详解
  9. 光棍节脱单,单身狗该你上了
  10. java默认异常处理_spring boot 默认异常处理的实现
  11. Scikit-Learn 学得如何?程序员不容错过十大实用功能来袭
  12. 【VirtualBox】设置NAT端口映射-SSH登录
  13. Harmony OS — ProgressBar垂直、水平进度条
  14. 用友系统与银行接口对接实现财务数据的导入
  15. UAV 无人机检测实践分析
  16. [UEFI启动教程]移动硬盘安装U盘装机助理(双模式启动)
  17. 本地音乐上传到网易音乐云盘上
  18. Day507508509510.图灵学院之面试题② -面经
  19. 质数 AcWing 868. 筛质数 线性筛
  20. 300iq Contest 3简要题解

热门文章

  1. python 判断字符串时是否是json格式方法
  2. Leetcode47: Palindrome Linked List
  3. Ubuntu远程操作Linux服务器GUI程序
  4. inode directory
  5. HALCON示例程序forest.hdev识别森林中的树
  6. 学习笔记(12):Python网络编程并发编程-解决粘包问题-简单版本
  7. 基于python3的Opencv(一)-打开摄像头显示图像
  8. 双缓冲 android,Android 的 SurfaceView 双缓冲应用
  9. SDM For Face Alignment 流程介绍及Matlab代码实现之预处理篇
  10. 计算机函数公式一等奖怎么算,信息技术应用 用计算机画函数图象教案设计(一等奖)...