精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux PCI驅動到底都干了些什么?(二)

Linux閱碼場 ? 來源:Linuxer ? 2020-04-30 15:45 ? 次閱讀

緊接著前文:Linux PCI驅動到底都干了些什么?(一)

我們在淺談Linux PCI設備驅動(一)中(以下簡稱 淺談(一) )介紹了PCI的配置寄存器組,而Linux PCI初始化就是使用了這些寄存器來進行的。后面我們會舉個例子來說明Linux PCI設備驅動的主要工作內容(不是全部內容),這里只做文字性的介紹而不會涉及具體代碼的分析,因為要分析代碼的話,基本就是對 Linux內核源代碼情景分析(下冊)第八章的解讀,讀者若想分析代碼,可以參考該書的內容,我們這里就不去深入分析這些代碼了。

Linux PCI設備驅動代碼必須掃描系統中所有的PCI總線,尋找系統中所有的PCI設備(包括PCI-PCI橋設備)。系統中的每條PCI總線都有個編號number,根PCI總線的編號為0。系統當前存在的所有根總線(因為可能存在不止一個Host/PCI橋,那么就可能存在多條根總線) 都通過其pci_bus結構體中的node成員鏈接成一個全局的根總線鏈表,其表頭由struct list_head類型的全局變量pci_root_buses來描述,我們在/linux-2.4.18/linux/drivers/pci/pci.c的38行可以看到如下定義:

LIST_HEAD(pci_root_buses);

而根總線下面的所有下級總線則都通過其pci_bus結構體中的node成員鏈接到其父總線的children鏈表中。這樣,通過這兩種PCI總線鏈表,Linux內核就將所有的pci_bus結構體以一種倒置樹的方式組織起來。

另外,每個PCI設備都由一個pci_dev結構體表示,每個pci_dev結構體都同時連入兩個隊列,一方面通過其成員global_list掛入一個總的pci_dev結構隊列(隊列頭是pci_devices);同時又通過成員bus_list掛入其所在總線的pci_dev結構隊列devices(隊列頭是pci_bus.devices,即該pci設備所在的pci總線的devices隊列),并且使指針bus(指pci_dev結構體里的bus成員)指向代表著其所在總線的pci_bus結構。如果具體的設備是PCI-PCI橋,則還要使其指針subordinate指向代表著另一條PCI總線的pci_bus結構。同樣我們在/linux-2.4.18/linux/drivers/pci/pci.c的39行可以看到如下定義:

LIST_HEAD(pci_devices);

對于PCI設備鏈表,我們可以通過圖1來理解。

注:該圖摘自《Linux設備驅動開發詳解》 第21章 PCI設備驅動。

圖1 Linux PCI設備鏈表

而對于我們在淺談(一)中貼出的圖1的PCI系統結構示意圖,Linux內核中對應的數據結構如這里的圖2所示。

圖2 Linux內核PCI數據結構

Linux PCI初始化代碼從PCI總線0開始掃描,它通過讀取"Vendor ID"和"Device ID"來試圖發現每一個插槽上的設備。如果發現了一個PCI-PCI橋,則創建一個pci_bus數據結構并且連入到由pci_root_buses指向的pci_bus和pci_dev數據結構組成的樹中。PCI初始化代碼通過設備類代碼0x060400來判斷一個PCI設備是否是PCI-PCI橋。然后,Linux核心開始構造這個橋設備另一端的PCI總線和其上的設備。如果還發現了橋設備,就以同樣的步驟來進行構建。這個處理過程稱之為深度優先算法。PCI-PCI橋橫跨在兩條總線之間,寄存器PCI_PRIMARY_BUS和PCI_SECONDARY_BUS的內容就說明了其上下兩端的總線號,其中PCI_SECONDARY_BUS就是該PCI-PCI橋所連接和控制的總線,而PCI_SUBORDINATE_BUS則說明自此以下、在以此為根的子樹中最大的總線號是什么。

我們可以在/linux-2.4.18/linux/include/linux/pci.h看到如下定義:

112:/*Headertype1(PCI-to-PCIbridges)*/113:#definePCI_PRIMARY_BUS0x18/*Primarybusnumber*/114:#definePCI_SECONDARY_BUS0x19/*Secondarybusnumber*/115: #define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */

由于在枚舉階段做的是深度優先掃描,所以子樹中的總線號總是連續遞增的。當CPU往I/O寄存器0xCF8中寫入一個綜合地址以后,從0號總線開始,每個PCI-PCI橋會把綜合地址中的總線號與自身的總線號相比,如果相符就用邏輯設備號在本總線上尋訪目標設備;否則就進一步把這個總線號與PCI_SUBORDINATE_BUS中的內容相比,如果目標總線號落在當前子樹范圍中,就把綜合地址傳遞給其下的各個次層PCI-PCI橋,要不然就不予理睬。這樣,最終就會找到目標設備。當然,這個過程只是在PCI設備的配置階段需要這樣做,一旦配置完成,CPU就直接通過有關的總線地址訪問目標設備了。

PCI-PCI橋要想正確傳遞對PCI I/O,PCI Memory或PCI Configuration地址空間的讀和寫請求,必須知道下列信息

(1)Primary Bus Number(主總線號)

該PCI-PCI橋所處的PCI總線稱為主總線。

(2)Secondary Bus Number(子總線號)

該PCI-PCI橋所連接的PCI總線稱為子總線/次總線號。

(3)Subordinate Bus Number

PCI總線的下屬PCI總線的總線編號最大值。有點繞,看后面的分析就明白了。

PCI I/O 和 PCI Memory 窗口

PCI橋的配置寄存器與一般的PCI設備不同。一般PCI設備可以有6個地址區間,外加一個ROM區間,代表著設備上實際存在的存儲器或寄存器區間。而PCI橋,則本身并不一定有存儲器或寄存器區間,但是卻有三個用于地址過濾的區間。每個地址過濾區間決定了一個地址窗口,從CPU一側發出的地址,如果落在PCI橋的某個窗口內,就可以穿過PCI橋而到達其所連接的總線上。此外,PCI橋的命令寄存器中還有”memory access enable”和”I/O access enable ”的兩個控制位,當這兩個控制位為0時,這些窗口就全都關上了。在未完成對PCI總線的初始化之前,還沒有為PCI設備上的各個區間分配合適的總線地址時,正是因為這兩個控制位為0,才不會對CPU一側造成干擾。例如, 對于淺談(一)的 PCI系統示意圖 ,僅當讀和寫請求中的PCI I/O或PCI memory地址屬于SCSIEthernet設備時,PCI-PCI橋才將這些總線上的請求從PCI總線0傳遞到PCI總線1。這種過濾機制可以避免地址在系統中沒必要的繁衍。為了做到這點,每個PCI-PCI橋必須正確地被設置好它所負責的PCI I/O或PCI memory的起始地址和大小。當一個讀或寫請求地址落在其負責的范圍之內,這個請求將被映射到次級的PCI總線上。系統中的PCI-PCI橋一旦設置完畢,如果Linux中的設備驅動程序存取的PCI I/O和PCI memory地址落在在這些窗口之內,那么這些PCI-PCI橋就是透明的。這是個很重要的特性,使得Linux PCI設備驅動程序開發者的工作容易些。

問題是配置一個PCI-PCI橋的時候,并不知道這個PCI-PCI橋的subordinate bus number。那么就不知道該PCI橋下面是否還有其他的PCI-PCI橋。即使你知道,也不清楚如何對它們賦值。解決方法是利用上述的深度掃描算法來掃描每個總線。每當發現PCI-PCI橋就對它進行賦值。當發現一個PCI-PCI橋時,可以確定它的secondary bus number。然后我們暫時先將其subordinate bus number賦值為0xFF。緊接著,開始掃描該PCI-PCI橋的downstream橋。這個過程看起來有點復雜,下面的例子將給出清晰的解釋:

圖3 配置PCI系統 第一步

PCI-PCI橋編號--第一步

以圖3的拓撲結構為例,掃描時首先發現的橋是Bridge1。Bridge 1的downstream PCI總線號碼被賦值1。自然該橋的secondary bus number也是1。其subordinate bus number暫時賦值為0xFF。上述賦值的含義是所有類型1的含有PCI總線1或更高(<255)的號碼的PCI配置地址將被Bridge 1傳遞到PCI總線1上。如果PCI總線號是1,Bridge 1 還負責將配置地址的類型轉換成類型0(對于這里說的類型0和類型1,請參考淺談(一))。否則,就不做轉換。上述動作就是開始掃描總線1時Linux PCI初始化代碼所完成的對總線0的配置工作。

圖4 配置PCI系統 第二步

PCI-PCI橋編號--第二步

由于Linux PCI設備驅動使用深度優先算法進行掃描,所以初始化代碼開始掃描總線1。從而Bridge 2被發現。因為在Bridge 2下面發現不再有PCI-PCI橋,所以Bridge 2的subordinate bus number是2,等于它的secondary bus number。圖4顯示了在這個時刻總線和PCI-PCI橋的賦值情況。

圖5 配置PCI系統 第三步

PCI-PCI橋編號--第三步

Linux PCI設備驅動代碼從總線2的掃描中回來接著進行掃描總線1,發現Bridge 3。它的primary bus number被賦值為1,secondary bus number為3。因為總線3上還發現了PCI-PCI橋,所以Bridge 3的subordinate bus number暫時賦值0xFF。圖5顯示了這個時刻系統配置的狀態。到目前為止,含有總線號1,2,3的類型1的PCI配置都可以正確地傳送到相應的總線上。

圖6 配置PCI系統 第四步

PCI-PCI橋編號--第四步

現在Linux開始掃描PCI總線3,Bridge 3的downstream。PCI總線3上有另外一個PCI-PCI橋,Bridge 4。因此Bridge 4的primary bus number的值為3,secondary bus number為4。由于Bridge 4下面沒有別的橋設備,所以Bridge 4的subordinate bus number為4。然后回到PCI-PCI Bridge 3。這時就將Bridge 3的subordinate bus number從0xFF改為4,表示總線4是從Bridge 3往下走的最遠的PCI-PCI橋。最后,Linux PCI設備驅動代碼將4以同樣的道理賦值給Bridge 1的subordinate bus number。圖6反映了系統最后的狀態。

注:淺談Linux PCI設備驅動(二)暫時的整體結構就是這樣了,后續可能還會有些細節上的修補和添加。在此強烈推薦想學Linux PCI設備驅動的朋友結合《Linux內核源代碼情景分析下冊》第八章和《Linux設備驅動開發詳解》第21章 來學習。感謝您關注本文。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 寄存器
    +關注

    關注

    31

    文章

    5325

    瀏覽量

    120044
  • 總線
    +關注

    關注

    10

    文章

    2869

    瀏覽量

    87995
  • PCI設備
    +關注

    關注

    0

    文章

    9

    瀏覽量

    8125

原文標題:PCI設備驅動(二)

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    RTOS與Linux到底有什么區別

    很多做嵌入式開發的小伙伴存在這樣的疑惑:RTOS與Linux到底有什么區別?
    的頭像 發表于 10-29 09:53 ?331次閱讀

    pci內存控制器感嘆號有影響嗎

    PCI內存控制器感嘆號通常表示硬件設備存在一問題,這可能會對您的計算機性能產生影響。以下是一可能的原因和解決方法: 驅動程序問題:感嘆號可能表示
    的頭像 發表于 10-10 16:56 ?1794次閱讀

    LSP 2.10 DaVinci Linux驅動程序

    電子發燒友網站提供《LSP 2.10 DaVinci Linux驅動程序.pdf》資料免費下載
    發表于 10-09 09:30 ?0次下載
    LSP 2.10 DaVinci <b class='flag-5'>Linux</b><b class='flag-5'>驅動</b>程序

    linux系統的設備驅動一般分幾類

    Linux系統的設備驅動是操作系統與硬件設備之間的橋梁,負責實現操作系統與硬件設備之間的通信和控制。Linux系統的設備驅動可以分為以下幾類: 字符設備
    的頭像 發表于 08-30 15:13 ?350次閱讀

    Linux設備驅動程序分類有哪些

    Linux設備驅動程序是操作系統與硬件設備之間的橋梁,負責實現硬件設備與操作系統之間的通信和控制。Linux設備驅動程序的分類繁多,可以根據不同的標準進行分類。 按硬件類型分類
    的頭像 發表于 08-30 15:11 ?450次閱讀

    linux驅動程序如何加載進內核

    ,需要了解Linux內核的基本概念和API。以下是一關鍵概念: 1.1 內核模塊:Linux內核模塊是一種動態加載和卸載的代碼,可以在不重新啟動系統的情況下加載和卸載。驅動程序通常以
    的頭像 發表于 08-30 15:02 ?386次閱讀

    linux驅動程序主要有哪些功能

    Linux驅動程序是操作系統與硬件設備之間進行通信的橋梁,負責實現硬件設備與操作系統之間的數據交換和控制。Linux驅動程序的主要功能包括以下幾個方面: 設備識別與初始化
    的頭像 發表于 08-30 14:47 ?307次閱讀

    linux驅動程序的編譯方法是什么

    Linux驅動程序的編譯方法主要包括兩種: 與內核一起編譯 和 編譯成獨立的內核模塊 。以下是對這兩種方法的介紹: 一、與內核一起編譯 與內核一起編譯意味著將驅動程序的源代碼直接集成到Linu
    的頭像 發表于 08-30 14:46 ?434次閱讀

    Linux 驅動開發與應用開發,你知道多少?

    一、Linux驅動開發與應用開發的區別開發層次不同:Linux驅動開發主要是針對硬件設備進行編程,處于操作系統內核層,直接與硬件交互,為上層應用提供設備訪問的接口。
    的頭像 發表于 08-30 12:16 ?623次閱讀
    <b class='flag-5'>Linux</b> <b class='flag-5'>驅動</b>開發與應用開發,你知道多少?

    PCI2250 PCIPCI橋數據表

    電子發燒友網站提供《PCI2250 PCIPCI橋數據表.pdf》資料免費下載
    發表于 07-10 09:34 ?0次下載
    <b class='flag-5'>PCI</b>2250 <b class='flag-5'>PCI</b>到<b class='flag-5'>PCI</b>橋數據表

    請問esp32s3怎么添加nt35510驅動到新工程中?

    請問esp32s3怎么添加nt35510驅動到新工程中
    發表于 06-27 06:30

    Nvidia與AMD新芯片,突破PCIe瓶頸

    AMD 和 Nvidia 的 GPU 依賴 PCI 總線與 CPU 進行通信。CPU 和 GPU 有兩個不同的內存域,數據必須通過 PCI 接口從 CPU 域移動到 GPU 域(并返
    的頭像 發表于 03-08 14:15 ?611次閱讀
    Nvidia與AMD新芯片,突破PCIe瓶頸

    RK3568-Linux系統使用手冊(

    RK3568-Linux系統使用手冊(
    的頭像 發表于 01-22 10:48 ?1777次閱讀
    RK3568-<b class='flag-5'>Linux</b>系統使用手冊(<b class='flag-5'>二</b>)

    通過JTAG啟動Linux的方法和腳本

    存儲器(QSPI Flash,eMMC 等)上的鏡像,直接啟動到 Linux。但當板子調試時,經常需要通過 JTAG 把 SoC 器件啟動到 Linux。這篇文章將分享通過 JTAG
    的頭像 發表于 12-22 10:27 ?1403次閱讀
    通過JTAG啟動<b class='flag-5'>Linux</b>的方法和腳本

    linux驅動程序的主要流程和功能

    驅動程序是用于控制和管理硬件設備的軟件模塊,它主要負責與設備進行交互,通過操作設備的寄存器和接口,實現對硬件的控制和訪問。在Linux系統中,驅動程序是實現與硬件設備交互的一個關鍵部分。本文將詳細
    的頭像 發表于 12-08 14:56 ?2267次閱讀