小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

pci 學習筆記

 clover_xian 2012-05-03
pci 學習筆記 (2011-04-02 15:40)
分類: study&research


  PCI是Peripheral Component Interconnect(外設部件互連標準)的縮寫,它是目前個人電腦中使用最為廣泛的接口,其位寬為32位或64位,工作頻率為33MHz,最大數(shù)據(jù)傳輸率為133MB/sec(32位)和266MB/sec(64位)。可插接顯卡、聲卡、網(wǎng)卡、內(nèi)置Modem、內(nèi)置ADSL Modem、USB2.0卡、IEEE1394卡、IDE接口卡、RAID卡、電視卡、視頻采集卡以及其它種類繁多的擴展卡.
  目前PCI-E是PCI最新的發(fā)展方向,串行,點對點傳輸,每個傳輸通道獨享帶寬;支持雙向傳輸模式和數(shù)據(jù)分通道傳輸模式;在PCI-E 3.0規(guī)范中,X32端口的雙向速率高達320Gbps,可以滿足新一代的I/O接口,比如:千兆(GE)、萬兆(10GE)的以太網(wǎng)技術(shù)、4G/8G的FC技術(shù)
一. PCI 引腳


1. 接口控制管腳 (出問題時常測這些管腳)

FRAME#:幀周期信號。Master驅(qū)動,表示一次訪問的開始和持續(xù)時間。 FRAME#無效時,是傳輸?shù)淖詈笠粋€數(shù)據(jù)周期。

IRDY#:Master準備好信號。
TRDY#:Slave準備好信號。

當這兩者同時有效時,才能進行完整的數(shù)據(jù)傳輸,否則即為等待周期。

在寫周期,IRDY#信號有效時,表示有效的數(shù)據(jù)信號已在AD0~AD31中建立;
在讀周期,IRDY#信號有效時,表示Master已做好接收數(shù)據(jù)的準備。

在寫周期,TRDY#信號有效,表示Slave已做好了接收數(shù)據(jù)的準備。
在讀周期,TRDY#信號有效,表示有效數(shù)據(jù)已被送入AD0~AD31中,


STOP#:停止數(shù)據(jù)傳送信號,由Slave發(fā)出。當它有效時,表示Slave請求Master終止當前的數(shù)據(jù)傳送。

IDSEL:初始化設備選擇信號。在讀寫配置空間時,用作Slave的片選信號(Slave通常把IDSEL連到AD[31:0]上的一根,PFA中的device id就是這么確定的)

DEVSEL#:設備選擇信號,由Slave驅(qū)動,該信號有效時,當前Slave設備已被選中
 
二.時序
讀時序


寫時序:


 
 
 
三.PCI配置空間

256字節(jié)的PCI配置空間分為64字節(jié)的頭標區(qū)和192字節(jié)的設備相關區(qū)兩部分。頭標區(qū)的各個寄存器用來唯一地識別設備;設備相關區(qū)則保存一些與設備相關的數(shù)據(jù)。

 

配置空間的頭標區(qū)又分為兩部分:前16個字節(jié)的定義在各種類型的PCI設備中都是一樣的;剩余的字節(jié)隨設備類型不同而有所不同。位于偏移地址0EH處的頭標類型字段規(guī)定了頭標區(qū)的布局結(jié)構(gòu)。目前,規(guī)范定義了三種頭標類型。

 

頭標類型

設備

2

PCI-CardBus

1

PCI-PCI

0

除上述橋外的所有設備

 

因為PCI網(wǎng)卡的頭標類型是0,所以下面我們就來詳細說說其布局結(jié)構(gòu),至于其他類型的頭標請讀者自行閱讀。圖3就是頭標類型0的頭標區(qū)的布局。頭標區(qū)中的寄存器根據(jù)功能可分成下面幾組:

 

1. 設備的識別

1       供應商代碼:該寄存器用于識別PCI設備的制造商,具體代碼由PCI SIGhttp://www.)分配。0FFFFH是無效的供應商代碼。

2       設備代碼。該寄存器用來標識某供應商生產(chǎn)的具體設備,代碼由各供應商定義。供應商代碼和設備代碼,讀者可以到網(wǎng)站http://www./查閱。

 

3 頭標類型0的頭標區(qū)的布局

 

3       版本號。該寄存器用來定義指定設備的版本信息。

4       頭標類型。該字段的第7位為“1”標識該設備是多功能設備,為“0”標識為單功能設備;該字段的06位就是上文表中所述的頭標類型。

5       設備分類代碼。用來標識設備的總體功能和特定的寄存器級編程接口。

上面5個字段均為只讀類型,所有的PCI設備都必須實現(xiàn)其功能。

 

2. 設備控制和設備狀態(tài)

1       命令寄存器為一個設備發(fā)出和響應PCI總線命令提供粗略的控制。圖4就是命令寄存器格式。

4 命令寄存器格式

 

我們比較感興趣的位有:

a.0I/O空間控制):控制對I/O空間訪問的響應。該位為0時,禁止設備響應對I/O空間的訪問;該位為1時,允許設備響應I/O空間的訪問。缺省設置為0

b.1(存儲器空間控制):控制一個設備對存儲器空間訪問的響應。該位為0時,禁止響應;該位為1時,允許設備響應對存儲器空間的訪問。缺省設置為0。

 

至于其他位的功能,讀者若有興趣可以自行查閱。

 

2       狀態(tài)寄存器用來記錄PCI總線有關的狀態(tài)信息。

 

3. 基址寄存器

PCI設備中,除了配置空間外,還有兩個物理空間:內(nèi)存空間和I/O空間。為了訪問這兩個地址空間,就必須使用基址寄存器。頭標類型0中涉及3種基址寄存器:內(nèi)存空間基址寄存器、I/O空間基址寄存器和擴展ROM基址寄存器。關于基址寄存器,我們下一章重點講述。

 

4. 其他寄存器

其他寄存器包括一些本文不涉及到的寄存器,如中斷引腳、中斷線等等。有興趣的讀者可以自行閱讀。

 

四.PCI配置空間的訪問

上面說過,PCI規(guī)范使用從0CF8H~0CFFH 8I/O地址來訪問所有設備的PCI配置空間。這8個字節(jié)實際上構(gòu)成了兩個32位寄存器:0CF8H寄存器叫做“配置地址寄存器”;0CFCH叫做“配置數(shù)據(jù)寄存器”。當要訪問配置空間的寄存器時,先向地址寄存器寫上目標地址,然后就可以從數(shù)據(jù)寄存器中讀寫數(shù)據(jù)了J。

 

我們說過,PCI配置空間對應于一個PCI邏輯設備,所以要訪問一個配置空間的某個寄存器,必須要指定:PCI總線號、PCI設備號、PCI設備功能號和寄存器號。配置地址寄存器的格式如下:

 

31

30   24

23     16

15     11

10    8

7       2

1

0

使能位

保留

總線號

設備號

功能號

寄存器號

0

0

 

0、1位上的“0”是用來要求你只能按雙字(4字節(jié))來讀寫配置空間寄存器。第31位“使能位”用來決定是否允許訪問配置空間:為“1”時表示可以訪問;為“0”時表示不可以訪問。

 

例如,為了讀總線號0、設備號17H、功能號030H寄存器,你可以使用下面的代碼:

 

MOV  EAX, 8000B830H

MOV  DX, 0CF8H

OUT   DX, EAX

 

MOV DX, 0CFCH

IN  EAX, DA

 

五.PCI配置空間的遍歷

從上面的配置地址寄存器的格式我們可以看出:總線號從0255、設備號從031、功能號從07。根據(jù)配置空間的第0個寄存器是否返回0FFFFH值來判斷是否存在該PCI設備。下面是PCI配置空間遍歷的流程圖:

5遍歷PCI配置空間流程圖

六.基址寄存器

PCI設備中,除了配置空間外,還有兩個物理空間:內(nèi)存空間和I/O空間。為了訪問這兩個地址空間,就必須使用基址寄存器。頭標類型0中涉及3種基址寄存器:內(nèi)存空間基址寄存器、I/O空間基址寄存器和擴展ROM基址寄存器。

 

PCI設備可以在地址空間中浮動是PCI局部總線中最重要的功能之一。它能夠簡化設備的配置過程。在系統(tǒng)上電時,與設備無關的系統(tǒng)軟件必須確定有哪些設備存在,同時建立一個統(tǒng)一的地址映射關系,并確定一個設備是否有擴展ROM。

 

1.   地址映射

加電軟件在引導操作系統(tǒng)之前必須建立一個統(tǒng)一的地址映射。也就是說,必須確定在系統(tǒng)中有多少存儲器以及系統(tǒng)中的I/O控制器要求多少地址空間。當這些信息確定之后,加電軟件便可以把I/O控制器映射到合理的地址空間并引導系統(tǒng)。為了使這種映射能夠做到與響應的設備無關,從而在配置空間的頭標區(qū)中安排了一個供映射時使用的基址寄存器。

 

在所有的基址寄存器中,位0均為只讀位并且用來決定能夠是存儲器空間還是I/O空間。如果該位為0,則表示映射到存儲器空間;若為1則表示映射到I/O地址空間。

 

2.   存儲器基地址寄存器

映射到存儲器空間的基址寄存器可以是32位寬度,也可以是64位寬度(支持映射到一個64位地址空間時)(如圖6)。

6  32/64存儲器基地址寄存器格式

 

其中位0要用硬件方法使其恒為0。而位2和位1兩位用來表示映射類型,具體如下:

 

2和位1

映射類型

00

基地址寄存器為32位寬,可以在32位表示的存儲器地址范圍的任何地方進行映射

01

保留

10

基地址寄存器為64位寬,可以映射到以64位表示的存儲器空間的任何地方

11

保留

 

至于位3,若數(shù)據(jù)是可預取的,就應將它置為1,否則清0。該寄存器的區(qū)域各位用來將一設備映射到存儲器空間。

 

基地址寄存器中用于32位存儲器譯碼器的位【31::4】和用于64位存儲器譯碼器的位【63::4】稱為基地址單元。它的作用是:確定與譯碼器相關的存儲器的大小;給譯碼器分配地址。如果存儲器設備需要小于4K的存儲空間,規(guī)范建議存儲器范圍強行設為4KB

 

3.   I/O基地址寄存器

映射到I/O空間的基址寄存器寬度總是32位(如圖7):

 

7  I/O基地址寄存器格式

 

其中位0值為1(用硬件實現(xiàn)的),位1為保留位并且其讀出值必須為0,其余各位用來把設備映射到I/O空間。

 

當基地址寄存器位0的返回值為1時,表示這是一個I/O譯碼器,而不是存儲器譯碼器,位1保留并總是返回0,【31::2】是基地址單元,并用于確定需要的I/O塊容量,設置它的起始地址。

 

規(guī)范要求映射它的控制寄存器組到I/O空間的 設備不必請求每個I/O基地址寄存器超過256個單元。

 

4.   確定塊容量和分配地址范圍

要確定存儲器的容量或I/O空間大小可以通過簡單地向基地址寄存器寫入全“1”并回讀來確定。若返回一個是0值,則表示未實現(xiàn)基地址寄存器;如果讀回地值為非0,則編程人員通過從基地址單元的最低有效位向上掃描返回值以找到第一個被成功置“1”的位來確定所需存儲器的容量或I/0空間的大小。假設寄存器的位0是一個加權(quán)二進制1,那么位1的值就是2,位2的值就是4,依此類推。這樣,在基地址單元中第一個發(fā)現(xiàn)的1所對應的加權(quán)二進制值便是所需的空間數(shù)。這也是寄存器的第一個可讀/可寫位,在它之上的所有位鈞定義為可讀/可寫位。這個信息發(fā)現(xiàn)后,程序?qū)?/SPAN>32/64位存儲器起始地址或32I/O地址寫入基地址寄存器中。

 

5.   擴展ROM基地址寄存器

有些PCI設備,尤其是那些準備用于PC結(jié)構(gòu)擴展板上的設備,需要EPROM作為擴展ROM。為此,在配置空間偏移地址30H處開始定義了四個字節(jié)的寄存器,用來處理這個擴展ROM的基地址和大小。(如圖8)

 

8 擴展ROM基地址寄存器格式

 

該寄存器和32位基地址寄存器相比,除了位的編碼和用途不同之外,其它功能完全相似。它的高21位對應于擴展ROM基地址的高21位。一個設備實際實現(xiàn)的位數(shù)取決于該設備要求多大的地址空間。例如,一個設備要求它的擴展ROM映射到一64KB存儲區(qū)域時,它就應該實現(xiàn)此寄存器的高16位,其它5位用硬件方法使它們恒為0。凡是支持擴展ROM的設備必須實現(xiàn)這個寄存器。

與設備無關的配置軟件通過對擴展ROM基址寄存器的地址位上寫入全“1”,然后再讀回以確定設備要求多大的地址范圍。所有的無關位上都返回0,從而有效地指出了地址邊界,也就知道了設備要求的這一塊地址空間的大小。一個設備要求的地址空間范圍不能超過16MB。

 

這個寄存器的位0用來控制相應的設備是否能夠接受對其擴展ROM的訪問。當該位為0時,禁止訪問設備的擴展ROM地址空間;當該位為1時,允許將本寄存器的其它位作為參數(shù)進行地址譯碼。命令寄存器中的存儲器空間位優(yōu)先于擴展ROM的使能位,但是,如果存儲器空間位和擴展ROM的的使能位同時為1時,設備就必須響應對其擴展ROM的訪問。擴展ROM的使能位在復位后應該為0。

 

七.PCI拓撲結(jié)構(gòu)
PCI拓撲結(jié)構(gòu),有如下例子



    在上圖的總線結(jié)構(gòu)中,ethernet設備和pci-pci bridge的資源空間必須要是pci bus0的一個子集
    同理,SCSI和VIDEO同類型資源必須要是pci_bus1的子集。
    CPU訪問PCI的過程是這樣的(只有一個根總線和pci-pci bridge過濾窗口功能打開的情況):
    1.cpu向pci發(fā)出一個I/O請求。
    首先經(jīng)過根總線.它會判斷是否在它的資源范圍內(nèi).如果在它的范圍,它就會丟向總線所在的每一個設備.包括pci bridge. 如果沒有在根總線的資源范圍,則不會處理這個請求.
    2.如果pci設備判斷該地址屬于它的資源范圍,則處理后發(fā)出應答
    3.pci bridge接收到這個請求,它會判斷I/O地址是否在它的資源范圍內(nèi).如果在它的范圍,它會把它丟到它的下層子線.
    4.下層總線經(jīng)過經(jīng)過相同的處理后,就會找到這個PCI設備了
    一個PCI設備訪問其它PCI設備或者其它外設的過程:
    1.首先這個PCI發(fā)出一個請求,這個請求會在總線上廣播
    2.如果要請求的設備是在同級總線,就會產(chǎn)生應答
    3.請求的設備不是在同層總線,就會進行pci bridge.pci橋判斷該請求不在它的范圍內(nèi)(目的地不是它下層的設備),就會將它丟向上層.
    4.這樣輾轉(zhuǎn)之后,就能找到對應的設備了


八.PCI枚舉過程
通過PCI枚舉,CPU知道當前系統(tǒng)上有多少PCI設備,多少根PCI總線,PCI配置空間初始化。
    PCI 總線掃描的原理是從總線 0 掃描到總線 255,對于每條總線,系統(tǒng)都會掃描所有(總線號,設備號,功能號),讀出每個設備配置空間的Device ID和Vendor ID寄存器,如果這兩個寄存器的值是個無效值(0xFFFF),則說明當前位置上沒有設備,接著掃描下一個位置。
    如果是有效值(非0xFFFF),當前位置是個有效的 PCI 設備/橋。進而再讀取該設備的 Header Type 寄存器,如果該寄存器為 1,則表示當前設備是 PCI 橋,否則是 PCI 設備。
Register Number:配置空間寄存器偏移量
Function Number:多功能設備有多個功能號
Device Number:設備編號
Bus Number:總線編號

對所有 PCI 總線進行編號
    PCI 橋如何知道它所連接的 PCI 總線情況呢?這就需要對 PCI 橋進行總線編號。前面介紹過 PCI 橋提供了 Primary Bus Number、Secondary Bus Number 和 Subordinate Bus Number 三個寄存器用于標志該橋所連接的 PCI 總線,下面通過一個示例來說明內(nèi)核對于 PCI 總線是如何進行編號的。

1.系統(tǒng)運行初始,Bus A 為 0,通過上面的 PCI 總線掃描得到連接在 Bus A 上的 PCI 橋(即圖中Bridge 1)
2.下面開始設置 Bridge 1 的 Bus 寄存器。將 Primary Bus Number 寄存器設置成 Bus A 的編號,即 0。將 Secondary Bus Number 寄存器設置成 Bus B 的編號,它的值等于(Bus A + 1),也就是 1。由于暫時無法知道該橋所能訪問的所有下行總線數(shù)目,Subordinate Bus Number 寄存器暫時設置成 0xFF。
3.當掃描完所有 Bus A 上所有(設備號,功能號)后,開始掃描 Bus B,Bus B 的編號在掃描完 Bus A 后已經(jīng)得到,為 1。Bus B 的掃描方法同步驟(1),先掃描出 Bus B 上的 PCI 橋(即圖中的 Bridge 2),然后配置 Primary Bus Number 寄存器為 1,Secondary Bus Number 寄存器為 2,而 Subordinate Bus Number 寄存器依然為 0xFF。
4.Bus B 掃描完后得到 Bus C 的編號,為2。下面開始掃描 Bus C,因為 Bus C 上沒有 PCI 橋,于是在掃描完其它(設備號,功能號)后,Bus C 的掃描結(jié)束。
5.由于 Bridge 2 所能訪問到的最大 Bus 編號是 2,因此重新設置 Bridge 2 的 Subordinate Bus Number 寄存器為 2。
6.由于 Bridge 1 所能訪問到的最大 Bus 編號也是 2,因此重新設置 Bridge 1 的 Subordinate Bus Number 寄存器為 2。
7.總線編號結(jié)束。


九.Linux內(nèi)核PCI數(shù)據(jù)結(jié)構(gòu)
內(nèi)核(linux-2.6.24) 提供了三類數(shù)據(jù)結(jié)構(gòu)用以描述 PCI 控制器、PCI 設備以及 PCI 總線。
數(shù)據(jù)結(jié)構(gòu)關系如下所示

PCI 控制器 用 pci_controller 結(jié)構(gòu)來描述,它有以下幾個主要的屬性:
index:該屬性標志 PCI 控制器的編號。
next:該屬性指向下一個 PCI 控制器,通過 next 屬性,PCI 控制器可以形成一個單向鏈表。
first_busno:該屬性標志了連接在該控制器上第一條總線的編號。
last_busno:該屬性標志了連接在該控制器上最后一條總線的編號。
ops:該屬性標志了當前 PCI 控制器所對應的 PCI 配制空間讀寫操作函數(shù)。
io_space:該屬性標志了當前 PCI 控制器所支持的 IO 地址空間。
mem_space:該屬性標志了當前 PCI 控制器所支持的 Memory 地址區(qū)間。
cfg_addr:該屬性標志了當前 PCI 控制器發(fā)起 Configuration 訪問方式時所需要寫入的地址空間。
cfg_data:該屬性標志了當前 PCI 控制器發(fā)起 Configuration 訪問方式時所需要讀寫的數(shù)據(jù)空間。
bus:該屬性標志了當前 PCI 控制器所連接的 PCI 總線,它對應的數(shù)據(jù)結(jié)構(gòu)是 pci_bus。
PCI 總線 用 pci_bus 結(jié)構(gòu)來描述,它有以下幾個主要的屬性:
parent:可通過該屬性索引到上層 PCI 總線。
self:該屬性標志了連接的上行 PCI 橋(對應的數(shù)據(jù)結(jié)構(gòu)是 pci_dev)。
children:該屬性標志了總線連接的所有 PCI 子總線鏈表。
devices:該屬性標志了總線連接的所有 PCI 設備鏈表。
ops:該屬性標志了總線上所有 PCI 設備的配制空間讀寫操作函數(shù)。
number:該屬性標志了當前 PCI 總線的編號。
primary:該屬性標志了 PCI 上行總線編號。
secondary:該屬性標志了 PCI 下行總線編號。
subordinate:該屬性標志了能夠訪問到的最大總線編號。
resource:該屬性標志了 Memory/IO 地址空間。
PCI 設備 用 pci_dev 結(jié)構(gòu)來描述,它有以下幾個主要的屬性:
global_list:Linux 定義了一個全局列表來索引所有PCI 設備,該屬性標志了這個全局列表的首指針。
bus:該屬性標志了當前設備所在的 PCI 總線(對應的數(shù)據(jù)結(jié)構(gòu)是 pci_bus)。
devfn:該屬性標志了設備編號和功能編號。
vendor:該屬性標志了供應商編號。
device:該屬性標志了設備編號。
driver:該屬性標志了設備對應的驅(qū)動代碼(對應的數(shù)據(jù)結(jié)構(gòu)是 pci_driver)。
irq:該屬性標志了中斷號。
resource:該屬性標志了 Memory/IO 地址區(qū)間。
當 Linux 內(nèi)核在做 PCI 初始化工作時,它會根據(jù)建立一個由 pci_controller、pci_bus 和 pci_dev 三者組成的一個組織結(jié)構(gòu)圖。根據(jù)這個結(jié)構(gòu),軟件開發(fā)者可以很方便的通過 PCI 控制器索引到每個 PCI 設備或者 PCI 總線。


 

  十.linux的PCI子系統(tǒng)初始化流程
第一步:Linux分配數(shù)據(jù)結(jié)構(gòu)pci_contoller,并初始化,包括PCI的mem/io空間范圍和訪問PCI配置空間所需的handler。
第二步:PCI設備的枚舉:掃描系統(tǒng)上所有PCI設備,初始化它們的配置空間。(硬件上的初始化)
第三步:用數(shù)據(jù)結(jié)構(gòu)將PCI設備信息聯(lián)系起來,構(gòu)建PCI樹。(軟件上的初始化)
第四步:加載PCI設備驅(qū)動。
1 初始化PCI控制器
pci_controller結(jié)構(gòu)是內(nèi)核描述PCI子系統(tǒng)信息的數(shù)據(jù)結(jié)構(gòu),里面定義了可供PCI設備使用的mem資源和io資源的范圍,訪問pci設備配置空間的handler等等。
函數(shù)調(diào)用關系:

 

  1. start_kernel --> mpc8560ads_setup_arch --> mpc85xx_setup_hose()
  2. 此函數(shù)分配并初始化了pci_controller
  3. mpc85xx_setup_hose()
  4.     -->pcibios_alloc_controller() //分配數(shù)據(jù)結(jié)構(gòu)pci_controller

  5.     ppc_md.pci_map_irq = mpc85xx_map_irq; //用來獲得pci設備irq號的handler

  6.     -->setup_indirect_pci() //設置pci_controller里訪問PCI配置空間的鉤子函數(shù)

  7.                             //使用ioremap后的CFG_ADDR和CFG_DATA的虛擬地址

  8.     -->mpc85xx_setup_pci1() //設置PCI inbound和outbound窗口寄存器。

  9. PCI子系統(tǒng)的mem和io地址空間范圍也在函數(shù)mpc85xx_setup_hose()中定義:
  10.     pci_controller *hose_a;
  11.     hose_a->mem_space.start = MPC85XX_PCI1_LOWER_MEM;
  12.     hose_a->mem_space.end = MPC85XX_PCI1_UPPER_MEM;
  13.     hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO;
  14.     hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO;


2 PCI枚舉過程
目前為止,內(nèi)核只知道PCI子系統(tǒng)總的mem資源和io資源地址范圍。
接下來,內(nèi)核需要掃描所有PCI設備,把這些資源分配給PCI設備,具體方法參考前面講的PCI枚舉過程。
內(nèi)核分配mem資源時是從高地址開始分配的。

 

  1. mpc85xx_setup_hose()
  2.     -->pciauto_bus_scan()
  3.     for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { //遍歷0號總線上所有PCI設備

  4.         if (讀當前設備配置空間PCI_HEADER_TYPE失敗)
  5.             continue; //當前設備不存在,掃描下一個

  6.         讀當前設備配置空間PCI_CLASS_REVISION
  7.         If(當前設備是PCI橋){
  8.             pciauto_setup_bars() //分配pci_controller的資源的子集

  9.             pciauto_prescan_setup_bridge() //寫PCI橋配置空間 PCI_PRIMARY_BUS

  10.                                                 //PCI_SECONDARY_BUS

  11.                                                 //PCI_SUBORDINATE_BUS

  12.             pciauto_bus_scan() //遞歸掃描下一條pci bus

  13.             pciauto_postscan_setup_bridge() //寫PCI橋配置空間PCI_SUBORDINATE_BUS

  14.         }
  15.         。。。。。略去
  16.         else {
  17.             //當前設備是PCI設備

  18.             pciauto_setup_bars()
  19.         }
  20.     }


 

    注意:執(zhí)行完 pciauto_bus_scan后,所有pci設備(包括橋)的配置空間都已經(jīng)傻瓜式的簡單初始化
      但這些橋和設備還沒有通過數(shù)據(jù)結(jié)構(gòu)組織起來,這些工作要在第四步 pcibios_init里來完成
3 創(chuàng)建PCI樹
上面說了,PCI設備配置空間都初始化差不多了,但是PCI設備還沒有通過數(shù)據(jù)結(jié)構(gòu)組織起來。   

 

  1. do_initcalls()
  2.   -->pcibios_init() //所在文件 arch/ppc/kernel/pci.c

  3. pcibios_init()
  4.     (1):為PCI設備構(gòu)造數(shù)據(jù)結(jié)構(gòu),組織成PCI樹

  5. ->pci_scan_bus(hose->first_busno,hose->ops,hose)//hose就是上面的pci_controller結(jié)構(gòu)


  6.  -->pci_scan_bus_parented

  7.    -->pci_create_bus // 建立 PCI bus 0 對應的數(shù)據(jù)結(jié)構(gòu),這個bus的資源尚未初始化

  8.  -->pci_scan_child_bus // 從PCI bus 0 開始掃描生成PCI樹,使用了遞歸


  9.      -->pci_scan_slot

  10.       -->pci_scan_single_dev
  11.     -->pci_scan_device() //創(chuàng)建 pci_dev結(jié)構(gòu)

  12.      -->pci_setup_device() //區(qū)分橋與設備,分別進行初始化

  13.       -->pci_read_bases();


 

pci_dev->resouce[]中保存的才是cpu internal address(EA),可以對這些地址進行用ioremap,在驅(qū)動程序?qū)ar所指位置讀寫的時候一定要用這       
    (2)給PCI設備分配IRQ號

 

  1. -->pci_fixup_irqs()
  2.         //遍歷所有pci設備,調(diào)用pdev_fixup_irq()

  3.    -->pdev_fixup_irq
  4.        -->ppc_md.pci_swizzle() //實際調(diào)用common_swizzle(),獲得pci所在slot編號

  5. 讀PCI設備配置空間PCI_INTERRUPT_PIN,獲得中斷pin編號[1到4]

  6.     之所以是1到4,因為PCI規(guī)范里設備最多4個管腳(除第一個外,其他3個僅用于多功能設備)
  7.        -->ppc_md.pci_map_irq() //實際調(diào)用mpc85xx_map_irq()

  8.                                     //根據(jù)slot,pin 和 pci_irq_table[][4]

  9.                                     //來計算出irq號

  10.        -->pcibios_update_irq(pci_dev,irq)
  11.         //將irq號寫入pci設備的配置空間PCI_INTERRUPT_LINE

  12.         //注意,這里寄存器只是用來保存結(jié)果,例如把其值8改為9,并不能改變中斷號

  13.     (3)PCI結(jié)構(gòu)樹有了,現(xiàn)在構(gòu)建PCI的資源樹,有沖突就修改
  14.     -->pcibios_allocate_bus_resource()
  15.         //只考慮pci_bus,形成bus級資源樹(并同時check,資源沖突了就修改)

  16.     -->pcibios_allocate_resources()
  17.         


 

4 加載PCI設備驅(qū)動
以e1000 PCI 網(wǎng)卡 82546GB為例,講解一個PCI驅(qū)動的加載過程
驅(qū)動里有如下代碼:

 

  1. static struct pci_driver e1000_driver = {
  2.     .name = e1000_driver_name,
  3.     .id_table = e1000_pci_tbl,
  4.     .probe = e1000_probe,
  5.     .remove = __devexit_p(e1000_remove),
  6. #ifdef CONFIG_PM
  7.     /* Power Managment Hooks */
  8.     .suspend = e1000_suspend,
  9.     .resume = e1000_resume,
  10. #endif
  11.     .shutdown = e1000_shutdown,
  12.     .err_handler = &e1000_err_handler
  13. };
  14. module_init(e1000_init_module);
  15. do_initcalls()
  16.     -->e1000_init_module
  17.         pci_register_driver(&e1000_driver)
  18.         // e1000_driver.driver.bus = &pci_bus_type;

  19.     -->driver_register(e1000_driver.driver);
  20.     //pci_bus_type.probe() 非空,即調(diào)用pci_device_probe()

  21. pci_device_probe(*device)
  22.     -->__pci_device_probe(*pci_driver,*pci_dev)
  23.         -->pci_match_device(*pci_driver,*pci_dev)
  24.         -->pci_call_probe(*pci_driver,*pci_dev,pci_device_id)
  25.             -->drv->probe(*pci_device,*pci_device_id)
  26.             即執(zhí)行 e1000_probe(*pci_device,*pci_device_id)


接下來就是e1000 PCI 網(wǎng)卡驅(qū)動的具體代碼

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多