您的位置:首页 > 理论基础 > 计算机网络

基于网络设备框架的驱动分析

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这个结构体内主要是一些地址比较重要,还不清楚是干什么的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络