日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pci枚举初始化部分(2)

發布時間:2025/6/17 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pci枚举初始化部分(2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.2.8判斷pcie設備是否支持雷電技術

Intel具有一種基于Thunderbolt技術的PCIE變體,它結合了DisplayPort和PCIe協議,與Mini DisplayPort兼容。
Thunderbolt技術融合兩種通信方法或者說協議,其中PCI Express用于數據傳輸,可以連接幾乎任何類型的設備,DisplayPort用于顯示,能同步傳輸1080p乃至超高清視頻和最多八聲道音頻。
因此代碼只在intel生產的設備中進行判別。
set_pcie_thunderbolt()

while ((vsec = pci_find_next_ext_capability(dev, vsec,PCI_EXT_CAP_ID_VNDR))) {pci_read_config_dword(dev, vsec + PCI_VNDR_HEADER, &header);/* Is the device part of a Thunderbolt controller? *///設備是否具有雷電控制器if (dev->vendor == PCI_VENDOR_ID_INTEL &&PCI_VNDR_HEADER_ID(header) == PCI_VSEC_ID_INTEL_TBT) {dev->is_thunderbolt = 1;return;}}

其中有

#define PCI_VNDR_HEADER_ID(x) ((x) & 0xffff) #define PCI_VSEC_ID_INTEL_TBT 0x1234 //雷電接口

1.2.9修復某些特殊的bug

對于某些bug,只存在于特定體系或設備,無法在此處進行列舉,因此提供一個hook用于修復特殊設備的bug。而hook通過內核配置情況進行掛載。
pci_fixup_device()

//查找是否存在廠商號設備號相同的情況 for (; f < end; f++)if ((f->class == (u32) (dev->class >> f->class_shift) ||f->class == (u32) PCI_ANY_ID) &&(f->vendor == dev->vendor ||f->vendor == (u16) PCI_ANY_ID) &&(f->device == dev->device ||f->device == (u16) PCI_ANY_ID)) {void (*hook)(struct pci_dev *dev);//獲取hook函數指針,用于修復特定bug #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONShook = offset_to_ptr(&f->hook_offset); #elsehook = f->hook; #endifcalltime = fixup_debug_start(dev, hook);hook(dev);fixup_debug_report(dev, calltime, hook);}

其中hook可有由

#define DECLARE_PCI_FIXUP_CLASS_EARLY(vendor, device, class, \class_shift, hook) \DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \hook, vendor, device, class, class_shift, hook)

等宏進行掛載。

  • 舉個例子
    arch\x86\pci
static void pci_early_fixup_cyrix_5530(struct pci_dev *dev) {u8 r;/* clear 'F4 Video Configuration Trap' bit */pci_read_config_byte(dev, 0x42, &r);r &= 0xfd;pci_write_config_byte(dev, 0x42, r); } //注冊回調函數到pci_early_fixup段中,用于修復x86平臺下該設備出現的bug。 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,pci_early_fixup_cyrix_5530); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,pci_early_fixup_cyrix_5530);

通過DECLARE_PCI_FIXUP_EARLY宏將pci_early_fixup_cyrix_5530回調函數注冊到pci_fixup_early段中,在通過hook函數指針調用并執行函數解決x86平臺下5530設備特有的錯誤情況。

1.2.10 設置command寄存器

1.2.10.1 錯誤情況禁止IO空間和內存空間

//沒有識別正確的if (dev->non_compliant_bars) {pci_read_config_word(dev, PCI_COMMAND, &cmd);if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {pci_info(dev, "device has non-compliant BARs; disabling IO/MEM decoding\n");cmd &= ~PCI_COMMAND_IO;cmd &= ~PCI_COMMAND_MEMORY;pci_write_config_word(dev, PCI_COMMAND, cmd);}}

COMMAND[0] :IO SPACE位
該位表示PCI設備是否響應I/O請求,為1時響應,0時不響應。
COMMAND[1]: Memory Space位
該位表示PCI設備是否響應存儲器請求,為1時響應,0時不響應。

1.2.10.2 判斷command寄存器中斷禁止位是否可寫

pci_intx_mask_broken()

u16 orig, toggle, new;pci_read_config_word(dev, PCI_COMMAND, &orig);toggle = orig ^ PCI_COMMAND_INTX_DISABLE;pci_write_config_word(dev, PCI_COMMAND, toggle);pci_read_config_word(dev, PCI_COMMAND, &new);pci_write_config_word(dev, PCI_COMMAND, orig);//PCI_COMMAND_INTX_DISABLE是預留位并在PCIr2.3版本是只讀的,因此嚴格輸出//如果他是不可寫的,則這個設備沒有損壞。if (new != toggle)return 1;return 0;

COMMAND[10] :interrupt Disable位
復位值為0,該位為1時,PCI設備不能通過INTx信號向HOST主橋提交中斷請求,為0時可以使用INTx信號提出請求。當PCI設備使用MSI中斷方式提交中斷請求時,該位將被置為1。

1.2.11 根據不同頭類型做初始化

1.2.11.1標準頭

1.2.11.1.1獲取設備信息

獲取設備中斷信息和BAR空間信息。

switch (dev->hdr_type) { /* header type */case PCI_HEADER_TYPE_NORMAL: /* standard header */ //錯誤情況if (class == PCI_CLASS_BRIDGE_PCI)goto bad; //獲取中斷號和中斷引腳pci_read_irq(dev); //獲取基地址pci_read_bases(dev, 6, PCI_ROM_ADDRESS);//獲取子廠商號設備號pci_subsystem_ids(dev, &dev->subsystem_vendor, &dev->subsystem_device);

(1)中斷信息
包括中斷號,中斷引腳。
pci_read_irq()

pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);dev->pin = irq;if (irq)pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);dev->irq = irq;

(2)BAR空間信息
包括BAR空間大小,空間基地址,空間類型(IO/內存),空間位數(32位,64位)等。
pci_read_bases函數調用__pci_read_base函數來獲取這些信息。
__pci_read_base()
(2.1)默認為 32位PCI時,獲取PCI空間大小

pci_read_config_dword(dev, pos, &l);pci_write_config_dword(dev, pos, l | mask);pci_read_config_dword(dev, pos, &sz);pci_write_config_dword(dev, pos, l);
  • (2.2) 通過decode_bar()函數判別PCIBAR空間類型*
  • 判斷是否IO空間類型。
//判斷是否IO空間if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;flags |= IORESOURCE_IO;return flags;}

通過BAR基地址的bit[0]可判別BAR空間類型為IO空間還是內存空間,1表示IO空間,0表示內存空間。
bit[1,2]則表示了BAR空間為32位還是64位。
bit[3]表示BAR是否支持預取。
其中bit[1,2]=01在linux4.x代碼中代表1M這種類型。

  • 判斷內存空間位數
//判斷內存空間位數mem_type = bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK;switch (mem_type) {case PCI_BASE_ADDRESS_MEM_TYPE_32:break;case PCI_BASE_ADDRESS_MEM_TYPE_1M:/* 1M mem BAR treated as 32-bit BAR */break;case PCI_BASE_ADDRESS_MEM_TYPE_64:flags |= IORESOURCE_MEM_64;break;default:/* mem unknown type treated as 32-bit BAR */break;}
  • 64位的處理
//64位重新獲取設備基地址和大小pci_read_config_dword(dev, pos + 4, &l);pci_write_config_dword(dev, pos + 4, ~0);pci_read_config_dword(dev, pos + 4, &sz);pci_write_config_dword(dev, pos + 4, l);

獲取地址和大小后還需判斷其是否超過體系所支持的位數,32位下是不能支持64位PCI設備的,PCI空間大小也是不能超過4G的。

  • 測試BAR空間映射是否正確。
pcibios_bus_to_resource(dev->bus, res, &region);pcibios_resource_to_bus(dev->bus, &inverted_region, res);

pcibios_bus_to_resource函數用于總線地址轉換到資源地址(用于CPU的物理地址)。
pcibios_resource_to_bus執行相反操作,如果,相互轉換的值不正確,則不能使用該設備。

1.2.11.1.2 對于ATA控制器的特殊設置

傳統模式ATA控制器具有固定地址。且BAR0-3的數據在某些情況下是無效的。
classCode寄存器用于判斷設備類別。

#define PCI_CLASS_STORAGE_IDE 0x0101

通過base class=01,subclass =01,可以確定為IDE類型存儲器

對于IDE控制器類型的PCI設備,又通過interface寄存器字段進行了細分:

interface:
bit7:確定是否為主IDE設備
bit3:可編程指示器(次通道)
bit2:操作模式(次通道)
bit1:可編程指示器(主通道)
bit0:操作模式(主通道)
根據PCI IDE Controller Specification Revision 1.0文檔可知

對于主通道來說,命令寄存器被固定為1f0h-1f7h,其控制塊地址為3fh,
次通道命令寄存器地址170h-177h,控制寄存器376h.

if (class == PCI_CLASS_STORAGE_IDE) {u8 progif;pci_read_config_byte(dev,, &progif); //主通道IDE控制器 if ((progif & 1) == 0) {region.start = 0x1F0;region.end = 0x1F7;res = &dev->resource[0];res->flags = LEGACY_IO_RESOURCE;pcibios_bus_to_resource(dev->bus, res, &region);pci_info(dev, "legacy IDE quirk: reg 0x10: %pR\n",res);region.start = 0x3F6;region.end = 0x3F6;res = &dev->resource[1];res->flags = LEGACY_IO_RESOURCE;pcibios_bus_to_resource(dev->bus, res, &region);pci_info(dev, "legacy IDE quirk: reg 0x14: %pR\n",res);} //次通道IDE控制器 if ((progif & 4) == 0) {region.start = 0x170;region.end = 0x177;res = &dev->resource[2];res->flags = LEGACY_IO_RESOURCE;pcibios_bus_to_resource(dev->bus, res, &region);pci_info(dev, "legacy IDE quirk: reg 0x18: %pR\n",res);region.start = 0x376;region.end = 0x376;res = &dev->resource[3];res->flags = LEGACY_IO_RESOURCE;pcibios_bus_to_resource(dev->bus, res, &region);pci_info(dev, "legacy IDE quirk: reg 0x1c: %pR\n",res);}}break;

1.2.11.2橋頭

PCI-PCI橋若要求譯碼(比如透明橋),橋的編程接口代碼必須是0x01

case PCI_HEADER_TYPE_BRIDGE: /* bridge header */if (class != PCI_CLASS_BRIDGE_PCI)goto bad;pci_read_irq(dev);dev->transparent = ((dev->class & 0xff) == 1);pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); //查詢是否支持熱插拔set_pcie_hotplug_bridge(dev); //查找capability中子系統的廠商號和設備號pos = pci_find_capability(dev, PCI_CAP_ID_SSVID);if (pos) {pci_read_config_word(dev, pos + PCI_SSVID_VENDOR_ID, &dev->subsystem_vendor);pci_read_config_word(dev, pos + PCI_SSVID_DEVICE_ID, &dev->subsystem_device);}break;

對于熱插拔
set_pcie_hotplug_bridge()

pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &reg32);if (reg32 & PCI_EXP_SLTCAP_HPC)pdev->is_hotplug_bridge = 1;

其中

#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */

通過查詢pcie_3.0總線規范,可以看到偏移為14h的寄存器中有關于是否支持熱插拔的狀態位。

bit6 = 1時,表示設備支持熱插拔。

1.2.11.2cardBus橋頭

case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */if (class != PCI_CLASS_BRIDGE_CARDBUS)goto bad;pci_read_irq(dev);pci_read_bases(dev, 1, 0);pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);break;

結束

pci_setup_device()函數完成了對單個設備的設備和檢測,并將獲取的信息存取設備結構體中,用于后期具體設備的使用。

轉載于:https://www.cnblogs.com/weiyoutongxing/p/10045668.html

總結

以上是生活随笔為你收集整理的pci枚举初始化部分(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。