rtems网络移植-网卡的注册和初始化-程序员宅基地

技术标签: 网络  数据结构与算法  

上篇博文介绍了在rtems下实现和网卡lan8710的通信,接下来就是实现网卡的标准化注册和初始化。

在这里本人参考了rtems m68k中gen68360的网络驱动文件和《tcp/ip详解卷二》:

首先是驱动的attach函数:

The driver attach function is responsible for configuring the driver and making the connection between the network stack and the driver.

这个驱动attach函数目的是为了配置驱动,并且连接协议栈和驱动函数,意义重大

以下是gen68360的attach函数实现:

int
rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
{
	struct scc_softc *sc;
	struct ifnet *ifp;
	int mtu;
	int unitNumber;
	char *unitName;

	/*
	 * Make sure we're really being attached
	 */
	if (!attaching) {
		printf ("SCC1 driver can not be detached.\n");
		return 0;
	}

	/*
 	 * Parse driver name
	 */
	if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
		return 0;

	/*
	 * Is driver free?
	 */
	if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
		printf ("Bad SCC unit number.\n");
		return 0;
	}
	sc = &scc_softc[unitNumber - 1];
	ifp = &sc->arpcom.ac_if;
	if (ifp->if_softc != NULL) {
		printf ("Driver already in use.\n");
		return 0;
	}

	/*
	 * Process options
	 */
	if (config->hardware_address) {
		memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
	}
	else {
		/*
		 * The first 4 bytes of the bootstrap prom
		 * contain the value loaded into the stack
		 * pointer as part of the CPU32's hardware
		 * reset exception handler.  The following
		 * 4 bytes contain the value loaded into the
		 * program counter.  The boards' Ethernet
		 * address is stored in the six bytes
		 * immediately preceding this initial
		 * program counter value.
		 *
		 * See start360/start360.s.
		 */
		const unsigned long *ExceptionVectors;
		const unsigned char *entryPoint;

		/*
		 * Sanity check -- assume entry point must be
		 * within 1 MByte of beginning of boot ROM.
		 */
		ExceptionVectors = (const unsigned long *)&_RomBase;
		entryPoint = (const unsigned char *)ExceptionVectors[1];
		if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
					>= (1 * 1024 * 1024)) {
			printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
			sc->arpcom.ac_enaddr[0] = 0x08;
			sc->arpcom.ac_enaddr[1] = 0xF3;
			sc->arpcom.ac_enaddr[2] = 0x3E;
			sc->arpcom.ac_enaddr[3] = 0xC2;
			sc->arpcom.ac_enaddr[4] = 0x7E;
			sc->arpcom.ac_enaddr[5] = 0x38;
		}
		else {
			memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, ETHER_ADDR_LEN);
		}
	}
	if (config->mtu)
		mtu = config->mtu;
	else
		mtu = ETHERMTU;
	if (config->rbuf_count)
		sc->rxBdCount = config->rbuf_count;
	else
		sc->rxBdCount = RX_BUF_COUNT;
	if (config->xbuf_count)
		sc->txBdCount = config->xbuf_count;
	else
		sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
	sc->acceptBroadcast = !config->ignore_broadcast;

	/*
	 * Set up network interface values
	 */
	ifp->if_softc = sc;
	ifp->if_unit = unitNumber;
	ifp->if_name = unitName;
	ifp->if_mtu = mtu;
	ifp->if_init = scc_init;
	ifp->if_ioctl = scc_ioctl;
	ifp->if_start = scc_start;
	ifp->if_output = ether_output;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
	if (ifp->if_snd.ifq_maxlen == 0)
		ifp->if_snd.ifq_maxlen = ifqmaxlen;

	/*
	 * Attach the interface
	 */
	if_attach (ifp);
	ether_ifattach (ifp);
	return 1;
}

该函数首先注册两个结构体

ifnet结构包含了所有接口的通用信息,可以看到函数的最后部分就是对这个结构体中的成员进行初始化,if_name是一个短字符串,用于标识接口的类型,而if_unit 标识多个相同类型的实例,比如两个以太网卡,fe0和fe1,这样if_index在内核中唯一地标识这个接口。if_mtu表示最大的接收单元大小,通常是1500字节,if_init是一个初始化函数,所指向的scc_init函数是一个初始化网卡设置的函数,这个待会再说,if_ioctl是io控制函数,也就是io命令的接口,if_start是开始函数,指向的scc_start函数是实现以太网帧的发送,if_flag表明接口的操作状态和属性,IFF_BROADCAST表示接口用于广播网,IFF_SIMPLEX表示接口不能接受它自己发送的数据。如果支持多播的设备还要设置IFF_MULTICAST。


另一个结构体是scc_softc,是自己创建的结构体,每个结构的第一个成员是sc_ac,是一个arpcom结构。


声明完结构体后首先要转换驱动的名字,调用rtems_bsdnet_parse_driver_name函数,返回值是unitnumber,通常是大于0。

接着是设置硬件地址以及sc结构的一系列信息,这里不多说。

最后设置好ifp网络接口,然后调用if_attach把这个结构插入到接口链表中。


接着看下以上这个接口函数的参数rtems_bsdnet_ifconfig结构体的配置。

/*
   ** Configure the ethernet device structure
   */
   if1_config.name =       "fe1";//RTEMS_BSP_NETWORK_DRIVER_NAME;
   if1_config.attach =     RTEMS_BSP_NETWORK_DRIVER_ATTACH;
   if1_config.ip_address=  IPAddress;
   if1_config.ip_netmask=  NetMask;
   if1_config.rbuf_count = 32;
   if1_config.xbuf_count = 32;
   if1_config.next = NULL;

在这里注册了rtems_bsdnet_ifconfig这个结构体if1_config,name选择fe1,在驱动函数中rtems_bsdnet_parse_driver_name解析这个name变成fe和1。attach这个成员非常重要,他告诉系统这个结构体的具体配置函数是RTEMS_BSP_NETWORK_DRIVER_ATTACH,也就是底层驱动实现的。

而整个驱动调用的步骤如下:首先启动系统,调用init函数,init中定义rtems_bsdnet_ifconfig这个结构体if1_config,然后初始化,在attach成员中选择底层驱动的attach的函数名,接着系统就会调用这个函数,也就是回到了最上面的驱动attach函数,对设备进行进一步的初始化。




对设备注册完后,要进行网卡的进一步的配置,比如工作方式是双工还是单工,速率是10/100/1000M,支不支持自协商等等。这个配置函数要在scc_init函数中调用

具体实现如下:

int genphy_config(void)
{

  int val;
  u32 features;

	/* For now, I'll claim that the generic driver supports
	 * all possible port types */
	features = (SUPPORTED_TP | SUPPORTED_MII
			| SUPPORTED_AUI | SUPPORTED_FIBRE |
			SUPPORTED_BNC);

	/* Do we support autonegotiation? */
	val = cpsw_mdio_read(0,0,MII_BMSR);                                              //val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
        
	if (val < 0)
		return val;

	if (val & BMSR_ANEGCAPABLE)
		features |= SUPPORTED_Autoneg;
                

	if (val & BMSR_100FULL)
		features |= SUPPORTED_100baseT_Full;
                
	if (val & BMSR_100HALF)
		features |= SUPPORTED_100baseT_Half;
                
	if (val & BMSR_10FULL)
		features |= SUPPORTED_10baseT_Full;
               
	if (val & BMSR_10HALF)
		features |= SUPPORTED_10baseT_Half;
               
	if (val & BMSR_ESTATEN) {
	val = cpsw_mdio_read(0,0,MII_ESTATUS);	                                                    //val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS);
       
		if (val < 0)
			return val;

		if (val & ESTATUS_1000_TFULL)
			features |= SUPPORTED_1000baseT_Full;
                        
		if (val & ESTATUS_1000_THALF)
			features |= SUPPORTED_1000baseT_Half;
                        
		if (val & ESTATUS_1000_XFULL)
			features |= SUPPORTED_1000baseX_Full;
                        
		if (val & ESTATUS_1000_XHALF)
			features |= SUPPORTED_1000baseX_Half;
           }            

//	phydev->supported = features;
//	phydev->advertising = features;

	genphy_config_aneg(features);

	return 0;


}

首先features指的是支持的通信方式,有MII、光纤等,这些用|表示支持一种即可

然后调用cpsw_mdio_read函数判断这个网卡是否支持自协商autonegotiation,如果不支持,则返回0并退出,如果结果包含BMSR_ANEGCAPABLE,说明支持自协商,就在features |= SUPPORTED_Autoneg;,然后是判断是否支持100M全双工,如果支持就在features加上该宏定义,以下都可以类推。

该函数到最后调用genphy_config_aneg函数将feature值写入到网卡寄存器中。



初始化后,调用genphy_update_link函数进行连接的更新:

具体实现如下:

int genphy_update_link(void)
{
	unsigned int mii_reg;

	/*
	 * Wait if the link is up, and autonegotiation is in progress
	 * (ie - we're capable and it's not done)
	 */
	mii_reg = cpsw_mdio_read(0, 0, MII_BMSR);

	/*
	 * If we already saw the link up, and it hasn't gone down, then
	 * we don't need to wait for autoneg again
	 */
	if (mii_reg & BMSR_LSTATUS)
         {      phy_link=1;
		return 0;  
         }
	if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
		int i = 0;

		printf("Waiting for PHY auto negotiation to complete");
		while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
			/*
			 * Timeout reached ?
			 */
			if (i > PHY_ANEG_TIMEOUT) {
				printf(" TIMEOUT !\n");
				phy_link=0;
				return 0;
			}

			

			if ((i++ % 500) == 0)
				printf(".");

			udelay(1000);	/* 1 ms */
			mii_reg = cpsw_mdio_read(0, 0, MII_BMSR);
		}
		printf(" done\n");
		phy_link=1;
	} else {
		/* Read the link a second time to clear the latched state */
		mii_reg = cpsw_mdio_read(0, 0, MII_BMSR);

		if (mii_reg & BMSR_LSTATUS)
			phy_link=1;
		else
			phy_link=0;
	}

	return 0;
}


首先调用cpsw_mdio_read函数读状态寄存器,然后判断如果连接是成立的,就直接返回。否则就进入循环,每隔一段时间读取寄存器的值,然后判断。如果连接成立就返回函数,否则返回0,并打印timeout。




转载于:https://www.cnblogs.com/sichenzhao/p/9320304.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33961829/article/details/93943668

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文