一:基本概念

应用程序最终以套接字的形式完成网络设备的接口。,对网络设备定义四个层次:网络协议接口层(数据包的发送接收,向网络层协议提供统一的数据包收发接口,舍得上层协议独立于具体的设备,(ip,arp等)),网络设备接口层(结构体net_device,用于描述具体的网络设备属性和操作的结构体,规划了具体操作硬件的 设备驱动功能层的结构),设备驱动功能层(数据包发送,中断处理(数据包接收),是驱动网络设备成员完成响应的动作的程序),网络设备与媒介(网络物理媒介,完成数据包发送和接收逇物理实体)。

1:网络协议接口层:当Ip或者ARP需要数据包时,将调用网络接口协议层的dev_queue_xmit函数发送该数据包,并指向一个sk_buff数据结构的指针,netif_rx,用来接收一个数据包,sk_buff很重要:用于linux网络子系统中的各层之间的数据传递,(include/linux/skbuff.h)中,当发送数据包时,创建sk_buff,并且递交给下层,,其中对sk_buff的操作函数有分配释放变更等操作。

2:网络设备接口层:抽象的结构体为net_device,指代一个网络设备,(include/linux/netdevice),主要参数:名称,硬件信息(共享内存的其实和结束信息,网络设备的IO基地址,中断号,多端口设备的端口,dma通道),接口信息,硬件类型,最大传输单元,设置mac地址单元。设备操作函数:打开网络设备(获取IO地址,IRQ,DMA等通道,)启动数据包的发送接收,,发送超时(采用数据包重发,恢复网络设备),得到网络设备信息(ndo_get_stats返回一个net_device_stats网络设备流量信息统计),进行特定的io控制,配置接口,设置设备的mac地址,ethtool调试工具, NAPI轮训接收方式,

3:设备驱动功能:需要被设备驱动赋予具体的数值和函数,对于具体的设备,编写具体的设备驱动功能层函数,网络数据包的接收可有中断引发,负责读取硬件上接收到的数据包并且传送给上层协议,

网络设备的注册和注销:register_netdev,alloc_netdev,

数据包的发送:,将sk_buff的有效数据放入临时缓冲区,检查限定,设置硬件寄存器,驱使网络设备发送。在中断处理中,调用netif_wake_queue唤醒被阻塞的上层,以启动继续向网络设备传输数据包,(重启设备发送队列),数据包接收:中断处理函数接收,netif_rx将sk_buff传递给上层协议。(一般采用中断接收流程)。

4:网络连接状态:netif_carrier_on函数改变设备的连接状态,通常采用定义一个定时器对链路状态进行周期性检测,读取相关的物理设备寄存器。读取相关的统计信息。

5:802.1Q VLAN 技术原理,只要涉及到二层网络技术,就会涉及到vlan,vlan是设计到以太网交换的,主要方针:根据源mac进行进行学习,根据目的mac进行转发,源mac学习:交换机接收到以太网帧头中的源mac地址来建立自己的源mac表,目的mac转发:根据接收到的以太网的帧头中的目的mac和本地mac决定如何转发。只定义了数据帧的封装格式,在以太网头中插入四字节的vlan头,

带以太网vlan tag的以太网格式:DMAC(6bytes) | SMAC(6bytes) | Ether-Type(0x8100) | VLAN(4bytes) | DATA |

vlan2.3:PRI(3bits) | CFI(1bit) | TAG(12bits) | Ether-Type(2bytes) | DATA |

PRI:帧优先级,就是通常所说的802.1p。
 CFI:规范标识位,0为规范格式,用于802.3或EthII。
 TAG:就是我们通常说的VLAN ID
 Ether-Type:标识紧随其后的数据类型。

引入VLAN概念后,数据帧只在相应的VLAN进行交换。用通俗一点的话来讲,一个交换机被虚拟出了多个逻辑交换机,每一个VLAN内的端口都是一个逻辑上的交换机。用专业一点的话来讲,一个交换机被划分了多个不同的广播域,每一个VLAN内的端口,在同一个广播域内。学习和转发都只在同一个VLAN中进行,数据帧不能跨VLAN交换或转发。一个VLAN可以包含多个端口,而一个端口也可以属于多个VLAN。一个端口在一个VLAN中有不同的属性,TAG的添加和移除原则就是根据这个属性而定的。
         TAGED:如果一个端口在一个VLAN中的属性是TAG的,那么,从该端口转发出去的数据帧就是TAGED。(当然,该数据帧是在该VLAN中交换的)
         UNTAGED:如果一个端口在一个VLAN中的属性是UNTAG的,那么,从该端口转发出去的数据帧就是UNTAGED。(当然,该数据帧是在该VLAN中交换的)

二:mac和phy的区别

一个网卡包括驱动的两个层:物理层和数据链路层,物理层定义了数据发送接收所需要的信号,数据链路层提供标准的接口,提供寻址机制,数据帧的建构,数据差错检查,向网络层提供标准的接口功能,,数据链路层芯片一般称之为mac控制器,物理层的芯片称之为phy,mac 收到ip数据包后,将之拆包,包里有目标mac,源mac,协议类型,校验码,目标mca是通过ARP协议产生,第一次发送给某个IP地址时,会发送一个ARP包(知道其ip地址),其mac的目标地址是广播地址,因为是广播包,所以局域网都会收到,如果相同会发出ARP响应,以后这个IP地址的目标mac地址就被确认。以太网的mac芯片的一端接计算机pci总线,另一端接phy芯片。phy实现csma/cd的部分功能,检测网络上是否有数据传送,有数据在传送中就等待,一旦检测到网络空闲,在等等一个随机事件后将数据发送出去,,mac通过smi总线不断获取phy的状态,例如连接速度, 双工能力等。都是定义为IEEE标准,

实际中CPU集成mac,cpu有两种寄存器用在mac上,一组用作收发,对应dma,一组用作对phy的控制。,对于phy芯片,cpu不能直接访问这组寄存器,只能通过mac上的miim寄存器组实现间接访问。同时phy芯片负责完成mii总线的数据与media接口的数据传输,有寄存器配置完成。

三:hisiv3536平台的网卡驱动程序:

https://blog.csdn.net/heliangbin87/article/details/75997189

分析文件:drivers/net/ethernet/stmmac

https://www.linuxidc.com/Linux/2012-06/62812.htm

用于分析net_dev的解释

1:通过平台注册程序得到有用的调用函数:stmmac_dvr_probe探测函数

stmmac_syscfg_init:获取寄存器配置。

stmmac_base_ioaddr =  ioremap_nocache(res->start, res->end - res->start + 1);获取mac 寄存器基地址

ndev = alloc_etherdev(sizeof(struct stmmac_priv));申请网卡设备的私有数据,网开始河北是通用数据,私有数据则为mac控制器的数据结构

ret = stmmac_mac_device_setup(ndev):选择和初始化mac 驱动。

ret = stmmac_probe(ndev);网络设备注册

ret = stmmac_mdio_register(ndev);mdio总线注册

stmmac_device_list[priv->id] = ndev;将网卡设备赋给设备驱动链表。其他的接口使用这个全局变量。

ret = stmmac_reset();复位dma,gma寄存器

stmmac_dma_operation_mode(priv);设置硬件dma 操作队列

priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);创建和初始化发送接收描述链表。

init_dma_desc_rings(ndev);dma环形配置。

if (unlikely(priv->hw->dma->init(priv->dma_ioaddr,priv->dma_channel,  priv->plat->pbl, priv->dma_tx_phy,   priv->dma_rx_phy, 0) < 0))dma软件初始化

对这两个参数的解释比较重要:priv->dirty_rx = priv->cur_rx = 0;

priv->dirty_tx = priv->cur_tx = 0;

发送接收通道初始化,已获取上传到网络协议层的数据帧index,协议层会释放skb,dirty已经填充skb到dma队列的index。

ret = request_irq(SYNOP_GMAC_IRQNUM, stmmac_interrupt, IRQF_SHARED, STMMAC_RESOURCE_NAME, pdev);请求中断

writel(~0, stmmac_base_ioaddr + TNK_REG_INTR_EN);使能中断

一些定义的可能比较重要的参数:中断号:55

priv->ioaddr = stmmac_base_ioaddr + (i * 0x4000);:控制寄存器的便宜地址0x4000

priv->dma_ioaddr = stmmac_base_ioaddr;dma和mii映射
priv->mii_ioaddr = stmmac_base_ioaddr;

2:mac控制设置

dwmac1000_setup(priv->ioaddr);选择gmac初始化

mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);分配内存,
主要是一些寄存器的配置

mac->mac = &dwmac1000_ops;mac操作,其中包括mac配置,校验配置,转存mac地址,处理外部事件中断状态,组播缓冲设置,流控制设置,电源管理,单薄mac地址。
 mac->dma = &dwmac1000_dma_ops;dma操作

选择增强型子系统数据结构体描述device->desc = &enh_desc_ops;

3:网络设备注册stmmac_probe(ndev)

网卡操作函数初始化。初始化接口features和发送timeout,初始化NAPI,获取mac,初始化操作锁,初始化网卡设备

dev->netdev_ops = &stmmac_netdev_ops;设备操作

stmmac_set_ethtool_ops(dev);ethtool工具操作,

dev->watchdog_timeo = msecs_to_jiffies(watchdog);发送超时,最终会调用stmmac_tx_timeout这个进程处理超时函数。

netif_napi_add(dev, &priv->napi, stmmac_poll, 64);初始化轮训接收包

priv->hw->mac->get_umac_addr((void __iomem *)dev->base_addr, dev->dev_addr, 0);获取mac地址

register_netdev(dev);注册网络设备。

4:stmmac_netdev_ops网络设备操作函数

static const struct net_device_ops stmmac_netdev_ops = {
    .ndo_open = stmmac_open,
    .ndo_start_xmit = stmmac_xmit,
    .ndo_stop = stmmac_release,
    .ndo_change_mtu = stmmac_change_mtu,
    .ndo_set_rx_mode = stmmac_multicast_list,
    .ndo_tx_timeout = stmmac_tx_timeout,
    .ndo_do_ioctl = stmmac_ioctl,
    .ndo_set_config = stmmac_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
    .ndo_poll_controller = stmmac_poll_controller,
#endif
    .ndo_set_mac_address = stmmac_eth_mac_addr,
};

5:打开网卡设备stmmac_open:

stmmac_init_phy(dev);初始化phy

priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);设置mac地址到硬件

priv->hw->mac->core_init(priv->ioaddr);使能mac内核

napi_enable(&priv->napi);
    napi_schedule(&priv->napi);napi使能

priv->hw->dma->start_tx(priv->dma_ioaddr, priv->dma_channel);
    priv->hw->dma->start_rx(priv->dma_ioaddr, priv->dma_channel);dma收发使能

init_timer(&priv->poll_timer);
    priv->poll_timer.function = stmmac_poll_func;
    priv->poll_timer.data = (unsigned long)dev;
    priv->poll_timer.expires = jiffies + STMMAC_POLL_TIMER;
    add_timer(&priv->poll_timer);启动相关定时器

stmmac_enable_mac(priv->ioaddr);使能mac 发送接收

netif_start_queue(dev);使能队列

6:phy连接

stmmac_init_phy:

phydev = phy_connect(dev, phy_id, &stmmac_adjust_link,priv->phy_interface);以太网连接到phy设备,根据实际的phy情况,调整连接参数,全半双工模式,速度,mii,gmii

在mdio总线PHY device找到指定的设备,设备转换为phy设备,,连接以太网device到指定的phy设备,启动phy。

7:中断处理函数:stmmac_interrupt

int_status = readl(stmmac_base_ioaddr + TNK_REG_INTR_STAT);读取中断寄存器

stmmac_mac_irq:    最终调用status = priv->hw->dma->dma_interrupt(priv->dma_ioaddr, priv->dma_channel,
                     &priv->xstats);读取dma中断状态,如果是正确的发送接收,则进行NAPI调度,

8:NAPI接口stmmac_pool,一个是数据发送完成产生中断,进入该函数回收资源

netif_napi_add(dev, &priv->napi, stmmac_poll, 64);

stmmac_tx(priv);:回收已经发送完成的资源

work_done = stmmac_rx(priv, budget);接收数据包

9:stmmac_rx(priv, budget);数据包的接收

GMAC根据寄存器的配置,获取可用的接收描述,然后从RxFIFO中读取phy接收的ETHERNET保温,如果保温复合条件,将该保温写入数据缓冲区

next_entry = (++priv->cur_rx) % rxsize;
        p_next = priv->dma_rx + next_entry;获取下一帧。

status = (priv->hw->desc->rx_status(&priv->dev->stats,
                            &priv->xstats, p));获取收到帧状态

frame_len = priv->hw->desc->get_rx_frame_len(p);获取帧长度
skb = priv->rx_skbuff[entry];

priv->rx_skbuff[entry] = NULL;获取帧数据

skb_put(skb, frame_len);设置skb 长度
            dma_unmap_single(priv->device, priv->rx_skbuff_dma[entry],   priv->dma_buf_sz, DMA_FROM_DEVICE);接触流式dma映射。

napi_gro_receive(&priv->napi, skb);将skb通过NAPI接口上传到上层网络协议处理

stmmac_rx_refill(priv);重新填充接收队列

10:.ndo_start_xmit = stmmac_xmit,发送函数

entry = priv->cur_tx % txsize;

desc = priv->dma_tx + entry;获取可发送的描述数据

priv->tx_skbuff[entry] = skb;
    priv->tx_page[entry] = NULL;将skb放到发送队列中去。

unsigned int nopaged_len = skb_headlen(skb);

desc->des2 = dma_map_single(priv->device, skb->data, nopaged_len, DMA_TO_DEVICE);
        priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,  csum_insertion);

当只有一个片段是。skb->data将发送所有的数据,当有多个数据片段,skb->data将指向第一个数据片段,其他数据放在共享数据结构frag中

然后发送剩余数据片段

priv->hw->desc->set_tx_owner(first);
    priv->cur_tx += count;降低一个数据片段交给GMAC,记录当前发送index。

priv->hw->dma->enable_dma_transmission(priv->dma_ioaddr,
                           priv->dma_channel);激活txdma

11:init_dma_desc_rings:初始化dma:(rx:256,tx:256,size:64k)

接收用于分配接收的配置结构体:priv->rx_skbuff_dma = kzalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);申请skbbuf对应的dma地址

priv->rx_skbuff = kzalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);分配对应的skbuf结构体

priv->dma_rx =(struct dma_desc *)dma_alloc_coherent(priv->device,rxsize *sizeof(struct dma_desc), &priv->dma_rx_phy,
                          GFP_KERNEL);建立一致性映射:用于分配dma源struct dma_desc,将dma源的结构体映射到连续地址位

发送用于分配发送的配置结构体:priv->tx_skbuff = kzalloc(sizeof(struct sk_buff *) * txsize,GFP_KERNEL);
    priv->tx_page = kzalloc(sizeof(struct page *) * txsize, GFP_KERNEL);
    priv->dma_tx = (struct dma_desc *)dma_alloc_coherent(priv->device,  txsize * sizeof(struct dma_desc), &priv->dma_tx_phy,
                          GFP_KERNEL);

for (i = 0; i < rxsize; i++) { //对所有的接收源进行映射,对于接收,首先将全部的dma与skb建立起来映射
       struct dma_desc *p = priv->dma_rx + i;

skb = netdev_alloc_skb_ip_align(dev, bfsize); //分配skb
        if (unlikely(skb == NULL)) {
            pr_err("%s: Rx init fails; skb is NULL\n", __func__);
            return -ENOMEM;
        }
        priv->rx_skbuff[i] = skb;

//流式映射对应的skb到dma地址上
        priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,bfsize,  DMA_FROM_DEVICE);
        p->des2 = priv->rx_skbuff_dma[i]; //将dma的物理地址赋给dma的操作结构体,该结构体用来配置返回dma的操作状态
        DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
            priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
    }

priv->cur_rx = 0;当前接收到的数据包块
priv->dirty_rx = (unsigned int)(i - rxsize); 当前已经填充的skb数据块参数。

对于发送只有在发送的过程中建立起来映射

网卡驱动(hisi3536网卡驱动,以及stmmac层)相关推荐

  1. linux pci 网卡驱动,linux网络设备驱动_pci网卡

    <linux网络设备驱动_pci网卡>由会员分享,可在线阅读,更多相关<linux网络设备驱动_pci网卡(12页珍藏版)>请在技术文库上搜索. 1. LinuxLinux 网 ...

  2. vmware esxi 查看网卡、Raid卡驱动

    vmware esxi 查看网卡.Raid卡驱动 http://blog.51cto.com/adamcrab/1942763 查看网卡 [root@localhost:~] esxcfg-nics ...

  3. fedora18 fedora17安装显卡驱动和网卡驱动

    fedora18 fedora17安装显卡驱动和网卡驱动 最近一直有种想购物的冲动,压抑了好久,最后购买了一个镁光M4固态硬盘,使用了很长时间fedora系统,恰巧看到fedora 18 alpha版 ...

  4. Hyper-V虚拟机安装及网卡无法找到,驱动无法安装解决办法

    Hyper-V虚拟机安装及网卡无法找到,驱动无法安装解决办法 最近使用了一下WIN2008中的虚拟机,在使用中遇到了一些问题,现在对安装过程及处理方法进行记录下来 1.安装Hyper-V,在我的电脑上 ...

  5. VMware ESXi 8.0 Unlocker OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版)

    发布 ESXi 8.0 集成驱动版,在个人电脑上运行企业级工作负载 请访问原文链接:VMware ESXi 8.0 Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集 ...

  6. VMware ESXi 6.7 U3 Unlocker OEM BIOS 集成 REALTEK 网卡驱动和 NVMe 驱动 (集成驱动版)

    ESXi-6.7.0-20221004001 Build 20497097 请访问原文链接:https://sysin.org/blog/vmware-esxi-6-sysin/,查看最新版.原创作品 ...

  7. VMware ESXi 8.0U1 集成网卡驱动和 NVMe 驱动 (网卡驱动集成版,整合版)

    原文地址:VMware ESXi 8.0U1 集成网卡驱动和 NVMe 驱动 (网卡驱动集成版,整合版) - DIYNAS 下载地址: VMware ESXi 8.0U1 集成网卡驱动和 NVMe 驱 ...

  8. ar8171 linux网卡驱动,ar8171 8175网卡驱动(ar8171网卡驱动下载)V1.0.1 官方最新版

    ar8171 8175网卡驱动(ar8171网卡驱动下载)是针对同网卡推出的最新驱动软件.适用于win7/8/10系统,ar8171 8175网卡驱动能够快速的进行所需的硬盘驱动,轻松的调用其内的各项 ...

  9. 水星UD6S网卡Linux驱动,水星ud6s驱动下载-水星UD6S无线网卡驱动下载 v1.0官方版--pc6下载站...

    水星UD6S无线网卡驱动是这款水星超小型650M双频无线USB网卡UD6S的官方驱动,这款无线网卡采用超小型外观设计,双频无线,最高速率633Mbps,全面支持Windows系统,支持SoftAP功能 ...

  10. arm平台linux的ethtool配置,ARM-Linux驱动--DM9000网卡驱动分析(四)

    原标题:ARM-Linux驱动--DM9000网卡驱动分析(四) 硬件平台:FL2440 (S3C2440) 内核版本:2.6.35 主机平台:Ubuntu 11.04 内核版本:2.6.39 交叉编 ...

最新文章

  1. Springboot整合Websocket遇到的坑_websocket session不支持序列化,无法存储至redis_Websocket相关问题总结(Session共享,用户多端登录等)
  2. 数据库代码编写_如何将您的职业转变为数据科学-即使您今天不编写代码。
  3. Sasha and a Very Easy Test CodeForces - 1109E (数学,线段树)
  4. JSON.stringify()实现原理
  5. pdf php 添加元数据,PDF怎么添加/清除元数据-PDF添加/清除元数据的方法 - 河东软件园...
  6. PHP中PDO方法fetch参数问题
  7. 测试开发如何设计测试用例
  8. DB9接口公头母头引脚区别
  9. cass软件yy命令_CASS快捷命令大全
  10. [个人笔记]FDTD100
  11. python自动生成ppt_用Python自动化生成倒计时图片
  12. 《哈利·波特:霍格沃茨之谜》推出二月支线任务“天界舞会”,带来新的选择、挑战与服装
  13. 5.Wide Deep Learning for Recommender Systems论文详细解读和代码实现
  14. php vox转码,php base64 编码图片,音频,视频
  15. 【面试】896- 助力春招!2021 阿里字节快手新鲜面经
  16. 「Unity3D」(9)自定义编辑器菜单扩展总结
  17. 天道酬勤,上善若水—八字真言让您立于“不败之地”
  18. Windows关闭某个端口的服务
  19. windows下安装pytorch报错InvalidArchiveError(‘Error with archive D:\\anaconda\\pkgs\\pytorch-1.2.0
  20. 网上挣钱方法有哪些?这6个方法是目前最稳的!

热门文章

  1. 01-使用脚手架搭建项目
  2. 哈工大计算机科学博士,计算机科学与技术学院博士生培养方案-哈尔滨工业大学计算机学院.DOC...
  3. Python调用大恒相机采集图片(Ubuntu16.04)
  4. 手撕前端面试题【javascript~ 总成绩排名、子字符串频次统计、继承、判断斐波那契数组等】
  5. Prouteus 定时中断 控制流水灯的实现
  6. Ordered Neurons: Integrating Tree Structures into Recurrent Neural Networks
  7. 潜行创新第四次亮相美国CES展:中国智造推动水下智能科技应用
  8. 这届年轻人为何这么穷, 90后都在啃老买房吗?
  9. Mybatis第三天动态Sql语句、XML中一对多、多对一、多对多该怎么写
  10. 腾讯乘车码公众号裂变涨粉实操案例分析!