SylixOS适配MPC8377网卡驱动(etsec)编写总结
来源:互联网 发布:专业ps软件 编辑:程序博客网 时间:2024/06/04 01:17
经过这一个月的学习,总算勉勉强强在uboot的基础上改好了网卡驱动:
发送只用了一个包缓冲buffer,大小就是1536(MTU1500的情况下),接收区缓冲20个,每个1536字节。发送没有用中断的方式,接收采用中断的方式进行。注意缓冲描述符在这个驱动里面是采用的静态全局变量的方式:
typedef volatile struct rtxbd {txbd8_t txbd[TX_BUF_CNT];rxbd8_t rxbd[PKTBUFSRX];} RTXBD;
static RTXBD rtx __attribute__ ((aligned(8)));
首先我们需要熟读一下mpc8377的网卡相关与中断相关的datasheet,主要注意以下几个寄存器:
中断控制器ipic的SIVCR、SIPNR(H/L)、SIMSR(H/L)、SEMSR
网卡控制器etsec的IEVENT、IMASK、DMACTRL、MACCFG1、MACCFG2,还有一些PHY相关寄存器(好吧其实我没怎么看PHY的)
设置相关寄存器的宏定义、相关寄存器位的置位宏定义,注意ievent寄存器是写1清除中断,imask是写0屏蔽中断。
整个网卡的驱动初始化流程(以SylixOS的BSP为例):
1.在bsp初始化中调用的是halNetifAttch (VOID)函数:
完成的功能:
设置网卡物理地址mac、网关、默认ip、设置ipv6相关、调用上层协议(应该是lwip)里面的初始化函数(涉及内核,不需要我们实现)。
然后用协议栈的netif_add函数添加网卡,并绑定初始化函数tsecEthInit
2.tsecEthInit函数:
从这里开始的实现,部分抄袭了uboot网卡驱动,这里提一句,uboot里面是最简单的轮询的方式才进行接收,比较消耗处理器,而且速度相对而言也比较慢。所以我要改造uboot里面的网卡驱动,将接收从轮询改为中断的方式进行。
这个函数里面进行的步骤如下:
2.1分配DMA区域给实际包缓冲区域:
for (i = 0; i < PKTBUFSRX; i++) { NetRxPackets[i] = API_VmmDmaAllocAlign(PKTSIZE_ALIGN, PKTALIGN); } NetTxPacket = API_VmmDmaAllocAlign(PKTSIZE_ALIGN, PKTALIGN);然后分配网卡数据结构:
priv = (struct tsec_private *)sys_malloc(sizeof(*priv)); /* 分配网卡数据结构 */
调用tsec_initialize()函数
2.2 int tsec_initialize(int index, struct tsec_private *priv):
为结构体priv里的结构分配内存并初始化phy寄存器、mac控制寄存器、bufferdescriptor(缓冲描述符)。前者调用的是init_phy函数,后二者调用tsec_init函数
init_phy函数抄自UBOOT:
static int init_phy(struct tsec_private *priv){struct phy_info *curphy;volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);/* Assign a Physical address to the TBI */regs->tbipa = CFG_TBIPA_VALUE;regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);regs->tbipa = CFG_TBIPA_VALUE;asm("sync");/* Reset MII (due to new addresses) */priv->phyregs->miimcfg = MIIMCFG_RESET;asm("sync");priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;asm("sync");while (priv->phyregs->miimind & MIIMIND_BUSY) ;/* Get the cmd structure corresponding to the attached * PHY */curphy = get_phy_info(priv);if (curphy == NULL) {priv->phyinfo = NULL;printk(KERN_ERR"%s: No PHY found\n", priv->name);return 0;}priv->phyinfo = curphy;phy_run_commands(priv, priv->phyinfo->config);return 1;}
int tsec_init(struct tsec_private *priv)调用init_registers初始化其他通用控制器(比如重要的ievent与imask),然后调用static startup_tsec(struct tsec_private *priv)来进行缓冲描述符的初始化;
static void startup_tsec(struct tsec_private *priv){int i;volatile tsec_t *regs = priv->regs;/* Point to the buffer descriptors */regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);/* Initialize the Rx Buffer descriptors */for (i = 0; i < PKTBUFSRX; i++) {rtx.rxbd[i].status = RXBD_EMPTY | RXBD_INTERRUPT;rtx.rxbd[i].length = 0;rtx.rxbd[i].bufPtr = (UINT32)NetRxPackets[i];}rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; /* BD的最后一个status要为回卷 *//* Initialize the TX Buffer Descriptors */for (i = 0; i < TX_BUF_CNT; i++) {rtx.txbd[i].status = TXBD_INTERRUPT;rtx.txbd[i].length = 0;rtx.txbd[i].bufPtr = 0;}rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;/* Start up the PHY */if(priv->phyinfo)phy_run_commands(priv, priv->phyinfo->startup);adjust_link(priv);/* Enable Transmit and Receive */regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);/* Tell the DMA it is clear to go */regs->dmactrl |= DMACTRL_INIT_SETTINGS;regs->tstat = TSTAT_CLEAR_THALT;regs->rstat = RSTAT_CLEAR_RHALT;regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);regs->imask=IMASK_RXFEN0 | IMASK_RXB0;/////先只要接收中断打开}
这里注意一个很重要的地方,我之前一直是失败的状态就是因为这里:
rtx.rxbd[i].status = RXBD_EMPTY | RXBD_INTERRUPT; //在uboot原始驱动里面是不使用中断的,所以不会有后面那个interrupt部分,必须加上。
2.3 记录网卡数据并设置网卡参数:
pNetif->state = priv; /* 记录网卡数据结构 */#if LWIP_NETIF_HOSTNAME pNetif->hostname = HOSTNAME; /* 设置主机名 */#endif /* LWIP_NETIF_HOSTNAME */ pNetif->name[0] = IFNAME0; /* 设置网卡名 */ pNetif->name[1] = IFNAME1; NETIF_INIT_SNMP(pNetif, snmp_ifType_ethernet_csmacd, 100000000); /* 初始化 SNMP */ pNetif->output = etharp_output; /* 安装驱动发送函数,上层函数,不用实现 */ pNetif->linkoutput = __tsecEthTx; /* 发包函数,需要自己写 */ #if LWIP_IPV6 > 0 pNetif->output_ip6 = ethip6_output;#endif /* LWIP_IPV6 > 0 ,这个函数不用实现 */ lib_memcpy(pNetif->hwaddr, priv->enetaddr, ETHARP_HWADDR_LEN); /* 设置 MAC 地址 */ pNetif->hwaddr_len = ETHARP_HWADDR_LEN; /* 设置 MAC 地址长度 */ pNetif->mtu = 1500; /* 设置最大传输单元 */ pNetif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;这个套路基本上是固定的。
然后这里我为了保证网卡链路链接上,用了一个while循环,这可能不太对:
while (!priv->link) { /*优先初始化网口链路*/ phy_run_commands(priv, priv->phyinfo->startup); if (priv->link) { adjust_link(priv); pNetif->link_speed = priv->speed * 1000 * 1000; netif_set_link_up(pNetif); break; } }
2.4 注册中断(这里我自己只注册了接收中断并使能)
也就是说网卡驱动需要中断控制器驱动先写好的情况下才能完成,我之前已经写了中断控制器的驱动了,那个相对而言比较简单,就不再这里赘述,值得注意的是IPIC在MPC8377里面实际上中断屏蔽相关寄存器已经变成了SIMSR_H、SIMSR_L、SEMSR三个,注意根据中断号来对不同的屏蔽寄存器进行操作来使能禁能中断。
3. 中断响应函数receiveIsr:
完成的功能:
3.1 关中断,然后使用netJobAdd函数添加一个netTask进行收包:
if(pNetif!=NULL){ if (netJobAdd((VOIDFUNCPTR)tsec_recv, pNetif, 0, 0, 0, 0, 0) == ERROR_NONE) { /* * 关闭接收中断 */ regs->imask &= ~IMASK_RXFEN0; }else{ printk(KERN_INFO"The netJobRing is full.\n"); regs->imask &= IMASK_RXFEN0; } }else{ printk(KERN_INFO"receiveIsr:error irq\n"); }
while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { ………… rtx.rxbd[rxIdx].length = 0; /* Set the wrap bit if this is the last element in the list */ rtx.rxbd[rxIdx].status = RXBD_EMPTY | RXBD_INTERRUPT | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); rxIdx = (rxIdx + 1) % PKTBUFSRX;///检查下一个缓冲描述符}同样要记住把intterrupt位设置,因为uboot里同样这里没有设置中断,我之前忘记设置了,搞了半天都没有收包中断,所以特别蛋疼。设置完之后记得把index设置到下一个位置再次进行检查。
3.2 在ievent里写1清中断,并且设置imask再使能中断
4.用到的调试技巧:
没有MPC8377的调试器,所以调试只能通过打印的方式进行。打印过的主要信息是:
中断控制器里收到的中断控制号(注意串口的不要打印,不然会输出很多很多……)
收包函数里面打印包的信息,查看数据有没有收到。
打印ievent和imask寄存器值,这里可以使用SylixOS的系统API来安装一个控制台指令,这样就能比较方便的打一条指令就能查看寄存器的值了。
API_TShellKeywordAdd("printEn", (PCOMMAND_START_ROUTINE)__tsecCallDebug); /*安装Debug指令*/
在_tsecCallDebug里面打印自己需要的寄存器的值。
如果嫌打指令麻烦,可以创建线程,但是不推荐,因为打印速度比较快,会看不清信息。建议还是用安装Debug指令的方式查看寄存器的值。
还可以用ints指令看看中断安装是否成功(看enable返回以及最后的count值有没有增加,如下图所示)
最后贴一下互ping图,哈哈哈,搞了将近3个多星期,在没有什么嵌入式基础的情况下,能搞完中断控制器驱动和把uboot的网卡驱动改成中断形式,我觉得虽然效率非常不理想,但是总算是有所收获了吧,还是比较高兴的。
1 0
- SylixOS适配MPC8377网卡驱动(etsec)编写总结
- SylixOS网卡驱动框架
- SylixOS网卡驱动浅析
- SylixOS网卡驱动优化
- SylixOS网卡驱动实现篇
- SylixOS网卡驱动调用篇
- SylixOS 网卡驱动netdev_notify函数分析
- etsec网卡crc错误
- 编写Linux网卡设备驱动(下)
- 编写Linux网卡设备驱动(下) .
- 编写Linux网卡设备驱动(下)
- 网卡驱动编写方法
- 网卡驱动之虚拟网卡驱动编写
- 网卡驱动之虚拟网卡驱动编写
- SylixOS热插拔驱动接口(三)
- linux驱动之网卡驱动-虚拟网卡驱动编写
- SylixOS音频驱动移植
- SylixOS USB虚拟网卡框架
- RequireJS的几种define定义方式
- js 手机端触发事事件、javascript手机端/移动端触发事件
- openfire是一个基于XMPP的开源项目
- 政务部门信息孤岛求解
- 数据库性能优化
- SylixOS适配MPC8377网卡驱动(etsec)编写总结
- llvm初步涉猎
- Unity高级——状态机——有限状态机
- ubuntu查看文件使用的大小
- ElasticSearch在linux上的安装部署(留存自己看)
- C++中类的细节说明
- Git的诞生
- 莫比乌斯函数和反演定理的理解
- unity assetBundle更新 打包变化