250 likes | 437 Views
Ch15- Overview of Peripheral Buses. Overview of Peripheral Buses. 低階硬體控制 (ch-8) 高階匯流排架構 ( bus architecture ) 匯流排是由一組電子介面 (electrical interface) 與一組程式介面 ( programming interface ) 共同組成。 本章涵蓋多種匯流排架構,但重點在於 PC I ,以及用來存取 PCI 的核心函式 。. Outline. The PCI interface A Look back : ISA Other PC Buses
E N D
Overview of Peripheral Buses • 低階硬體控制(ch-8) • 高階匯流排架構 ( bus architecture ) • 匯流排是由一組電子介面(electrical interface) 與一組程式介面(programming interface)共同組成。 • 本章涵蓋多種匯流排架構,但重點在於PCI,以及用來存取PCI的核心函式。
Outline • The PCI interface • A Look back:ISA • Other PC Buses • PC/104 and PC/104+ • SBus • NuBus • External Buses • Backward Compatibility
The PCI Interface • Peripheral Component Interconnect • PCI不只是電子線路的佈線方式,更是一套完整的標準規格。除了規定電器特性之外,也規範了電腦內部不同元件之間的互動原則。 • PCI三大目標: • 提升CPU與週邊之間的資料傳輸效能 • 儘可能跨平台(IA-32, Alpha, PowerPC, SPARC64和IA-64) • 簡化安裝移除週邊的程序(具備自動偵測能力)
PCI 定址法 • 每個PCI裝置都有一個16-bits識別碼 • 匯流排bus-8bits • 裝置device-5bits • 機能function-3bits • 一個系統最多可以容納256個PCI匯流排,每組匯流排最多可接32個裝置,每個裝置最多可具備8種機能。 • Linux驅動程式不必直接處理硬體位址,而以--pci_dev--來代表PCI裝置。(ch13-struct pci_dev) • 橋接器(bridges):連接不同匯流排。 • 整個PCI系統組織成一個樹狀結構..
PCI 定址法 • 查看系統上有哪些PCI裝置時: • lspci ( 在pciutils套件裡 ) • “BB:DD:F”就是識別碼的三個欄位 • cat /proc/bus/pci/devices | cut –f1,3 |sort 00:00.0 Host bridge 00:01.0 PCI bridge 00:05.0 Ethernet controller 00:07.0 ISA bridge 00:07.1 IDE interface 00:07.2 USB Controller 00:07.4 ISA bridge 00:07.5 Multimedia audio controller 00:07.6 Communication controller 00:0a.0 CardBus bridge 01:00.0 VGA compatible controller
PCI 定址法 • 每片PCI卡的硬體電路,都要能夠回答它們的”記憶區、I/O埠、組態暫存器”分別在三種位址空間的範圍。 • 同PCI匯流排上的所有裝置,共用記憶體空間與I/O空間,這表示當某記憶位址被存取時,同匯流排上的全部裝置會同時看到相同的位址信號。 • 同PCI匯流排上的不同裝置,彼此的記憶區必須錯開,令一方面,組態暫存器的位址,則採用”槽位定址法(geographical addressing)” • PCI規格要求介面卡上的每一塊記憶區與I/O區,都必須被映射到其他位址範圍。( PCI BIOS )
開機期 • 當電源施加到PCI裝置時,裝置上的記憶體與I/O埠都還沒映射到主機的位址空間,任何輔助機能(中斷、DMA)與主要機能(顯示、控制硬碟..)都失效,在這種情況下裝置指對“組態交涉”有反應。 • 組態交涉:將裝置設定成可供主機存取的狀態,稱為BIOS、NVRAM或PROM,隨平台而定。韌體藉由讀、寫PCI控制器上的暫存器,而提供存取裝置組態空間的能力。 • cat /proc/bus/pci/devices 16 bits • cat /proc/pci 文字 • cat /proc/bus/pci/01/08.0 組態現況檔
組態暫存器與初始化 • 組態空間的格局,是任何PCI裝置都必須遵守的標準,與裝置類型無關。 • 給個PCI裝置都有一個256-byte的位址空間,前64-byte的格式必須符合統一標準,其餘部份開放給廠商自己決定。 • 必要暫存器&選項暫存器 • PCI暫存器的位元組順序固定是”little-endian”。雖然PCI標準的設計目標之一是跨平台,但是還是可看到出PCI設計者比較偏向於Intel-PC環境。
組態暫存器與初始化 • vendorID:16-bits暫存器,代表“硬體製造商”。 • (ex:intel其vendorID為0x8086) • deviceID:16-bits暫存器,其內容值由製造廠商自己決定,不必經過正式的行政註冊。通常與vendorID搭配成對,組成一個可代表特定硬體裝置的32-bits識別碼(signature)。 • class:16-bits暫存器,較高8-bits代表通類(base class),或稱為組別(group)。 • (ex:Ethernet與Token Ring是屬於網路組的兩種類別) • subsystem vendorID & subsystem deviceID:對於功能類似的裝置…讓驅動程式進一步區別…
組態暫存器與初始化 • #include <linux/config.h> • CONFIG_PCI • #include <linux/pci.h> • int pci_present(void); • struct pci_dev; • struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); • struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from); • int pci_enable_device(struct pci_dev *dev); • struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
組態暫存器與初始化 #ifndef CONFIG_PCI # error "This driver needs PCI support to be available" #endif int jail_find_all_devices(void) { struct pci_dev *dev = NULL; int found; if (!pci_present()) return -ENODEV; for (found=0; found < JAIL_MAX_DEV;) { dev = pci_find_device(JAIL_VENDOR, JAIL_ID, dev); if (!dev) /* no more devices are there */ break; /* do device-specific actions and count the device */ found += jail_init_one(dev); } return (index == 0) ? -ENODEV : 0; }
組態暫存器與初始化 • jail_init_one( )的角色隨裝置的性質而定,所處沒法列出確切的程式碼。但有些觀念需謹記在心… • 進行必要的而外特測程序,確保找到裝置確實在支援之列。 • 在存取任何資源之前,必須先呼叫pci_enable_device( )。 • 對於網路介面驅動程式,應該將dev-driver_data指向介面所屬的struct net_device( )
存取組態空間 • 順利偵測出裝置之後,驅動程式還需要能夠讀寫裝置的三種位址空間:記憶體、I/O埠、組態空間。 • Linux核心對驅動程式提供了8, 16, 32-bits三種資料傳輸模式來存取組態空間。<linux/pci.h> 讀取: int pci_read_config_byte(struct pci_dev *dev, int where, u8 *ptr); int pci_read_config_word(struct pci_dev *dev, int where, u16 *ptr); int pci_read_config_dword(struct pci_dev *dev, int where, u32 *ptr); 寫入: int pci_write_config_byte (struct pci_dev *dev, int where, u8 val); int pci_write_config_word (struct pci_dev *dev, int where, u16 val); int pci_write_config_dword (struct pci_dev *dev, int where, u32 val);
檢視組態空間現況 • Linux 2.0後 直接利用現成的/proc/bus/pci • Linux 2.0前 需自己寫程式來檢視組態空間現況
存取I/O空間與記憶體空間 • 每個PCI裝置最多可以配備6個位址區,他們可能是記憶區,也可能是I/O區。 • 區別記憶區到底是對應到裝置上的記憶體或I/O暫存器,可藉由組態暫存器裡的“memory-is-prefetchable”位元來判斷。
Linux 2.4的PCI I/O資源 • Linux 2.4,PCI裝置的I/O區域已經被整合進”通用資源管理”,因此若想知道裝置的記憶空間或I/O空間是映射到何處,可以利用下列函式來取得區域的對應關係: • 只要利用這些函式,驅動程式其實可以完全不理會實際的PCI暫存器,因為系統已經幫你解讀… unsigned long pci_resource_start(struct pci_dev *dev, int bar); unsigned long pci_resource_end(struct pci_dev *dev, int bar); unsigned long pci_resource_flags(struct pci_dev *dev, int bar); IORESOURCE_IO IORESOURCE_MEM IORESOURCE_PREFETCH IORESOURCE_READONLY
PCI 中斷 • PCI的中斷很容易處理,在啟動Linux時,電腦的韌體就已經分配好各裝置的IRQ號碼,所以驅動程式只要照用即可。 • Configuration register 60:PCI_INTERRUPT_LINE • Configuration register 61︰PCI_INTERRUPT_PINE • 第九章介紹的中斷號碼探測技術也可以用在PCI裝置上,只不過可以直接從PCI_INTERRUPT_LINE讀取中斷號碼,然後存在適當的變數裡即可,如下: result = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &myirq); if (result) { /* deal with error */ }
熱插拔裝置的處置 • 每當有新裝置再系統的生命週期中出現時,所有可用的驅動程式都必須檢查新裝置是不是她們要驅動的對象,因此與其使用傳統的init與cleanup機制,支援熱插拔的驅動程式必須向核心註冊一個物件,以及一個open方法,該物件會要求probe來檢查是否應該持有新裝置,或是應該置之不理。我們稱為”Driver-Object技術” • 或許會抗議現在還沒有可以在PCI插槽上熱插拔的裝置。不過,對於必須處理多個替換裝置的驅動程式而言,Driver-Object技術也非常有用,因為在驅動程式進行初始化程序時,只需檢查目前裝置是否在已知清單中,而不必主動搜尋PCI匯流排。
其他PC匯流排 • ISA • PC/104與PC/104+ • MCA (Micro Channel Architecture) • EISA (Extended ISA) • VLB (VESA Local Bus) • SBus • NuBus • 外接式匯流排(USB)
USB • 通用串列匯流排 (Universal Serial Bus) • 是目前唯一成熟到可以適度討論的外接式匯流排 • USB特性: • 可以要求一段固定的頻寬,以便支援可靠的影音資料傳輸。 • 可被當成主機與裝置之間的純通訊管道,而不要求傳輸資料本身要編碼成特定的格式。 • Open Host Controller Interface (OHCI) • Universal Host Controller Interface (UHCI) • Enhanced Host Controller Interface (EHCI)
USB • OHCI:採用Memory存取方式 (CPU使用I/O指令來存取USB Controller) • UHCI:採用I/O-mapped存取方式 (CPU使用記憶體指令來存取USB Controller) • EHCI:USB2.0 • cat /proc/pci
設計USB驅動程式 • USB裝置驅動程式的設計技巧,很類似於pci_driver:驅動程式先向USB子系統註冊他的driver物件,然後使用vendor與device識別碼辨認其驅動對象是否被接到系統上。