cs8900a驅動移植筆記

硬件環境:SBC-2410X開發板(CPU:S3C2410X)
內核版本:2.6.11.1
運行環境:Debian2.6.8
交叉編譯環境:gcc-3.3.4-glibc-2.3.3
第一部分 網卡CS8900A驅動程序的移植
一、從網上將Linux內核源代碼下載到本機上,並將其解壓:
#tar jxf linux-2.6.11.1.tar.bz2
二、打開內核頂層目錄中的Makefile文件,這個文件中需要修改的內容包括以下兩個方面。
(1)指定目標平臺。
 移植前:
        ARCH?= $(SUBARCH)
 移植後:
 ARCH            :=arm
(2)指定交叉編譯器。
  移植前:
 CROSS_COMPILE  ?=
 移植後:
 CROSS_COMPILE   :=/opt/crosstool/arm-s3c2410-linux-gnu/gcc-3.3.4-glibc-2.3.3/bin/arm-s3c2410-linux-gnu-
注:這裏假設編譯器就放在本機的那個目錄下。
三、添加驅動程序源代碼,這涉及到以下幾個方面。(1)、從網上下載了cs8900.c和cs8900.h兩個針對2.6.7的內核的驅動程序源代碼,將其放在drivers/net/arm/目錄下面。
#cp cs8900.c  ./drivers/net/arm/
#cp cs8900.h  ./drivers/net/arm/
並在cs8900_probe()函數中,memset (&priv,0,sizeof (cs8900_t));函數之後添加如下兩條語句:
__raw_writel(0x2211d110,S3C2410_BWSCON);
__raw_writel(0x1f7c,S3C2410_BANKCON3);
注:其原因在"第二部分"解釋。
(2)、修改drivers/net/arm/目錄下的Kconfig文件,在最後添加如下內容:
Config ARM_CS8900
   tristate "CS8900 support"
 depends on NET_ETHERNET && ARM && ARCH_SMDK2410
 help
   Support for CS8900A chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the  Ethernet-HOWTO, available from  as well as .
   To compile this driver as a module, choose M here and read
.  The module will be
   called cs8900.o.
注:內核系統配置文件由2.4版本的config.in變成了2.6版本Kconfig文件,在這個文件裏面添加如上內容,則在運行make menuconfig或者make xconfig命令的時候就會出現:
        [ ]   CS8900 support 
這一選項。
(3)、修改drivers/net/arm/目錄下的Makefile文件,在最後添加如下內容:
obj-$(CONFIG_ARM_CS8900)    += cs8900.o
注:2.6版本內核的Makefile文件也與2.4版本的有所不同。添加以上語句,就會使內核在編譯的時候根據配置將cs8900A的驅動程序以模塊或靜態的方式編譯到內核當中。
(4)、在/arch/arm/mach-s3c2410/mach-smdk2410.c文件中,找到smdk2410_iodesc[]結構數組,添加如下如下內容:{vSMDK2410_ETH_IO, 0x19000000, SZ_1M, MT_DEVICE}
修改之後變成了:
 static struct map_desc smdk2410_iodesc[] __initdata = {
       /* nothing here yet */
        /* Map the ethernet controller CS8900A */        {vSMDK2410_ETH_IO, 0x19000000, SZ_1M, MT_DEVICE}
};
 注:由於在驅動程序的開發的時候,在驅動程序當中所用到的跟設備有關的地址都是虛擬地址,也就是說驅動程序操作的都是虛擬地址,那麼要使驅動程序對設備的操作反映到設備上去,就得將設備的物理地址映射到正確的虛擬地址上去,從而保證驅動程序對虛擬地址的操作也就是對相應的物理地址操作。以上添加的語句就是爲了將網卡的物理地址(0x19000000)映射到vSMDK2410_ETH_IO所指向的虛擬地址上去,上面的結構還定義了網卡虛擬地址所佔用的區間,也就是從vSMDK2410_ETH_IO開始的SZ_1M大小的去間,並指定了該區間所指向的域(的屬性)。(疑問:在本開發板上,網卡佔用的是CPU的nGCS3片選信號,也就是在Bank3,根據處理器的地址空間定義,這個地址應該是0x18000000,爲什麼這裏使用的是0x19000000?查找到2.4.18的內核當中,也是用0x19000000來進行映射。)
(5)、在include/asm-arm/arch-s3c2410/目錄下創建smdk2410.h文件,其內容爲:
#ifndef _INCLUDE_SMDK2410_H_
#define _INCLUDE_SMDK2410_H_
#include
#define pSMDK2410_ETH_IO         0x19000000
#define vSMDK2410_ETH_IO  0xE0000000
#define SMDK2410_ETH_IRQ   IRQ_EINT9
#endif // _INCLUDE_SMDK2410_H_
注:因爲在網卡驅動程序當中,用到了一些常量,所以特意在此添加這個頭文件。這個頭文件定義了網卡的物理地址、虛擬地址以及網卡佔用的中斷線。
四、配置、編譯內核。在內核頂層目錄當中鍵入:
  #make smdk2410_defconfig
由於2.6的內核默認就支持了S3C2410,所以就有一個默認的內核配置文件。裏面只是包括了一個簡單的配置,要使網卡編譯進內核,還要進行手工配置。
#make menuconfig
       Networking support  --->  
Ethernet (10 or 100Mbit)  --->
[*]   CS8900 support
將剛纔添加的網卡驅動程序靜態添加到內核當中。
最後進行內核編譯。
#make
然後將鏡像下載到開發板中去。
第二部分 問題解析
在移植網卡的過程中,並不是一帆風順的,整個過程遇到了問題雖然不多,但是去尋找問題的原因及解決的辦法的時候卻是非常曲折的。現在將本人在進行網卡驅動移植過程中所遇到的問題以及解決方法介紹如下。
因爲經驗不足,剛開始進行工作的時候,沒有將移植的思路明確。最先是打算將開發板供應商隨板提供的2.4.18內核下的驅動程序cs8900a.c移植到2.6.10的內核下。首先就是計劃先以編譯模塊的方式將該程序編譯通過之後,再將起編譯到2.6.10的內核當中,然後再對其進行邏輯上的修改。在模塊編譯該驅動程序的時候,首先碰到的問題就是頭文件的問題,根據編譯的出錯信息,挨個將頭文件添加好了。此時碰到的問題就是交叉編譯器(arm-s3c2410-linux-gnu-gcc)編譯到cs89x0_probe()函數的時候出錯。指向:BWSCON這一行,出錯信息是:
Incorrect Lvalue in assignment
後來查閱內核源代碼,跟蹤BWSCON的定義,其實它是指向一個常量地址的指針。在用2.95.3的交叉編譯器對其進行編譯的時候不會出錯,而用3.3.4的交叉編譯器進行便宜的時候卻出錯,於是懷疑是跟編譯器有關。將對BWSCON和BANKCON3的賦值操作這兩條語句註釋掉之後就不會報錯,所以肯定了在3.3.4版本的交叉編譯器不支持這樣的操作。原來以爲這兩條語句是對別的某個寄存器進行的操作,對網卡驅動沒什麼影響,於是就將註釋之後的驅動程序加入到2.6.10的內核當中進行編譯,並下載到開發板當中。這個時候從串口打回控制檯的出錯消息是在很長時間內都無法解決的。如下:
Cirrus Logic CS8900A driver for Linux (Modified for SMDK2410)
         eth0: incorrect signature 0x1005
mice: PS/2 mouse device common for all mice
NET: Registered protocol family 2
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
NET: Registered protocol family 1
IP-Config: Device `eth0' not found.
Looking up port of RPC 100003/2 on 192.168.0.1
RPC: sendmsg returned error 101
portmap: RPC call returned error 101
Root-NFS: Unable to get nfsd port number from server, using default
Looking up port of RPC 100005/1 on 192.168.0.1
RPC: sendmsg returned error 101
portmap: RPC call returned error 101
Root-NFS: Unable to get mountd port number from server, using default RPC: sendmsg returned error 101
mount: RPC call returned error 101
Root-NFS: Server returned error -101 while mounting /friendly-arm/root
VFS: Unable to mount root fs via NFS, trying floppy.
VFS: Cannot open root device "nfs" or unknown-block(2,0)
Please append a correct "root=" boot option
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
     觀察串口打印的信息,發現vivi正確啓動了內核,內核也對cpu進行了初始化,但是網卡就是無法驅動起來。覈對驅動程序源代碼,發現在內核初始化網卡時,運行到了cs89x0_probe1()函數的時候,探測網卡的ProductID的時候讀回的數據不是網卡的ID:0x630e。也就是沒探測到網卡而退出了cs89x0_probe1()函數。當時懷疑的是2.4.18的驅動程序跟2.6.10的設備驅動程序寫法有很多不同,如果繼續這樣的工作,也許工作量很大,所以馬上轉變了工作思路,決定從網上下載2.6的CS8900A的驅動程序,在搜索了很長時間之後,終於在一個網站上下載到了2.6.7內核下的CS8900A的驅動程序。按照"第一部分"的步驟加進了驅動之後,下載新的內核,串口回傳的信息跟上面的信息是一樣的。
重新啓動開發板,問題依然存在,但是仔細對比了cs89x0_probe1()函數讀回來的數據,發現這個signature在變化,而且沒有找到其變化的規律。
查看了驅動程序以及CS8900A的Datasheet,發現驅動程序的邏輯是正確的,於是首先懷疑是在驅動程序中,網卡iobase的物理地址不對,於是查看開發板的原理圖,發現網卡用的是cpu的nGCS3片選信號,該片選信號對應的地址空間起始地址是0x18000000,而在驅動中對用的是0x19000000,於是修改arch/arm/mach-s3c2410/mach-smdk2410.c文件中的mdk2410_iodesc[]結構對io地址的映射,將物理地址改爲0x18000000,重新編譯後網卡仍然無法被驅動,只是這個時候驅動程序讀來的數據也就是那個signature不會因爲每次重起而改變的,也就是每次讀回來的數據都是固定的。這時又懷疑是虛擬地址不正確。將2.6的驅動與2.4的驅動進行了比較,發現2.4用的 虛擬地址是0xd000000,於是修改2.6內核中的虛擬地址爲0xe000000,可是網卡還是無法驅動,反覆修改了虛擬地址和物理地址,問題依舊存在。這個時候思路幾乎停止。經過思考之後,把工作的思路定位在比較2.4和2.6的驅動程序的區別上,經過仔細的比較,發現在2.4的驅動程序當中在cs89x0_probe1()函數裏有對寄存器的設置,而2.6的驅動程序則沒有,查找cpu的Datasheet,發現該設置是對cpu內部兩個重要的控制器的設置。下面先介紹一下這兩個寄存器。
在S3C2410X中BWSCON是Bus width & wait control register(總線寬度及等待控制寄存器),這個寄存器控制着系統地址空間內(包括bank0-bank7)的總線數據寬度以及是否等待。BANKCONn(n=0~7)寄存器是Bank control register。這個寄存器控制着處於某個bank區間內的總線的地址setup的時鐘週期,片選信號的保持時間,訪問週期等。這個兩個寄存器中每個位的含義可以參見S3C2410X數據手冊的5-13~5-15,在此不加以詳敘。
查看了cpu的數據手冊、開發板原理圖以及2.4的驅動程序之後,發現在2.4的驅動程序中的以下兩條語句:
BWSCON = (BWSCON & ~(BWSCON_ST3 | BWSCON_WS3 | BWSCON_DW3)) |  (BWSCON_ST3 | BWSCON_WS3 | WSCON_DW(3, BWSCON_DW_16));
BANKCON3= BANKCON_Tacs0 | BANKCON_Tcos4 | BANKCON_Tacc14 | BANKCON_Toch1 | BANKCON_Tcah4 | BANKCON_Tacp6 | BANKCON_PMC1;
實際上是對地址區間BANK3(因爲開發板用的的是nGCS3,處於BANKCON3區間內)進行了設置。
先看對BWSCON的設置,這條語句實際上是要使BWSCON中除了ST3、WS3和DW3這四個位的其它各位得到保護,使ST3、WS3和DW3這四個位清零,然後再對ST3、WS3和DW3這四個位進行設置,經過這條語句之後,ST3、WS3和DW3這四個位被設置成了1101(二進制),意思就是對BANK3採用cpu引腳(A17、B16、C15、A16,這幾個引腳都分別有三種信號表示意義)的nBE信號(具體什麼意思,本人也不知道),對BANK3使用WAIT enable,使用16位的數據總線寬度。
其次就是對BANKCON3寄存器的設置。這條語句將BANKCON3設置成了0001 1111 0111 1100。(各個位的意思,我也沒弄明白什麼意思,估計就是設置各種操作的時鐘週期數目。)
清楚了驅動程序對寄存器的設置之後,就想到應該在vivi裏面對cpu的這幾個內存控制寄存器進行設置,於是找到vivi源代碼中include/platform/目錄下的smdk.h文件中對寄存器的初始化值的設置,修改之後如下:
/*#define vBWSCON               0x22111120*/
#define vBWSCON                 0x2211d110
#define vBANKCON0               0x00000700
#define vBANKCON1               0x00000700
#define vBANKCON2             0x00000700
#define vBANKCON3               0x00001f7c
#define vBANKCON4             0x00000700
#define vBANKCON5               0x00001f7c
#define vBANKCON6               0x00018005
#define vBANKCON7               0x00018005
#define vREFRESH                0x008e0459
#define vBANKSIZE               0xb2
#define vMRSRB6                 0x30
#define vMRSRB7                 0x30
重新通過JTAG口下載vivi,重新啓動內核後,發現問題依然存在,於是就想到在驅動程序裏面添加對內存控制器的設置。最開始是想模仿2.4的驅動程序那樣,找到各個相應的宏去代替2.4驅動程序裏的宏,在memset()函數之前添加,但是編譯的時候出錯,出錯信息是:
LValue incorrect in assignment
跟蹤內核的代碼發現對S3C2410_BWSCON、S3C2410_BANKCON3宏的定義分別返回的其實是一個常量,分別是0xf0100000和0xf0100010,這個常量是右值,不能當左值。因此就想到採用如下直接對地址進行賦值的方式對寄存器進行設置:
*(volatile unsigned short __force *)(0xf0100000)=(0x2211d110);
*(volatile unsigned short __force  *)(0xf0100010)=(0x00001f7c);
後來運行內核時發現,驅動程序初始化到了memset()函數之後,上述兩條語句之前就停止不動了(疑問:不知道這是什麼原因)。最後查找linux內核代碼找到了__raw_writell(v,a)這樣一個函數,於是就將上述兩條語句替換成:
__raw_writel(0x2211d110,S3C2410_BWSCON);
__raw_writel(0x1f7c,S3C2410_BANKCON3);
這樣經過設置內存控制寄存器之後,網卡終於被驅動起來了。但是由於在移植的過程中沒有將內核對devfs設備文件系統的支持編譯進內核裏面去,所以當網卡驅動之後去尋找網絡文件系統的時候發現找不到根文件系統,最後在配置內核的時候將devfs的支持加入,如下:
File systems  ---> 
  Pseudo filesystems  --->
     [*] /dev file system support (OBSOLETE)
之後,linux可以從主機上找到根文件系統,並創建init進程。這樣,網卡驅動程序經過接近三週的時間終於被驅動了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章