halNetifAttch():

在bspInit中会调用__enetInit函数初始化网口驱动,

static VOID  halNetifAttch (VOID)
{__enetInit();
}#endif                                                                  /*  LW_CFG_NET_EN > 0           */

__enetInit():

传参(寄存器基地址和EMAC中断号),并初始化自旋锁。

INT  __enetInit (VOID)
{
……netdev.priv = &_G_enetInfo;LW_SPIN_INIT(&_G_enetInfo.EentSlLock);__enetRegister(&netdev);
……
}

__enetRegister():

1.注册网络接口(__enetCoreInit,__enetCoreTx,__enetCoreRecv),

2.__enetSetHwaddr函数设置mac地址(如果添加NETDEV_INIT_LOAD_PARAM宏,那么注册网络时,会去检测系统etc目录下的ifparam.ini文件,如果没有这个文件,mac地址会为00:00:00:00:00:00。如果没有这个文件时,添加__enetSetHwaddr函数设置一下MAC地址。)

3.pNetDev相关参数赋值,最后将ip,netmask,gw与网口驱动绑定。绑定成功后创建线程用于检测网口连接状态(PHY芯片BMSR寄存器中有检测网口是否连接的状态位)

static VOID  __enetRegister (struct netdev  *pNetDev)
{
……static struct netdev_funcs  net_drv = {.init      = __enetCoreInit,.transmit  = __enetCoreTx,.receive   = __enetCoreRecv,};#if SET_MAC_AUTO__enetSetHwaddr(pNetDev);                                           /* 设置mac地址                    */
#endif
……lib_strcpy(ip,      "192.168.3.202");lib_strcpy(gw,      "192.168.3.1");lib_strcpy(netmask, "255.255.255.0");if (netdev_add(pNetDev,ip,netmask,gw,IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST) == 0) {__enetThreadCreate(pNetDev);}
}

__enetLinkThread():

若检测到网口已连接,调__setEmacSpeed函数设置mac(查看网口支持哪种连接方式并将PHY设置成相应模式)

static PVOID  __enetLinkThread (PVOID  pvArg)
{
……__phyRead(pNetDev, CONFIG_DRIVER_REGEMAC_PHYADDR, MII_BMSR, &usValue);if (usValue & PHY_STATUS_LINK_ST)  {                            /*  此时为连接成功状态          */_G_uiNetLinkStatus = PHY_STATUS_LINK_ST;/** 检测连接能力并设置mac*/__setEmacSpeed(pNetDev);netdev_set_linkup(pNetDev, 1, pNetDev->speed);}
……
}

__enetCoreInit():

1.开始init,transfer,receive函数编写

2.使能时钟,MAC初始化,PHY初始化,绑定中断服务。

3.PHY初始化函数功能大致和__enetLinkThread函数功能相似,检测网口连接状态。(不同的是,若检测到未连接,PHY会复位并进行自动协商,而__enetLinkThread函数直接退出。)通常在U-boot中已经进行过PHY复位和自动协商,所以这一步实际应用中可以省略。

static INT  __enetCoreInit (struct netdev  *pNetDev)
{
……__enetBoardInit(pNetDev);__enetCoreStart(pNetDev);                                             /*  MAC初始化                  */__phyInit(pNetDev);                                                   /*  PHY初始化                   *//** 绑定中断服务函数*/API_InterVectorConnect(pEnet->iIrqNum,(PINT_SVR_ROUTINE)__enetIsr,(PVOID)pNetDev,"enet_isr");API_InterVectorEnable(pEnet->iIrqNum);return  (ERROR_NONE);
}

EMAC中每一帧数据的接收和发送都需要通过DMA接口。

如框图所示,DMA通过AHB总线连接外部存储器,它包含用于缓冲帧数据的接收和发送FIFO,DMA模块用于管理发送和接收帧缓冲区队列,这些队列可以保留多个帧。

发送时,处理器将数据放在发送缓冲区(TX FIFO),通知DMA模块发送数据至MAC模块,最终发送到网络。

接收时,MAC模块从网络接收数据并通知DMA模块取至接收缓冲区(RX FIFO),完成后通知处理器来取。

DMA模块收发数据的单元被称为BD( Buffer Description,缓存描述符),网络通信的每个包都会被分成若干个帧,而每个帧则被保存在一个或多个BD中。所有的BD组成了一张BD 表,一般来说发送方向和接收方向的BD 表是各自独立的。

__enetBuffDescInit():

MAC初始化配置相关寄存器,使能中断,初始化EMAC 缓冲描述符(给描述符分配DMA内存,包括每个描述符对应的接收/发送缓冲区也要分配DMA内存),将分配内存后的描述符地址写入队列寄存器(DMA是通过队列寄存器中的地址找到BD描述符)

注意:描述符和对应缓冲区都需要用API_VmmDmaAlloc专用接口去分配内存。使用普通方式申请的内存可能会产生cache一致性问题,由于cache存在于CPU与内存之间,所以任何外设对内存的修改并不能保证cache中也得到同样的更新,同样处理器对缓存中内容的修改也不能保证内存中的数据得到更新。这一现象会导致DMA传输时好时坏。得到的数据并不完全正确。

static VOID  __enetBuffDescInit (struct netdev  *pNetDev)
{
……/** 给描述符分配DMA内存*/pEnet->pRxRing = (REGRxBDescriptor *)API_VmmDmaAlloc(RX_BUFS_MX * sizeof(struct RxBDescriptor));pEnet->pTxRing = (REGTxBDescriptor *)API_VmmDmaAlloc(TX_BUFS_MX * sizeof(struct TxBDescriptor));/** 接收描述符初始化*/pcRxbufAddr       = (CHAR *)API_VmmDmaAllocAlign(RX_BUFS_MX * RX_BUFS_SIZE, 4);
……/** 发送描述符初始化*/pcTxbufAddr = (CHAR *)API_VmmDmaAlloc(TX_BUFS_MX * TX_BUFS_SIZE);
……/** 描述符写入队列寄存器*/writel((INT32)pEnet->pRxRing, ulBaseaddr + REG_EMAC_RBQP);writel((INT32)pEnet->pTxRing, ulBaseaddr + REG_EMAC_TBQP);
}

__enetCoreTx():

__enetCoreTx网络发送函数,将数据拷贝到指定缓冲区,填充描述符内容,开始发送,统计。

LW_SPIN_LOCK_QUICK为自旋锁加锁操作,防止在传输过程中再一次产生传输命令。结束后LW_SPIN_UNLOCK_QUICK解锁。(CPU正在填充前一个帧的BD描述符,操作还未结束,指针还停留在当前描述符未指向下一个BD,此时若再次产生一个传输命令,CPU会将前一个BD描述符中的信息覆盖,从而产生错误。)

KN_SMP_WMB()内存屏障,作用为不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,它前面的指令都执行完毕。同时该指令前的变量缓存在后面使用时需重新到内存中读取。

static INT __enetCoreTx (struct netdev  *pNetDev, struct pbuf  *pstPbuf)
{
……LW_SPIN_LOCK_QUICK(&pEnet->EentSlLock, &iRegFlag);
……/** 拷贝buf*/pbuf_copy_partial(pstPbuf, (PVOID)pEnet->pTxRing[pEnet->iCurrentTx].iTxBaddr, usLen, 0);/** 填充描述符内容*/KN_SMP_WMB();
……KN_SMP_WMB();/** 开始发送*/writel(readl(ulBaseAddr + REG_EMAC_CTL) | REG_EMAC_CTL_TSR , ulBaseAddr + REG_EMAC_CTL);netdev_statinfo_total_add(pNetDev, LINK_OUTPUT, usLen);             /*  统计更新                   */if (((UINT8 *)pstPbuf->payload)[0] & 1) {netdev_statinfo_mcasts_inc(pNetDev, LINK_OUTPUT);               /*  统计发送广播数据包数        */} else {netdev_statinfo_ucasts_inc(pNetDev, LINK_OUTPUT);               /*  统计发送单播数据包数        */}LW_SPIN_UNLOCK_QUICK(&pEnet->EentSlLock, iRegFlag);return  (ERROR_NONE);
}

__enetCoreRecv():

__enetCoreRecv网络接收函数,通过RX中BD描述符内容,CPU去指定缓冲区得到数据,向上层传递数据。

static VOID __enetCoreRecv (struct netdev  *pNetDev, INT  (*input)(struct netdev *, struct pbuf *))
{
……while(1) {KN_SMP_WMB();if (!(pEnet->pRxRing[ulRxTail].iRxBaddrAndFlag & RX_DES_FLAG_OWNER)) {return;}
……if (input(pNetDev, pBuf)) {                             /*  向上层协议传递数据          */netdev_pbuf_free(pBuf);netdev_linkinfo_drop_inc(pNetDev);netdev_statinfo_discards_inc(pNetDev, LINK_INPUT);} else {netdev_linkinfo_recv_inc(pNetDev);netdev_statinfo_total_add(pNetDev, LINK_INPUT, ulLength);
}
……KN_SMP_WMB();}

__enetIsr():

__enetIsr中断函数,在发送/接收成功后会进入中断,对描述符进行相应处理。

static irqreturn_t __enetIsr (PVOID  pvArg, UINT32  uiVector)
{
……/** 在读取时中断状态寄存器,标志位会被清除*/uiIntStatus = readl(ulBaseaddr + REG_EMAC_ISR);uiRevStatus = readl(ulBaseaddr + REG_EMAC_RSR);/** 接收成功*/if ((uiIntStatus & REG_EMAC_IxR_RCOM) || (uiRevStatus & REG_EMAC_RSR_REC)) {netdev_notify(pNetDev, LINK_INPUT, 1);                          /*  通知系统进行接收            *//** 清除REC(Frame Received)位*/writel(uiRevStatus | REG_EMAC_RSR_REC, ulBaseaddr + REG_EMAC_RSR);}/** 发送成功*/if (uiIntStatus & REG_EMAC_IxR_TCOM) {__resetTxBDescriptor(pNetDev);                                  /*  复位发送描述符              */writel(REG_EMAC_TSR_COMP, ulBaseaddr + REG_EMAC_TSR);}
……return  (LW_IRQ_HANDLED);
}

SylixOS -- 网卡驱动浅析相关推荐

  1. 网卡驱动描述符助手功能浅析

    前言 网卡驱动里,CPU和MAC控制器都需要对DMA描述符空间进行读取或者写入.DMA描述符空间又会采用到CACHE和零拷贝技术,以往都是驱动自己去申请.关联内存和刷新(flush和invalidat ...

  2. e1000网卡驱动初感受

    在网络上搜索到一片Linux-千兆网卡驱动实现机制浅析,自己大概浏览了一下,觉得写得很好,可是自己没有看明白的时候还是白扯.想起来一句话,文档时写给已经懂了的人的.这句话在我做一个小东西的时候领悟的特 ...

  3. linux网卡e1000下载,Linux E1000网卡驱动分析

    本分析主要针对e1000网卡,驱动源码为7.3.20-k2.本文的目的不是为了讲述如何编写驱动程序,主要是分析网卡驱动内部的实现机制. Linux-千兆网卡驱动实现机制浅析 作者: Minit, 出处 ...

  4. udp数据报从网卡驱动到用户空间流程总结

    附有相关介绍资料 NAPI驱动流程:     中断发生     -->确定中断原因是数据接收完毕(中断原因也可能是发送完毕,DMA完毕,甚至是中断通道上的其他设备中断)     -->通过 ...

  5. 无法安装此计算机不存在英特尔,win2008serverr2intel网卡驱动无法安装不存在英特尔PRO适配器的解决方法...

    无法安装驱动程序,此计算机上不存在英特尔(R),PRO适配器,甚至去官网下载了 intel 82579vforwindows 2008 r2 的驱动 都提示这个. 解决方法: intel官网下载for ...

  6. 备份一个万能网卡驱动

    昨天安装了一个windows2008,因为是在pc上安装,还是个老机器,安装完成后竟然发现我的网卡驱动未成功安装,我就觉得弄个驱动精灵不就ok了吗,结果安装提示不支持server版本,安装驱动人生也不 ...

  7. linux拓实n87驱动下载,拓实n87网卡驱动for xp/win7官方版

    拓实n87网卡驱动for xp/win7官方版是一个十分强大的网卡驱动管理软件,拓实n87网卡驱动for xp/win7官方版是ts N87高增益全向无线USB网卡驱动程序,拓实n87全面支持移动cm ...

  8. (超贴心)Centos7安装2.5G网卡驱动(Realtek 3000)

    文章目录 前言 准备 正题 问题1: 问题2 问题3 问题4 前言 首先跟大家聊聊我的情况吧.因为网络极其关键,要不然服务器还服务个毛,就会是一个废物. 我是在最小化安装Centos7系统的时候,设置 ...

  9. 【技术贴】虚拟机 VMware win7 win8网卡驱动下载 解决虚拟机不识别网卡没有本地连接...

    解决虚拟机VMware7.0下虚拟win7 win8找不到网卡,不能识别网卡.没有本地连接.(本篇文章只适合虚拟机win7/win8 32位环境) 废话不多说,直接入题.vmware 虚拟机 win7 ...

  10. Linux 网卡驱动相关——03

    紧接上一篇,这里简要介绍net_device 结构和网卡驱动框架. struct net_device  是一个比sk_buff 更复杂的结构,里面包含了与TCP/IP协议栈通信的接口函数,但是自从2 ...

最新文章

  1. MySQL Replace INTO的使用
  2. LeetCode 21. Merge Two Sorted Lists--合并2个有序列表--python递归,迭代解法
  3. linux中链表的使用【转】
  4. 编辑器推荐KindEditor
  5. 【机器学习】怎样将Embedding融入传统机器学习框架?
  6. OpenGL 着色器的N体仿真
  7. java中sql去除游标_java.sql.SQLException:-ORA-01000:已超过最大打开游标
  8. 事情各大厂商在战场上布局
  9. linux运维和3dmax哪个简单,牛逼运维常用的工具系列-2
  10. 如何用for循环出数据库的数据
  11. 快速实现手势解锁功能
  12. uniapp开发原生android插件,获取浏览器cookie
  13. 专题讲座3 数论+博弈论 学习心得
  14. 如何区分冲突域和广播域?
  15. 如何在html修改图片大小,HTML – 如何在CSS中动态调整图像大小?
  16. 原生js实现购物车添加删除商品、计算价格功能
  17. STM32F1案例 ST7735 TFT液晶显示屏综合库使用
  18. UTF-16、UTF-16BE、UTF-16LE编码方式的区别
  19. gridControl控件的gridView实现全选
  20. APP系统开发模式一共有哪几种?

热门文章

  1. 【Unity】UI面板:倒计时器
  2. python统计(二)假设检验
  3. md文件如何打开,如何转html(无需破解)typora下载
  4. 虫虫asp建站源码_新云CMS仿完美下载站整站源码
  5. 过滤条件为包括以后期间的数据,期末结存可能不正确,是否继续?
  6. 计算机专业英语朱龙主编,计算机专业英语(高职高专计算机系列)
  7. 计算机英语口语900句,日常英语口语
  8. ubuntu安装windows 字体
  9. 300题 第七讲 零点定理与微分不等式
  10. 牛客网-前端刷题记录(简单级)