分析如下,所有分析这个网卡架构的都是基于 ISA总线接口的情况下的分析,不管是书还是blog。
ISA情况下,内核启动的时候,会调用结构体中的成员(函数指针),static struct devprobe2 [] = {
#ifdef{, 0},#endif进而调用probe函数, 完成网卡的probe。struct net_device * (int )
但是开发板上压根就不是用的这个路子,开发板网卡控制器本身就在cpu上,我们的网卡直接连到了CPU引脚。
其实想想,我们本质上就是想在内核启动的时候,调用网卡的probe函数,至于什么方式,放在总线的对应数组还是别的什么方式,都是可以的。
下面从网卡移植入口,看看我们移植的时候是如何做,使得内核启动的时候,去probe了我们的网卡。
综合比较了下网上关于移植的blog,又加上韦东山的书。发现上面的想法是错误的。
虽说我的开发板上是网卡和CPU直连的,没有经过ISA总线。我原来的设想是就不会使用上面的数组 [] ,也就调用不到我们的cs89x0_probe()函数了。但事实是:
---->
可以看到这个地方是遍历所有的总线的对应数组,不管有没有这种总线存在。我们这的情况,虽然没有ISA总线,虽然我们的网卡没有直接连到ISA总线上,按照上面的说法,只要让我们的probe函数被调用了就行,
哪怕放在PCI总线, eisa总线,的对应数组中,都是可以的,甚至可以创建一个数组,里面放上我们的cs89x0_probe()这个函数,就可以了。
好了,现在知道了,我们的开发板的probe函数就是使用ISA对应的数组来调用到的。下面就看probe函数的本身实现了。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
前面提到过,probe函数中要把系统的资源告诉内核,(就是吧net_device丰满一下,然后提交到内核去),其实际的函数函数是cs89x0_probe1,这里处理的函数cs89x0_probe只是准备下参数而已。
probe函数的主要功能是:http://blog.chinaunix.net/uid-28708203-id-3785215.html
0,检测网卡是否存在
1,映射网卡I/O资源。 0和1其实算作一步
2,申请中断(如果需要,一般都是在open中申请)
3,申请DMA,(如果需要,一般都是在open中申请)
4,提交体积
******************************************************************************************************************************************************
下面我们需要详细讲一讲上面提到的网卡I/O资源映射这件事:
http://blog.chinaunix.net/uid-28708203-id-3793252.html
使用网卡的I/O资源有两种方式,把他映射到I/O地址空间或者映射到内存地址空间。
这边是ARM,所以我们只能映射到内存地址空间。其有两种方式:动态映射,和静态映射,
动态映射往往是在cs89x0_probe函数中调用函数ioremap()函数来把物理内存映射为内核地址空间的虚拟地址。
而静态映射是在内核启动的时候,统一映射所有的外设的I/O外存空间。不知道内核启动时候的映射,后期系统运行过程中还能不能更改???
http://blog.chinaunix.net/uid-28708203-id-3791175.html
http://blog.chinaunix.net/uid-28708203-id-3791177.html
这两篇blog讲的相当透彻,不再罗嗦了。
韦东山的书上使用的是动态映射这种方式。
网上搜到的大量的移植文档,是采用的静态映射这种方式。
******************************************************************************************************************************************************
arch/arm/mach-s3c2440/mach-smdk2440.c
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ok,现在分析下probe的具体实现:
其实想想,我们本质上就是想在内核启动的时候,调用网卡的probe函数,至于什么方式,放在总线的对应数组还是别的什么方式,都是可以的。
下面从网卡移植入口,看看我们移植的时候是如何做,使得内核启动的时候,去probe了我们的网卡。
综合比较了下网上关于移植的blog,又加上韦东山的书。发现上面的想法是错误的。
虽说我的开发板上是网卡和CPU直连的,没有经过ISA总线。我原来的设想是就不会使用上面的数组 [] ,也就调用不到我们的cs89x0_probe()函数了。但事实是:
static int net_olddevs_init(void)
---->
static void (int )
点击(此处)折叠或打开
- 282static void __init ethif_probe2(int unit)
-
283{
-
284 unsigned long base_addr = netdev_boot_base("eth", unit);
-
285
-
286 if (base_addr == 1)
-
287 return;
-
288
-
289 (void)( probe_list2(unit, m68k_probes, base_addr == 0) &&
-
290 probe_list2(unit, eisa_probes, base_addr == 0) &&
-
291 probe_list2(unit, mca_probes, base_addr == 0) &&
-
292 probe_list2(unit, isa_probes, base_addr == 0) &&
-
293 probe_list2(unit, parport_probes, base_addr == 0));
- 294}
可以看到这个地方是遍历所有的总线的对应数组,不管有没有这种总线存在。我们这的情况,虽然没有ISA总线,虽然我们的网卡没有直接连到ISA总线上,按照上面的说法,只要让我们的probe函数被调用了就行,
哪怕放在PCI总线, eisa总线,的对应数组中,都是可以的,甚至可以创建一个数组,里面放上我们的cs89x0_probe()这个函数,就可以了。
好了,现在知道了,我们的开发板的probe函数就是使用ISA对应的数组来调用到的。下面就看probe函数的本身实现了。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
前面提到过,probe函数中要把系统的资源告诉内核,(就是吧net_device丰满一下,然后提交到内核去),其实际的函数函数是cs89x0_probe1,这里处理的函数cs89x0_probe只是准备下参数而已。
probe函数的主要功能是:http://blog.chinaunix.net/uid-28708203-id-3785215.html
0,检测网卡是否存在
1,映射网卡I/O资源。 0和1其实算作一步
2,申请中断(如果需要,一般都是在open中申请)
3,申请DMA,(如果需要,一般都是在open中申请)
4,提交体积
******************************************************************************************************************************************************
下面我们需要详细讲一讲上面提到的网卡I/O资源映射这件事:
http://blog.chinaunix.net/uid-28708203-id-3793252.html
使用网卡的I/O资源有两种方式,把他映射到I/O地址空间或者映射到内存地址空间。
这边是ARM,所以我们只能映射到内存地址空间。其有两种方式:动态映射,和静态映射,
动态映射往往是在cs89x0_probe函数中调用函数ioremap()函数来把物理内存映射为内核地址空间的虚拟地址。
而静态映射是在内核启动的时候,统一映射所有的外设的I/O外存空间。不知道内核启动时候的映射,后期系统运行过程中还能不能更改???
http://blog.chinaunix.net/uid-28708203-id-3791175.html
http://blog.chinaunix.net/uid-28708203-id-3791177.html
这两篇blog讲的相当透彻,不再罗嗦了。
韦东山的书上使用的是动态映射这种方式。
网上搜到的大量的移植文档,是采用的静态映射这种方式。
******************************************************************************************************************************************************
arch/arm/mach-s3c2440/mach-smdk2440.c
static struct [] = {
在这个数组中添加内容:
,{
// support cs8900
.virtual = vSMDK2410_ETH_IO, // virtural addr that will be remapped
.pfn = __phys_to_pfn(S3C2410_CS3 + (1<<24)),
.length = SZ_1M,
.type = MT_DEVICE,
}
或者是这么个格式
{vSMDK2410_ETH_IO,
0x19000000,
SZ_1M,
MT_DEVICE}
这个数组是下面函数调用的:******************************************************************************************************************************************************(, ());这个功能是把 物理地址 0x19000000映射到虚拟地址 vSMDK2410_ETH_IO 这个虚拟地址上去。******************************************************************************************************************************************************物理地址是这个的原因: 网卡已经焊接到板子上了,线路已经了连好了,就好比是RAM是分配了0x30000000 ~ 0x34000000这段物理地址空间。网卡被分配给了19000000,这个地址是从电路图得出来的:我们要判断某一个功能芯片是连接到了CPU哪个区域(物理地址空间),应该从CPU芯片的一看起。首先我们的cpu物理地址空间是 128MB×8=1024MB分为8个区域nGCS0-7。我们通过cpu出来的引脚 哪个连到 功能芯片上,来判断我们的功能芯片连到了CPU的哪个区域。看电路图上 CPU的引脚nGCS0--------------nGCS0nGCS1--------------nGCS1nGCS2--------------nGCS2nGCS3--------------nLAN_CSnGCS4--------------nGCS4nGCS5--------------nGCS5然后看CS8900A的引脚,有一个nCLIPSLE------------nLAN_CS那么证明网卡是连到第四个区域了,nGCS3的起始地址是18000000。我们再看下地址线,由于只有128MB的地址空间,所有有效的地址线就是 27条。网卡的起始地址如何确定出是 19000000???看下虚拟地址vSMDK2410_ETH_IO。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ok,现在分析下probe的具体实现:
static int net_olddevs_init(void)
---->static void (int )
---> (, , == 0)
--->struct net_device * (int )
struct net_device * (int )
这个函数真的仅仅的是一个参数准备函数,重头戏在
static int (struct net_device *dev, int , int )
这里有个好奇,既然我们的ARM中是只能使用“把网卡I/O资源映射到内存地址空间”,probe1中针对某一个端口地址,进行检测。
检测哪几个端口,是由数组netcard_portlist决定的。数组有几个成员,就调用几次 probe1。 原因是:
这个代码是针对X86来写的,X86使用的是I/O地址空间的方式,外设的I/O资源需要映射到I/O地址空间中去,但是他不是说地址空间的任意
值都可以,只能映射到有限的几个地址(开始)处。
这有限个,就是数组的成员。
这里,我既然是ARM的,明显的就不用检测了,我们不使用这些端口,这个机制只适用于X86。我们通过上面两种方式,把网卡的I/O资源映射到
内存地址空间。
但是probe1函数还是要执行,因为他不仅仅是探测,确定 I/O地址空间。也进行了其他一些操作。
韦东山那边,他是在probe函数中,控制了对netcard_portlist数组的使用,因为我们开发板什么布局我们已经知道了,不需要探测,直接映射就好。
那第二种方式,静态映射网卡I/O资源到内存地址空间的方式。移植的教程中都没有修改cs89x0.c,那么也就是说,内核还是会探测那么多个端口地址。
估计探测不出来也就作罢。我们下一步,还是去看看怎么使用的这些个地址。往下走吧。