Linux下PCIe子系統(二)——PCIe子系統框架詳解

Linux下PCIe子系統(二)——PCIe子系統框架詳解

1. 概述

PCIe(PCI Express)子系統是Linux內核中負責管理PCI/PCIe設備的核心組件。它提供了一套完整的框架來發現、配置和管理PCI設備,實現了設備的即插即用和熱插拔功能。

2. 核心數據結構

PCIe子系統使用以下核心數據結構來組織和管理設備:
在這里插入圖片描述

2.1 主要數據結構

結構體描述作用
struct pci_host_bridgeHost Bridge表示PCI域的根管理器,連接CPU和PCI總線
struct pci_busPCI總線表示代表一條PCI總線,可以掛載多個設備
struct pci_devPCI設備表示代表具體的PCI設備實例

2.2 數據結構關系

┌─────────────────────┐
│   pci_host_bridge   │ ← Host Bridge (根管理器)
└──────────┬──────────┘│▼
┌─────────────────────┐
│      pci_bus        │ ← PCI總線 (Bus 0)
│     (Root Bus)      │
└──────────┬──────────┘│▼
┌─────────────────────┐
│      pci_dev        │ ← PCI設備
│   (PCI設備/橋設備)   │
└─────────────────────┘

3. 驅動框架基礎

3.1 設備分類

Linux設備驅動將設備分為三大類:

  • 字符設備 - 順序訪問的設備(如串口、鍵盤)
  • 塊設備 - 隨機訪問的設備(如硬盤、U盤)
  • 網絡設備 - 網絡通信設備(如網卡)

3.2 字符設備注冊流程

PCI設備通常以字符設備的形式加載到內核中,其注冊流程包括:

  1. 注冊設備號 - 獲取主設備號和次設備號
  2. 創建并初始化cdev結構體 - 綁定file_operations
  3. 添加字符設備 - 將設備添加到內核
  4. 創建設備文件 - 在/dev下創建設備節點
  5. 實現file_operations - 實現設備操作函數集

注意: 學習PCIe子系統的目的是為專門的PCI設備開發對應的驅動程序。

4. PCI子系統實現流程

4.1 整體流程概覽

內核啟動
各子系統初始化
PCI子系統初始化
創建PCI總線結構
設備枚舉
掃描PCI設備并創建設備對象
驅動加載
PCI驅動注冊并匹配設備

4.2 時間線

啟動時間線:
0ms     內核啟動開始
2ms     pci_driver_init() - PCI總線類型注冊
5ms     pcibios_init() - 架構相關初始化及設備枚舉
8ms     pci_subsys_init() - PCI子系統完善
15ms    device_initcall() - 設備驅動匹配
20ms    用戶空間啟動

5. PCI子系統實現細節

5.1 PCI子系統初始化

5.1.1 pci_driver_init()函數

PCI子系統初始化通過pci_driver_init()函數實現,在內核中創建PCI總線(軟件抽象):

static int __init pci_driver_init(void)
{int ret;// 注冊PCI總線類型到設備模型ret = bus_register(&pci_bus_type);if(ret)return ret;// 添加DMA調試支持dma_debug_add_bus(&pci_bus_type);return 0;
}
5.1.2 關鍵功能
  • 總線注冊: 調用bus_register(&pci_bus_type)(所有總線都通過此函數注冊)
  • 設備模型集成: 將全局pci_bus_type結構體注冊到內核設備模型
  • sysfs接口: 在/sys/bus/下創建pci目錄,包含devicesdrivers子目錄

5.2 設備枚舉機制

5.2.1 枚舉 vs 設備樹

傳統設備樹方式

  • 在設備樹中描述硬件信息
  • 通過compatible屬性與驅動的of_match_table匹配
  • 靜態配置,啟動時解析一次

PCIe枚舉方式

  • 動態發現設備
  • 支持即插即用和熱插拔
  • 運行時設備管理

枚舉定義: 在計算機硬件領域是指系統性地發現、識別和配置硬件設備的過程。

5.2.2 為什么PCIe使用枚舉

使用設備樹會破壞PCIe設備的核心優勢:

  • ? 即插即用 - 新設備無法自動識別
  • ? 熱插拔 - 運行時插拔設備無法處理
  • ? 標準化 - 失去PCI協議的標準化優勢
5.2.3 PCIe設備枚舉詳細流程

階段一:基礎設施建設

pci_driver_init() → 注冊PCI總線類型
pcibios_init() → 平臺特定PCI配置  
pci_subsys_init() → 啟動完整枚舉流程

在這里插入圖片描述

階段二:Host Bridge注冊和Root Bus創建

pci_scan_root_bus_bridge()
├── pci_register_host_bridge()    // 注冊Host Bridge
│   ├── 創建Root Bus (Bus 0)
│   ├── 分配地址空間資源
│   │   ├── 內存窗口
│   │   └── I/O端口窗口
│   └── 注冊到Linux設備模型
└── pci_scan_child_bus()          // 開始設備掃描

階段三:遞歸設備掃描

核心掃描工作由pci_scan_child_bus_extend()完成,采用深度優先遞歸算法

pci_scan_child_bus_extend(bus, available_buses)
├── 第一階段:設備掃描
│   └── for (devfn = 0; devfn < 0x100; devfn += 8) {  // 32設備×8功能
│       ├── pci_scan_slot(bus, devfn)
│       ├── pci_scan_single_device()
│       ├── pci_scan_device()      // 讀取配置空間
│       └── pci_device_add()       // 添加到系統}
├── 第二階段:橋設備處理
│   └── for_each_pci_bridge(dev, bus) {
│       ├── pci_add_new_bus()      // 創建子總線
│       ├── 分配下級總線號
│       └── pci_scan_child_bus_extend(child_bus)  // 遞歸!}
└── 第三階段:資源分配├── pci_bus_size_bridges()     // 計算橋設備資源需求└── pci_bus_assign_resources() // 分配實際資源
5.2.4 設備發現機制

設備存在檢測

// 讀取vendor ID判斷設備是否存在
pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendor_id);if (vendor_id == 0xffffffff || vendor_id == 0x00000000) {// 設備不存在return NULL;
}

配置空間信息讀取

struct pci_dev *dev = pci_alloc_dev(bus);
dev->vendor = vendor_id & 0xffff;
dev->device = (vendor_id >> 16) & 0xffff;// 讀取其他重要信息
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
// 讀取BAR寄存器等...
5.2.5 遞歸掃描示例
掃描Root Bus 0:├── 00:00.0 - Host Bridge├── 00:01.0 - PCIe Root Port (橋設備)│   └── 創建Bus 1 → 遞歸掃描│       └── 01:00.0 - 顯卡├── 00:02.0 - 集成顯卡├── 00:1c.0 - PCIe Root Port (橋設備)  │   └── 創建Bus 2 → 遞歸掃描│       └── 02:00.0 - 網卡└── 00:1f.0 - ISA橋└── 創建Bus 3 → 遞歸掃描

6. 設備驅動匹配機制

6.1 關鍵函數

PCIe設備與驅動的匹配依賴兩個核心函數:

6.1.1 pci_bus_match()

功能:設備驅動匹配函數

static int pci_bus_match(struct device *dev, struct device_driver *drv)
{struct pci_dev *pci_dev = to_pci_dev(dev);struct pci_driver *pci_drv = to_pci_driver(drv);const struct pci_device_id *found_id;// 遍歷驅動的設備ID表進行匹配found_id = pci_match_device(pci_drv, pci_dev);if (found_id)return 1;  // 匹配成功return 0;      // 匹配失敗
}

匹配條件

  • Vendor ID: 廠商標識(由PCI-SIG分配)
  • Device ID: 設備標識(廠商自定義)
  • Subsystem Vendor ID: 子系統廠商ID(可選)
  • Subsystem Device ID: 子系統設備ID(可選)
  • Class Code: 設備類別(可選)

特殊值

  • 驅動中設置PCI_ANY_ID可匹配所有對應字段
6.1.2 pci_bus_probe()

功能:設備探測函數

static int pci_device_probe(struct device *dev)
{struct pci_dev *pci_dev = to_pci_dev(dev);struct pci_driver *drv = to_pci_driver(dev->driver);const struct pci_device_id *id;id = pci_match_device(drv, pci_dev);if (!id)return -ENODEV;// 調用驅動的probe函數return drv->probe(pci_dev, id);
}

6.2 匹配流程

匹配成功
匹配失敗
設備/驅動注冊
pci_bus_match調用
比對vendor/device信息
pci_bus_probe調用
嘗試下一個驅動
pci_device_probe執行
調用驅動probe函數
設備驅動綁定完成
匹配失敗

6.3 vendor和device信息

存儲位置

  • PCI配置空間: 偏移0x00(Vendor ID)和0x02(Device ID)
  • 硬件固化: 設備制造時寫入,無法修改

獲取方式

# 使用lspci查看設備信息
lspci -nn
# 輸出示例:
# 00:02.0 VGA compatible controller [0300]: Intel Corporation Device [8086:9bc4]
#                                                     ^^^^  ^^^^
#                                                   vendor device

驅動中的使用

static const struct pci_device_id my_pci_ids[] = {{ PCI_DEVICE(0x8086, 0x1234) },  // Intel的某個設備{ PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) }, // 支持所有設備  { 0, }  // 結束標記
};
MODULE_DEVICE_TABLE(pci, my_pci_ids);

7. PCIe Host設備創建(設備樹方式)

7.1 PCIe Host Controller的特殊性

雖然PCIe設備通過枚舉發現,但PCIe Host Controller本身需要通過設備樹描述:

  • Host Controller: Platform設備,通過設備樹描述
  • PCI設備: 通過Host Controller枚舉發現

7.2 設備樹到Platform設備流程

7.2.1 設備樹編譯和加載
DTS源文件 → DTC編譯器 → DTB二進制文件 → Bootloader加載到內存
7.2.2 DTS文件示例
pcie: pcie@f0000000 {compatible = "samsung,exynos5440-pcie";reg = <0xf0000000 0x1000>, <0xf0001000 0x1000>;interrupts = <0 5 0>, <0 4 0>;ranges = <0x81000000 0 0x60000000 0x60000000 0 0x00010000   /* I/O */0x82000000 0 0x60010000 0x60010000 0 0x0FFF0000>; /* Memory */#address-cells = <3>;#size-cells = <2>;device_type = "pci";
};
7.2.3 內核解析流程
start_kernel()└── setup_arch()└── unflatten_device_tree()              // 展開設備樹└── __unflatten_device_tree()└── populate_node()              // 創建device_node結構
7.2.4 Platform設備創建
// 在core_initcall階段
of_platform_default_populate_init()└── of_platform_default_populate()└── of_platform_bus_create()└── of_platform_device_create_pdata() // 創建platform_device

7.3 時間線對比

啟動時間線:
0ms     bootloader加載DTB到內存
2ms     unflatten_device_tree() - 解析成device_node  
5ms     pci_driver_init() - PCI子系統初始化
10ms    of_platform_default_populate() - 創建platform_device
12ms    PCIe Host Controller驅動匹配和probe
15ms    pci_scan_root_bus_bridge() - 開始PCI設備枚舉
20ms    PCI設備驅動匹配

8. 枚舉過程關鍵特點

8.1 技術特性

  • 自動發現性: 利用PCI協議的自描述特性,無需外部配置
  • 層次化管理: 通過總線-橋-設備的樹狀結構組織
  • 資源協調: 統一管理地址空間分配,避免資源沖突
  • 熱插拔支持: 為運行時設備插拔提供基礎架構

8.2 掃描算法特點

  • 廣度優先: 同級設備并行掃描
  • 深度遞歸: 發現橋設備時遞歸掃描下級總線
  • 資源預留: 為橋設備預留足夠的地址空間
  • 錯誤處理: 優雅處理配置空間讀取失敗等異常

8.3 與其他總線對比

特性PCIe設備設備樹設備
設備發現硬件自動枚舉軟件解析設備樹
設備信息配置空間自描述設備樹人工描述
匹配依據vendor/device IDcompatible字符串
熱插拔天然支持通常不支持
標準化完全標準化需要自定義

9. 總結

9.1 PCIe子系統優勢

PCIe子系統通過精心設計的層次化架構,實現了從硬件發現到驅動匹配的完整流程:

  1. 自動化設備發現: 通過枚舉機制自動發現設備
  2. 標準化管理: 統一的數據結構和接口
  3. 即插即用支持: 支持熱插拔和動態配置
  4. 層次化設計: 清晰的Host Bridge → Bus → Device架構
  5. 資源管理: 智能的地址空間分配和管理

9.2 關鍵技術點

  • 遞歸掃描算法: 深度優先遍歷整個PCI設備樹
  • 配置空間標準: 標準化的設備信息獲取方式
  • 雙重機制: Host Controller用設備樹,PCI設備用枚舉
  • 設備驅動分離: 清晰的設備發現和驅動匹配分離

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/90463.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/90463.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/90463.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[特殊字符] LLM(大型語言模型):智能時代的語言引擎與通用推理基座

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 從千億參數到人類認知的AI革命 &#x1f50d; 一、核心定義與核心特征…

18-C#改變形參內容

C#改變形參內容 1.ref 參數 int A100; add1(ref A) public int add1 (ref int x) {x x 10;return x; }2.out 參數 int A100; int B200; int Z; add3(A,B, out Z) public int add3 (int x&#xff0c;int y&#xff0c;int z) {z x y;return z; }

恒盾C#混淆加密大師最新版本1.4.0更新 - 增強各類加密效果, 提升兼容性, 使.NET加密更簡單

C#/.NET作為托管語言, 其編譯生成的EXE/DLL極易被反編譯工具還原源碼。據統計&#xff0c;大量的商業軟件曾遭遇過代碼逆向風險&#xff0c;導致核心算法泄露、授權被跳過. 因此對于C#語言開發的.NET程序來說, 在發布前進行混淆和加密非常有必要. 恒盾C#混淆加密大師作為一款.N…

數學建模:非線性規劃:二次規劃問題

一、定義如果規劃模型的目標函數是決策向量的二次函數&#xff0c;約束條件都是線性的&#xff0c;那么這個模型稱為二次規劃&#xff08;QP&#xff09;模型。二次規劃模型的一般形式為二、性質凸性判定準則二次規劃問題的凸性完全由Hessian矩陣H決定&#xff1a;??嚴格凸QP…

4. 那在詳細說一下 http 2.0 的特點

總結 二進制協議&#xff1a;文本通信改為二進制幀通信&#xff0c;數據可以劃分為更小的幀&#xff0c;便于高效解析和傳輸。多路復用&#xff1a;廢除 pipeline 管道&#xff0c;避免了“隊頭阻塞”問題。允許同一個 TCP 連接同時發送多個請求和協議&#xff0c;提高網絡資源…

Qt中遍歷QMap的多種方法及性能分析

Qt中遍歷QMap的多種方法及性能分析遍歷QMap的方法**1、使用迭代器&#xff08;STL風格&#xff09;****2、使用Java風格迭代器****3、使用C11范圍循環****4、使用鍵值分離遍歷**性能分析使用建議遍歷QMap的方法 1、使用迭代器&#xff08;STL風格&#xff09; QMap<QStrin…

Unity3D物理引擎性能優化策略

前言 在Unity3D中優化物理引擎性能&#xff0c;尤其是處理3D碰撞器與2D碰撞器的映射問題&#xff0c;需要結合系統特性和最佳實踐。以下是關鍵策略和實現方案&#xff1a; 對惹&#xff0c;這里有一個游戲開發交流小組&#xff0c;希望大家可以點擊進來一起交流一下開發經驗呀…

集群與集群應用

負載均衡與高可用綜合實驗一、集群是什么&#xff1f;是有一組獨立的計算機系統構成的一個松耦合的多處理系統&#xff0c;作為一個整體向用戶提供一組網絡資源&#xff0c;這些單個的計算機就是集群的節點。二、集群類型Load Balance cluster&#xff08;負載均衡集群&#xf…

jmm,`as - if - serial` 與 `happens - before` 原則

在Java并發編程中&#xff0c;as - if - serial 與 happens - before 原則是確保程序在多線程環境下正確執行的重要規則&#xff0c;下面為你詳細講解&#xff1a; as - if - serial原則 定義&#xff1a;as - if - serial 原則是指&#xff0c;不管編譯器和處理器如何優化&…

主流大模型Agent框架 AutoGPT詳解

注&#xff1a;此文章內容均節選自充電了么創始人&#xff0c;CEO兼CTO陳敬雷老師的新書《GPT多模態大模型與AI Agent智能體》&#xff08;跟我一起學人工智能&#xff09;【陳敬雷編著】【清華大學出版社】 GPT多模態大模型與AI Agent智能體書籍本章配套視頻課程【陳敬雷】 文…

kotlin學習,val使用get()的問題

疑問&#xff1a;定義val怎么還能使用get()代碼示例&#xff1a;private val nametype:Intget()Business.carInfo?.let{carSc(it)}?:LType.AS回答&#xff1a;Kotlin 允許為屬性定義自定義 getter&#xff0c;每次訪問屬性時會執行該方法疑問&#xff1a;這里引出另一個不解&…

解決el-select數據類型相同但是顯示數字的問題

這個不是我寫的&#xff0c;只是遇到的bug&#xff0c;寫法問題&#xff0c;忽略了值的綁定的問題源代碼bug&#xff1a;<el-selectv-model"schemeInfo.horizon"placeholder"請選擇起報月份"clearablefilterable><el-option v-for"(option,i…

熟練掌握RabbitMQ和Kafka的使用及相關應用場景。異步通知與解耦,流量削峰,配合本地消息表實現事務的最終一致性并解決消息可靠、順序消費和錯誤重試等問題

RabbitMQstock.#.nyse &#xff0c;#匹配多個字符&#xff0c;*匹配一個字符。 Confirm Callback 到達exchange的回調。 Return Callback 到達queue失敗的回調。 Kafka Kafka生產端分區器&#xff1a; 1.直接指定partition 指定0,1。 2.設置hashkey&#xff0c;計算key的hash值…

飛算科技:以原創技術賦能數字轉型

在數字科技迅猛發展的浪潮中&#xff0c;飛算數智科技&#xff08;深圳&#xff09;有限公司&#xff08;簡稱 “飛算科技”&#xff09;作為一家自主創新型的數字科技公司&#xff0c;同時也是國家級高新技術企業&#xff0c;正以扎實的技術實力和豐富的實踐經驗&#xff0c;在…

基于 Rust 的Actix Web 框架的應用與優化實例

基于 Rust 的Actix Web 框架的應用與優化實例 Actix Web 框架概述 Actix Web 是一個基于 Rust 的高性能、輕量級 Web 框架,構建于 Actix 異步運行時之上。它支持異步編程模型,適合構建高并發、低延遲的 Web 服務和 API。 核心特性 異步支持:基于 async/await 語法,充分利…

springMVC01-特點、創建項目、@RequestMapping、獲取參數請求,三種域對象

一、簡介 SpringMVC 就是 Spring 框架中的 MVC 模塊&#xff0c;用于構建 Web 應用中的“控制層”。 SpringMVC 是 Spring 提供的一個基于 Servlet 的 Web MVC 框架模塊&#xff0c;是 Spring 整個體系中的“Web 層核心”。 SpringMVC 是 Spring 的一部分&#xff0c;Spring…

Java基礎,反射破壞封裝性 - 單例模式的崩塌

目錄一、容易出現問題的小李代碼小李的單例設計看似完美&#xff0c;實則存在三個致命問題&#xff1a;1、反射攻擊的天然漏洞2、序列化的隱患3、性能瓶頸二、隔壁老王的優化方案三、為什么這樣優化&#xff1f;四、小結周五下午&#xff0c;代碼審查會議上&#xff0c;小李自信…

Neo4j 綜合練習作業

Neo4j 綜合練習作業 作業說明 這個作業涵蓋了 Neo4j 的多個重要知識點&#xff0c;包括節點和關系的創建、查詢、更新、刪除以及高級查詢功能。請使用 Cypher 語句完成以下所有題目。 數據準備 首先執行以下語句創建示例數據&#xff1a; ACTED_IN: 表示出演關系 DIRECTED: 表示…

基于PA算法的FTL引導

一、抽象綁定關系 1. 什么是 AF Block,什么是 NF Block,為什么要將多個 NF Block 綁定為一個 AF Block AF Block(Allocation Flash Block) 和 NF Block(NAND Flash Block) 是在 NAND Flash 存儲架構中用于管理數據的基本單位。 AF Block 定義:AF Block 是一組多個 NF…

快速入門Java中的IO操作

以下是 Java 中常用的 IO 知識點總結&#xff1a; 1. 流的分類 按數據流向&#xff1a;輸入流&#xff08;讀取數據&#xff09;和輸出流&#xff08;寫入數據&#xff09;。按數據類型&#xff1a;字節流&#xff08;處理二進制數據&#xff0c;以字節為單位&#xff09;和字符…