基于网络设备框架的驱动分析
2016-10-28 17:34
435 查看
基于网络设备框架的驱动分析
所谓网络设备,其实是一个概念而非实体,网卡仅仅是网络设备中的一部分。1.网络设备的特性
网络设备是比较特殊的,它不以文件形式存在,不符合Linux中“一切皆是文件”的哲学。应用程序若想联网,不是通过/dev下的文件,而是直接通过系统API(比如socket)调用网络驱动来联网为什么呢?原因是应用层对于网络读写方式其实是很固定的(相比于字符设备各种千奇百怪的功能),所以没必要以灵活的文件形式提供接口,API形式其实就够了
2.网络设备驱动的结构
由此不难看出,和块设备驱动相同,都是内核的顶层负责通用的上层逻辑,然后硬件差异由具体硬件驱动负责。驱动工程师只要完成极少的硬件相关的部分
3.网卡简介
下面介绍硬件相关的部分,以常见的DM9000为例。DM9000其实是通过s5pv210的SROM接口来直接挂载在总线上的,所谓的SROM接口其实是一种对外部开放总线的方式,通过这个接口,网卡可以直接通过总线访问,对于程序员来说就仿佛在访问SOC内部的SFR,网卡芯片与SOC直接的通信过程就可以不用关心了。简而言之,这个网卡芯片就像集成在SOC内部一样。s5pv210的内存映射表有关SROM的部分:
接下来看看我们板子上网卡的具体接法:
通过上图,我们还能得出很多重要信息:由接口data0-data15可知,SROM接口使用了16位宽度。由接口CSn1可知,网卡接了SROM的bank1的片选脚,所以网卡处在0x88000000开头的内存地址
dm9000的地址接口和数据接口是复用的,CMD接在了ADDR2(一根地址总线),当CMD为1时data0-data15传输的是数据,而当CMD为0时传输的是地址。不难得出,如果要写dm9000的内部寄存器,我们是往0x88000000先写地址,再往0x88000000+0b100(即4)写数据。(但有时要加上0x300的偏移量,详见后文)
4.网卡配置实例
网卡的配置分为两步:早期soc内部的SROM初始化,和网卡驱动负责的硬件本身的初始化早期的初始化
这部分与驱动无关,是初始化soc内部的SROM接口配置,所以每一种soc的初始化过程和SROM寄存器是不一样的。不过我们还是可以找出一些共性进入mach-smdkc110.c的 smdkc110_machine_init函数,检查DM9000相关的部分,发现调用了smdkc110_dm9000_set函数来初始化DM9000,其定义:
static void __init smdkc110_dm9000_set(void) { unsigned int tmp; tmp = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0)); __raw_writel(tmp, S5P_SROM_BC1); tmp = __raw_readl(S5P_SROM_BW); tmp &= ~(0xf << 4); tmp |= (1<<7) | (1<<6) | (1<<5) | (1<<4); // dm9000 16bit __raw_writel(tmp, S5P_SROM_BW); tmp = __raw_readl(S5PV210_MP01CON); tmp &= ~(0xf << 4); tmp |= (2 << 4); __raw_writel(tmp, S5PV210_MP01CON); }
一眼看出,这段代码用“先读再改后写”的方法在配SROM相关的寄存器。通过查芯片手册,我们很容易得知这段代码做了什么
SROM_BW寄存器主要负责各个bank的数据总线的宽度设置,不同的位分别设置不同的bank,由于定义了宏DM9000_16BIT_DATA,故此寄存器配置为16位模式,并且配置的是bank5,byteenable位设置成0(不使用UB/LB),waitenable位设成0(禁止等待),addrmode设为0(半字对齐)。我们修改为bank1,此外,原厂的很多设置都是有问题的,必须修改为byteenable位设置成1(使用UB/LB),waitenable位设成1(使能等待),addrmode设为1(字节对齐),至于这些参数到底怎么选择,其实都是一些约定俗成的套路,特别是dm9000作为一款历史悠久的老芯片,很多设置的方法都已经固化了,通过网络可以很轻松查到
最后原厂配置了MP01CON_REG这个寄存器,这个寄存器其实就是配置了引脚MP01,原厂将其设为复用功能,即SROM接口中的bank1片选引脚
网卡本身的配置
网卡本身的驱动是基于platform总线的,所以有关网卡的可配置项都在platform_device中不难找到dm9000的platform_device:
struct platform_device s5p_device_dm9000 = { .name = "dm9000", .id = 0, .num_resources = ARRAY_SIZE(s5p_dm9000_resources), .resource = s5p_dm9000_resources, .dev = { .platform_data = &s5p_dm9000_platdata, } };
观察后发现,主要的配置项还是在s5p_dm9000_resources和s5p_dm9000_platdata中
static struct resource s5p_dm9000_resources[] = { [0] = { .start = S5P_PA_DM9000, .end = S5P_PA_DM9000 + 3, .flags = IORESOURCE_MEM, }, [1] = { #if defined(CONFIG_DM9000_16BIT) .start = S5P_PA_DM9000 + 4, .end = S5P_PA_DM9000 + 7, .flags = IORESOURCE_MEM, #else .start = S5P_PA_DM9000 + 1, .end = S5P_PA_DM9000 + 1, .flags = IORESOURCE_MEM, #endif }, [2] = { .start = /*IRQ_EINT10*/IRQ_EINT10, .end = /*IRQ_EINT10*/IRQ_EINT10, .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, } };
S5P_PA_DM9000代表的正是dm9000的基地址,0x88000000。由s5pv210的内存映射表可知bank1就在该地址
但此处有坑,很玄学,居然有可能不工作,需要改成0x88000300才行,至于原因的话网上众说纷纭,一种比较合理的说法是:DM9000有不同的版本,其中有的内部自带0x300的偏移量…故只用bank的基地址是不行的,需要加上0x300。但其实我个人不认同这一观点,因为加上去的0x300地址是soc内存空间的地址,而不是dm9000内部寄存器的地址,更何况只有一根ADDR2接在dm9000上,照理说这0x300加不加根本没区别,所以我觉得可能是s5pv210内部的SROM相关的bug,等以后验证一下
.end元素,个人猜测可能与发送数据时的地址有关,等到以后有空测试一下就知道了
IRQ_EINT10代表了当有数据从dm9000传输至soc时,使用哪个外部中断,通过原理图不难得知,我们接了一个EINT10引脚
static struct dm9000_plat_data s5p_dm9000_platdata = { #if defined(CONFIG_DM9000_16BIT) .flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM, #else .flags = DM9000_PLATF_8BITONLY | DM9000_PLATF_NO_EEPROM, #endif .dev_addr = {0x00,0x09,0xc0,0xff,0xec,0x48}, //.dev_addr = {0x00,0x09,0xc0,0xff,0x11,0x33}, };
s5p_dm9000_platdata这个结构体内主要是一些地址比较重要,还不清楚是干什么的
相关文章推荐
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(二)
- Linux USB设备驱动框架分析
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(五)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析
- 网络驱动程序 各个函数详解及图解 DM9000A网卡驱动框架源码分析
- Linux设备驱动工程师之路——网络设备驱动基本原理和框架
- 网络设备驱动 和 DM9000 驱动程序分析
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(六)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(二)
- 网络设备驱动基本原理和框架
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(四)
- [Linux驱动开发] 网络设备之DM9000驱动架构分析
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(六)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(七)
- 基于事件驱动的领域模型实现框架 - 分析框架如何解决各种典型业务逻辑场景
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(七)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(三)
- Linux设备驱动工程师之路——网络设备驱动基本原理和框架
- ramdisk驱动程序分析-2.6内核--块设备驱动框架(1)
- Linux I2C设备驱动分析 基于2440 2.6.32内核