国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux下PCI設(shè)備驅(qū)動開發(fā)詳解(二)

這篇具有很好參考價值的文章主要介紹了Linux下PCI設(shè)備驅(qū)動開發(fā)詳解(二)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Linux下PCI設(shè)備驅(qū)動開發(fā)詳解(二)

根據(jù)上一章的概念,PCI驅(qū)動包括PCI通用的驅(qū)動,以及根據(jù)實際需要設(shè)備本身的驅(qū)動。

所謂的編寫設(shè)備驅(qū)動,其實就是編寫設(shè)備本身驅(qū)動,因為linux內(nèi)核的PCI驅(qū)動是內(nèi)核自帶的。

為了更好的學(xué)習(xí)PCI設(shè)備驅(qū)動,我們需要明白內(nèi)核具體做了什么,下面我們研究一下,linux PCI通用的驅(qū)動到底做了什么?

注:代碼對應(yīng)的 kernel-3.10.1

一、PCI 拓撲架構(gòu)

1.1 PCI的系統(tǒng)拓撲

在分析PCIe初始化枚舉流程之前,先描述下PCIe的拓撲結(jié)構(gòu)。
如下圖所示:

????????linux pcie設(shè)備樹,PCI設(shè)備驅(qū)動開發(fā)詳解,linux,驅(qū)動開發(fā),c語言,fpga開發(fā)

整個PCIe是一個樹形的拓撲:

(1) root complex是樹的根,它一般實現(xiàn)了一個主橋設(shè)備(host bridge),一條內(nèi)部PCIe總線bus0,以及通過若干PCI bridge擴展出一些root port。host bridge可以完成CPU地址總線到PCI域地址的轉(zhuǎn)換,pci bridge用于系統(tǒng)擴展,沒有地址轉(zhuǎn)換功能;

(2) switch是轉(zhuǎn)換設(shè)備,目的是擴展PCIe總線。switch中有一個upstream port和若干個downstream port,每個端口相當于一個pci bridge;

(3) PCIe EP device是葉子節(jié)點設(shè)備,比如PCIe網(wǎng)卡,顯卡。NVMe卡等;

1.2 PCIe的軟件框架

PCIe模塊涉及到的代碼文件很多,在分析PCIe的代碼前,先對PCIe涉及的代碼梳理如下:
這里以arm架構(gòu)為例,PCIe代碼主要分散在3個目錄:

drivers/pci/*
drivers/acpi/pci/*
arch/arm/match-xxx/pci.c

將PCIe代碼按照如下層次劃分:

linux pcie設(shè)備樹,PCI設(shè)備驅(qū)動開發(fā)詳解,linux,驅(qū)動開發(fā),c語言,fpga開發(fā)

arch PCIe driver:放一些和架構(gòu)強相關(guān)的PCIe的函數(shù)實現(xiàn),對應(yīng)arch/arm/xxx/pci.c

acpi PCIe driver: acpi掃描時所涉及的PCIe代碼,包括host bridge的解析初始化,PCIe bus的創(chuàng)建,ecam的映射等,對應(yīng)drivers/acpi/pci*.c

PCIe core driver:PCIe的子系統(tǒng)代碼,包括PCIe的枚舉流程,資源分配流程,中斷流程等,主要對應(yīng)drivers/pci/*.c

PCIe port bus driver:PCIe port的四個service代碼的整合,四個service主要是指PCIe dpc/pme/aer/hp,對應(yīng)drivers/pci/pcie/*

PCIe ep driver:葉子節(jié)點的設(shè)備驅(qū)動,比如顯卡、網(wǎng)卡、NVMe;

二、Linux內(nèi)核實現(xiàn)

PCIe的代碼文件這么多,初始化涉及的調(diào)用也很多,從哪里開始看呢?

1. PCIe初始化流程

內(nèi)核通過initcore的level決定模塊的啟動順序:

cat System.map |grep pci|grep initcall

可以看出關(guān)鍵symbol的調(diào)用順序如下:

linux pcie設(shè)備樹,PCI設(shè)備驅(qū)動開發(fā)詳解,linux,驅(qū)動開發(fā),c語言,fpga開發(fā)

pcibus_class_init:注冊pci_bus_class,完成后創(chuàng)建了/sys/class/pci_bus目錄;

pci_driver_init:注冊pci_bus_type,完成后創(chuàng)建了/sys/bus/pci目錄;

acpi_pci_init:注冊acpi_pci_bus,并設(shè)置電源管理相應(yīng)的操作;

acpi_init():acpi啟動所涉及到的初始化流程,PCIe基于acpi的啟動流程從該接口進入;

下面對acpi_init()流程展開,主要找和PCI初始化相關(guān)的調(diào)用:

static int __init acpi_init(void)
{
    ...
    pci_mmcfg_late_init();
    acpi_scan_init();
        ...
        acpi_pci_root_init();
            ...
            static struct acpi_scan_handler pci_root_handler = {
                .ids = root_device_ids,
                .attach = acpi_pci_root_add,
                .detach = acpi_pci_root_remove,
            }
	    acpi_pci_link_init();
	    acpi_platform_init();
	    acpi_lpss_init();
	    acpi_container_init();
	    acpi_memory_hotplug_init();
	    acpi_dock_init();
        ...
    acpi_ec_init();
    acpi_debugfs_init();
    acpi_sleep_proc_init();
    acpi_wakeup_device_init();
    ...
}

mmcfg_late_init():acpi先掃描MCFG表,MCFG表定義了ecam的相關(guān)資源;

acpi_pci_root_init():定義pcie host bridge device的attach函數(shù),ACPI的definition block中使用PNP0A03表示一個PCI host bridge;

acpi_pci_link_init():注冊pci_link_handler,主要和PCIe IRQ相關(guān);

acpi_bus_scan():會通過acpi_walk_namespace()遍歷system中所有的device,并為這些acpi device創(chuàng)建數(shù)據(jù)結(jié)構(gòu),執(zhí)行對應(yīng)device的attach函數(shù)。根據(jù)ACPI spec定義,PCIe host bridge device定義在DSDT表中,acpi在掃描中掃描DSDT,如果發(fā)現(xiàn)了PCIe host bridge,就會執(zhí)行device對應(yīng)的attach函數(shù),調(diào)用acpi_pci_root_add();

acpi_pci_root_add():

(1)通過ACPI的SEG參數(shù),獲取host bridge使用的segment號,segment指的是PCIe domain,主要目的是為了突破PCIe最大256條bus的限制;

(2)通過ACPI的CRS里的bus range類型資源取得該host bridge的secondary總線范圍,保存在root->secondary這個resource中;

(3)通過ACPI的BNN參數(shù)獲取host bridge的根總線號;
printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
	       acpi_device_name(device), acpi_device_bid(device),
	       root->segment, &root->secondary);

以上流程主要是獲取PCI設(shè)備的bdf號;

1. PCIe枚舉流程

我們先看內(nèi)核代碼:

struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
    struct acpi_device *device = root->device;
    struct pci_root_info *info = NULL;
    int domain = root->segment;
    int busnum = root->secondary.start;
    ...
    if (!setup_mcfg_map(info, domain, (u8)root->secondary.start, 
        (u8)root->secondary.end, root->mcfg_addr)) 
        bus = pci_create_root_bus(NULL,busnum, &pci_root_ops, sd, &resources);
  
    ...
}

這個函數(shù)主要是建立ecam映射,將ecam的空間進行映射,這樣cpu就可以通過內(nèi)存訪問到相應(yīng)設(shè)備的配置空間;

pci_create_root_bus():用來創(chuàng)建該{segment: busnr}下的根總線。傳遞的參數(shù):

NULL:host bridge設(shè)備的parent節(jié)點;

busnum:總線號;

pci_root_ops:配置空間的操作接口;

resource:私有數(shù)據(jù),用來保存總線號,IO空間,mem空間等信息;

以下依次函數(shù)調(diào)用是:

pci_scan_child_bus()
    +-> pci_scan_child_bus_extend()
        +-> for dev range(0, 256)
            pci_scan_slot()
                +-> pci_scan_single_device()
                    +-> pci_scan_device()
                        +-> pci_bus_read_dev_vendor_id()
                        +-> pci_alloc_dev()
                        +-> pci_setip_device()
                    +-> pci_add_device()
            
                +-> for each pci bridge
                    +-> pci_scan_bridge_extend()

更詳細的分析請參見后面的參考資料

總的來說,枚舉流程分為3步:

1.  發(fā)現(xiàn)主橋設(shè)備和根總線
2.  發(fā)現(xiàn)主橋設(shè)備下的所有PCI設(shè)備
3.  如果主橋下面的是PCI bridge,那么再次遍歷這個PCI bridge橋下的所有PCI設(shè)備,依次遞歸,直到將當前PCI總線樹遍歷完畢,返回host bridge的subordinate總線號。

3. PCIe的資源分配

PCIe設(shè)備枚舉完成后,PCI總線號已經(jīng)分配,PCIe ecam的映射、PCIe設(shè)備信息、bar的個數(shù)以及大小等已經(jīng)ready,但是此時并沒有給PCI device的bar、IO、mem分配資源。

這時就需要走到PCIe的資源分配流程,整個資源分配的過程就是從系統(tǒng)的總資源里給每個PCI device的bar分配資源。給每個PCI橋的base、limit的寄存器分配資源。

PCIe的資源分配流程整體比較復(fù)雜,主要介紹下總體的流程,對關(guān)鍵的函數(shù)再做展開。

PCIe資源分配的入口在pci_acpi_scan_root()->pci_bus_assign_resources(),詳細代碼如下:

void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
				      struct list_head *realloc_head,
				      struct list_head *fail_head)
{
	struct pci_bus *b;
	struct pci_dev *dev;

	pbus_assign_resources_sorted(bus, realloc_head, fail_head);

	list_for_each_entry(dev, &bus->devices, bus_list) {
		b = dev->subordinate;
		if (!b)
			continue;

		__pci_bus_assign_resources(b, realloc_head, fail_head);

		switch (dev->class >> 8) {
		case PCI_CLASS_BRIDGE_PCI:
			if (!pci_is_enabled(dev))
				pci_setup_bridge(b);
			break;

		case PCI_CLASS_BRIDGE_CARDBUS:
			pci_setup_cardbus(b);
			break;

		default:
			dev_info(&dev->dev, "not setting up bridge for bus "
				 "%04x:%02x\n", pci_domain_nr(b), b->number);
			break;
		}
	}
}

其中pbus_assign_resources_sorted,這個函數(shù)先對當前總線下設(shè)備請求的資源進行排序。

總而言之,PCIe的資源枚舉過程可以概括為如下:

1. 獲取上游PCI橋設(shè)備所管理的系統(tǒng)資源范圍;
2. 使用DFS對所有的pci ep device進行bar資源的分配;
3. 使用DFS對當前PCI橋設(shè)備的base limit的值,并對這些寄存器更新;

四、總結(jié)

1. 枚舉過程

主要是發(fā)現(xiàn)設(shè)備,主要流程如下:

1.  發(fā)現(xiàn)主橋設(shè)備和根總線
2.  發(fā)現(xiàn)主橋設(shè)備下的所有PCI設(shè)備
3.  如果主橋下面的是PCI bridge,那么再次遍歷這個PCI bridge橋下的所有PCI設(shè)備,依次遞歸,直到將當前PCI總線樹遍歷完畢,返回host bridge的subordinate總線號。

2. 資源分配過程

主要是管理設(shè)備,方便我們使用設(shè)備,主要流程如下:

1. 獲取上游PCI橋設(shè)備所管理的系統(tǒng)資源范圍;
2. 使用DFS對所有的pci ep device進行bar資源的分配;
3. 使用DFS對當前PCI橋設(shè)備的base limit的值,并對這些寄存器更新;

五、未完待續(xù)

Linux下PCI設(shè)備驅(qū)動開發(fā)詳解(三),從內(nèi)核角度來說,一切皆文件,下面從總線、設(shè)備、驅(qū)動的角度,詳細看一下PCI設(shè)備如何變成文件的。

四、參考資料

https://blog.csdn.net/kunkliu/article/details/108950970

<PCI Express Base Specification Revision 5.0, Version 1.0>

https://pcisig.com/文章來源地址http://www.zghlxwxcb.cn/news/detail-803640.html

到了這里,關(guān)于Linux下PCI設(shè)備驅(qū)動開發(fā)詳解(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • Linux驅(qū)動開發(fā):設(shè)備樹dts詳解

    Linux驅(qū)動開發(fā):設(shè)備樹dts詳解

    前言: 掌握設(shè)備樹是 Linux 驅(qū)動開發(fā)人員必備的技能!因為在新版本的 Linux 中, ARM 相關(guān)的驅(qū)動全部采用了設(shè)備樹(也有支持老式驅(qū)動的,比較少),最新出的 CPU 其驅(qū)動開發(fā)也基本都是基于設(shè)備樹的,比如 ST 新出的 STM32MP157、NXP 的 I.MX8 系列等。本篇博客核心是系統(tǒng)性的學(xué)習(xí)設(shè)

    2024年02月17日
    瀏覽(22)
  • pcie 的bdf 詳細介紹,及用法實例、linux 查看pci設(shè)備信息命令詳解

    PCIe是指PCI Express,是一種計算機總線標準。在PCIe中,每個連接到主板上的設(shè)備都有唯一的地址,被稱為BDF。 BDF:Bus、Device、Function 的縮寫。其中Bus是指PCIe總線編號(一個系統(tǒng)中可能存在多個PCIe總線),Device是指連接到該總線上的某個設(shè)備編號,F(xiàn)unction是指同一個設(shè)備上不同

    2024年02月16日
    瀏覽(21)
  • 宋寶華《Linux設(shè)備驅(qū)動開發(fā)詳解》 宋老師csdn上分享的網(wǎng)盤已失效,特意新增的。

    https://pan.baidu.com/s/1rCbRUmnDtjE4jHNB5eQ8CQ 提取碼:t12r 案例代碼: https://pan.baidu.com/s/1lSMGxLnEFwO0aJGORqx8Og 提取碼: bglj Linux設(shè)備驅(qū)動開發(fā)詳解:基于最新的Linux4.0內(nèi)核 (電子與嵌入式系統(tǒng)設(shè)計叢書) (宋寶華 著)電子書: https://download.csdn.net/download/MINGTING1323/86831055

    2024年02月13日
    瀏覽(20)
  • Linux驅(qū)動開發(fā)筆記(四):設(shè)備驅(qū)動介紹、熟悉雜項設(shè)備驅(qū)動和ubuntu開發(fā)雜項設(shè)備Demo

    Linux驅(qū)動開發(fā)筆記(四):設(shè)備驅(qū)動介紹、熟悉雜項設(shè)備驅(qū)動和ubuntu開發(fā)雜項設(shè)備Demo

    若該文為原創(chuàng)文章,轉(zhuǎn)載請注明原文出處 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134533533 紅胖子網(wǎng)絡(luò)科技博文大全:開發(fā)技術(shù)集合(包含Qt實用技術(shù)、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結(jié)合等等)持續(xù)更新中… 上一篇:《Linux驅(qū)動開發(fā)筆記(三

    2024年02月05日
    瀏覽(50)
  • 4、Linux驅(qū)動開發(fā):設(shè)備-設(shè)備號&設(shè)備號注冊

    4、Linux驅(qū)動開發(fā):設(shè)備-設(shè)備號&設(shè)備號注冊

    ??點擊這里查看所有博文 ??隨著自己工作的進行,接觸到的技術(shù)棧也越來越多。給我一個很直觀的感受就是,某一項技術(shù)/經(jīng)驗在剛開始接觸的時候都記得很清楚。往往過了幾個月都會忘記的差不多了,只有經(jīng)常會用到的東西才有可能真正記下來。存在很多在特殊情況下有

    2024年02月15日
    瀏覽(44)
  • Linux驅(qū)動開發(fā)實戰(zhàn)(一)——設(shè)備驅(qū)動模型

    Linux驅(qū)動開發(fā)實戰(zhàn)(一)——設(shè)備驅(qū)動模型

    在早期的Linux內(nèi)核中并沒有為設(shè)備驅(qū)動提供統(tǒng)一的設(shè)備模型。隨著內(nèi)核的不斷擴大及系統(tǒng)更加復(fù)雜,編寫一個驅(qū)動程序越來越困難,所以在Linux2.6內(nèi)核中添加了一個統(tǒng)一的設(shè)備模型。這樣,寫設(shè)備驅(qū)動程序就稍微容易一些了。本章將對設(shè)備模型進行詳細的介紹。 設(shè)備驅(qū)動模型

    2024年02月16日
    瀏覽(26)
  • 正點原子嵌入式linux驅(qū)動開發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動

    正點原子嵌入式linux驅(qū)動開發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動

    網(wǎng)絡(luò)驅(qū)動是linux里面驅(qū)動三巨頭之一 ,linux下的網(wǎng)絡(luò)功能非常強大,嵌入式linux中也常常用到網(wǎng)絡(luò)功能。前面已經(jīng)講過了字符設(shè)備驅(qū)動和塊設(shè)備驅(qū)動,本章就來學(xué)習(xí)一下linux里面的 網(wǎng)絡(luò)設(shè)備驅(qū)動 。 本次筆記中討論的都是有線網(wǎng)絡(luò)! 提起網(wǎng)絡(luò),一般想到的硬件就是“網(wǎng)卡”。在

    2024年01月17日
    瀏覽(25)
  • 深入探討Linux驅(qū)動開發(fā):Linux設(shè)備樹

    深入探討Linux驅(qū)動開發(fā):Linux設(shè)備樹

    設(shè)備樹(Device Tree,簡稱 DT)是一種在嵌入式系統(tǒng)中描述硬件設(shè)備的一種數(shù)據(jù)結(jié)構(gòu)和編程語言。它用于將硬件設(shè)備的配置信息以樹形結(jié)構(gòu)的方式進行描述,以便操作系統(tǒng)(如 Linux)可以根據(jù)這些信息正確地識別、配置和管理硬件設(shè)備。 設(shè)備樹最初被引入到 Linux 內(nèi)核中,用于解

    2023年04月27日
    瀏覽(24)
  • Linux設(shè)備驅(qū)動開發(fā) - 虛擬時鐘Clock驅(qū)動示例

    Linux設(shè)備驅(qū)動開發(fā) - 虛擬時鐘Clock驅(qū)動示例

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜歡的盆友歡迎點贊和訂閱! 你的喜歡就是我寫作的動力! 很多設(shè)備里面系統(tǒng)時鐘架構(gòu)極其復(fù)雜,讓學(xué)習(xí)Clock驅(qū)動的盆友頭大。這里我參考S3C2440的clock驅(qū)動寫了一個virtual clock,即虛擬時鐘驅(qū)動,分別包含clock的provider和

    2023年04月21日
    瀏覽(27)
  • Linux -- 字符設(shè)備驅(qū)動--LED的驅(qū)動開發(fā)(初級框架)

    Linux -- 字符設(shè)備驅(qū)動--LED的驅(qū)動開發(fā)(初級框架)

    看原理圖確定引腳,確定引腳輸出什么電平才能點亮 / 熄滅 LED 看主芯片手冊,確定寄存器操作方法:哪些寄存器?哪些位?地址是? 編寫驅(qū)動:先寫框架,再寫硬件操作的代碼 注意 :在芯片手冊中確定的寄存器地址被稱為 物理地址 ,在 Linux 內(nèi)核中無法直接使用。 需要使

    2024年04月28日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包