pci枚举初始化部分(2)
1.2.8判斷pcie設備是否支持雷電技術
Intel具有一種基于Thunderbolt技術的PCIE變體,它結合了DisplayPort和PCIe協議,與Mini DisplayPort兼容。
Thunderbolt技術融合兩種通信方法或者說協議,其中PCI Express用于數據傳輸,可以連接幾乎任何類型的設備,DisplayPort用于顯示,能同步傳輸1080p乃至超高清視頻和最多八聲道音頻。
因此代碼只在intel生產的設備中進行判別。
set_pcie_thunderbolt()
其中有
#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()
其中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
通過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()
(2)BAR空間信息
包括BAR空間大小,空間基地址,空間類型(IO/內存),空間位數(32位,64位)等。
pci_read_bases函數調用__pci_read_base函數來獲取這些信息。
__pci_read_base()
(2.1)默認為 32位PCI時,獲取PCI空間大小
- (2.2) 通過decode_bar()函數判別PCIBAR空間類型*
- 判斷是否IO空間類型。
通過BAR基地址的bit[0]可判別BAR空間類型為IO空間還是內存空間,1表示IO空間,0表示內存空間。
bit[1,2]則表示了BAR空間為32位還是64位。
bit[3]表示BAR是否支持預取。
其中bit[1,2]=01在linux4.x代碼中代表1M這種類型。
- 判斷內存空間位數
- 64位的處理
獲取地址和大小后還需判斷其是否超過體系所支持的位數,32位下是不能支持64位PCI設備的,PCI空間大小也是不能超過4G的。
- 測試BAR空間映射是否正確。
pcibios_bus_to_resource函數用于總線地址轉換到資源地址(用于CPU的物理地址)。
pcibios_resource_to_bus執行相反操作,如果,相互轉換的值不正確,則不能使用該設備。
1.2.11.1.2 對于ATA控制器的特殊設置
傳統模式ATA控制器具有固定地址。且BAR0-3的數據在某些情況下是無效的。
classCode寄存器用于判斷設備類別。
通過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.
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()
其中
#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)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 要不要立Flag呢
- 下一篇: Python脚本--微信公众号自定义菜单