5. 透過sysfs訪問PCI裝置資源¶
sysfs 通常掛載在 /sys,它提供了在支援它的平臺上訪問 PCI 資源的能力。例如,某個匯流排可能看起來像這樣
/sys/devices/pci0000:17
|-- 0000:17:00.0
| |-- class
| |-- config
| |-- device
| |-- enable
| |-- irq
| |-- local_cpus
| |-- remove
| |-- resource
| |-- resource0
| |-- resource1
| |-- resource2
| |-- revision
| |-- rom
| |-- subsystem_device
| |-- subsystem_vendor
| `-- vendor
`-- ...
最頂層元素描述了 PCI 域和匯流排號。在本例中,域號是 0000,匯流排號是 17(兩個值都是十六進位制)。該匯流排在槽位 0 包含一個單功能裝置。為方便起見,域號和匯流排號被複制了一份。裝置目錄下有幾個檔案,每個檔案都有自己的功能。
檔案
功能
class
PCI 類 (ascii, 只讀)
config
PCI 配置空間 (二進位制, 讀寫)
device
PCI 裝置 (ascii, 只讀)
enable
裝置是否已啟用 (ascii, 讀寫)
irq
IRQ 號 (ascii, 只讀)
local_cpus
鄰近 CPU 掩碼 (cpumask, 只讀)
remove
從核心列表中移除裝置 (ascii, 只寫)
resource
PCI 資源主機地址 (ascii, 只讀)
resource0..N
PCI 資源 N,如果存在 (二進位制, mmap, 讀寫[1])
resource0_wc..N_wc
PCI WC 對映資源 N,如果可預取 (二進位制, mmap)
revision
PCI 修訂版本 (ascii, 只讀)
rom
PCI ROM 資源,如果存在 (二進位制, 只讀)
subsystem_device
PCI 子系統裝置 (ascii, 只讀)
subsystem_vendor
PCI 子系統廠商 (ascii, 只讀)
vendor
PCI 廠商 (ascii, 只讀)
ro - read only file
rw - file is readable and writable
wo - write only file
mmap - file is mmapable
ascii - file contains ascii text
binary - file contains binary data
cpumask - file contains a cpumask type
只讀檔案用於提供資訊,對其的寫入將被忽略,'rom' 檔案除外。可寫檔案可用於對裝置執行操作(例如,更改配置空間、分離裝置)。可 mmap 的檔案透過對檔案進行偏移量為 0 的 mmap 操作來獲取,並可用於從使用者空間進行實際的裝置程式設計。請注意,某些平臺不支援某些資源的 mmap,因此請務必檢查任何 mmap 嘗試的返回值。其中最值得注意的是 I/O 埠資源,它們也提供讀寫訪問。
‘enable’ 檔案提供了一個計數器,指示裝置已被啟用的次數。如果 ‘enable’ 檔案當前返回 ‘4’,並向其中寫入 ‘1’,它將返回 ‘5’。向其中寫入 ‘0’ 將減少計數。然而,即使計數返回到 0,某些初始化可能也無法被撤銷。
‘rom’ 檔案很特殊,因為它提供對裝置 ROM 檔案的只讀訪問(如果可用)。但是,它預設是停用的,因此應用程式在嘗試讀取呼叫之前應向檔案寫入字串“1”以啟用它,並在訪問後透過寫入“0”到檔案來停用它。請注意,裝置必須處於啟用狀態,ROM 讀取才能成功返回資料。如果驅動程式未繫結到裝置,則可以使用上面提到的 ‘enable’ 檔案來啟用它。
‘remove’ 檔案用於移除 PCI 裝置,透過向該檔案寫入一個非零整數來實現。這不涉及任何熱插拔功能,例如關閉裝置電源。裝置將從核心的 PCI 裝置列表中移除,其 sysfs 目錄將被移除,並且裝置將從任何附加到它的驅動程式中移除。不允許移除 PCI 根匯流排。
5.1. 透過sysfs訪問傳統資源¶
如果底層平臺支援,sysfs 也提供了傳統 I/O 埠和 ISA 記憶體資源。它們位於 PCI 類層次結構中,例如:
/sys/class/pci_bus/0000:17/
|-- bridge -> ../../../devices/pci0000:17
|-- cpuaffinity
|-- legacy_io
`-- legacy_mem
legacy_io 檔案是一個讀寫檔案,應用程式可以使用它來執行傳統埠 I/O。應用程式應開啟該檔案,定址到所需的埠(例如 0x3e8),並執行 1、2 或 4 位元組的讀寫操作。legacy_mem 檔案應該使用與所需記憶體偏移量對應的偏移量進行 mmap,例如 VGA 幀緩衝區的 0xa0000。然後,應用程式可以簡單地解引用返回的指標(當然,在檢查錯誤之後)來訪問傳統記憶體空間。
5.2. 在新平臺上支援 PCI 訪問¶
為了支援上述 PCI 資源對映,Linux 平臺程式碼應理想地定義 ARCH_GENERIC_PCI_MMAP_RESOURCE 並使用該功能的通用實現。為了支援透過 /proc/bus/pci 中的檔案進行 mmap() 的歷史介面,平臺還可以設定 HAVE_PCI_MMAP。
或者,設定了 HAVE_PCI_MMAP 的平臺可以提供自己的 pci_mmap_resource_range() 實現,而不是定義 ARCH_GENERIC_PCI_MMAP_RESOURCE。
支援 PCI 資源寫合併對映的平臺必須定義 arch_can_pci_mmap_wc(),該函式在允許寫合併時在執行時應評估為非零值。支援 I/O 資源對映的平臺類似地定義 arch_can_pci_mmap_io()。
傳統資源受 HAVE_PCI_LEGACY 定義的保護。希望支援傳統功能的平臺應定義它並提供 pci_legacy_read、pci_legacy_write 和 pci_mmap_legacy_page_range 函式。