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_RELOCATIONS hook = offset_to_ptr(&f->hook_offset); #else hook = f->hook; #endif calltime = 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, ®ion);
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型別儲存器
605842281.png
606033218.png
對於IDE控制器型別的PCI裝置,又通過interface暫存器欄位進行了細分:
606501953.png
interface:
bit7:確定是否為主IDE裝置
bit3:可程式設計指示器(次通道)
bit2:操作模式(次通道)
bit1:可程式設計指示器(主通道)
bit0:操作模式(主通道)
根據PCI IDE Controller Specification Revision 1.0文件可知
607509671.png
對於主通道來說,命令暫存器被固定為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, ®ion);
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, ®ion);
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, ®ion);
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, ®ion);
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, ®32);
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的暫存器中有關於是否支援熱插拔的狀態位。
{{609199765.png(uploading...)}}
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()函式完成了對單個裝置的裝置和檢測,並將獲取的資訊存取裝置結構體中,用於後期具體裝置的使用。607509671.png
---恢復內容結束---
### 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_RELOCATIONS
hook = offset_to_ptr(&f->hook_offset);
#else
hook = f->hook;
#endif
calltime = 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, ®ion);
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型別儲存器
605842281.png
606033218.png
對於IDE控制器型別的PCI裝置,又通過interface暫存器欄位進行了細分:
606501953.png
interface:
bit7:確定是否為主IDE裝置
bit3:可程式設計指示器(次通道)
bit2:操作模式(次通道)
bit1:可程式設計指示器(主通道)
bit0:操作模式(主通道)
根據PCI IDE Controller Specification Revision 1.0文件可知
607509671.png
對於主通道來說,命令暫存器被固定為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, ®ion);
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, ®ion);
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, ®ion);
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, ®ion);
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, ®32);
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()函式完成了對單個裝置的裝置和檢測,並將獲取的資訊存取裝置結構體中,用於後期具體裝置的使用。607509671.png