PCI驱动开发学习笔记(一)
- PCIE簡介
???????? PCIe作為串行總線的一種,它的發(fā)展必然和另一種總線架構(gòu)密不可分:并行總線。
??????? 像PCIe接口的顯卡、聲卡、網(wǎng)卡,都屬于功能設(shè)備,在PCIe規(guī)范中,我們統(tǒng)稱為Endpoint(簡稱EP)。還有其他兩類設(shè)備,? 一個是Root Complex,簡稱RC,另一個是switch(或者PCI中稱為bridge),RC是根設(shè)備,通過switch和下游設(shè)備(可以是EP也可以是switch)進行橋接,從而各個PCIe設(shè)備組成了一個PCIe設(shè)備網(wǎng)絡(luò),信息就以數(shù)據(jù)包(TLP、DLLP)的形式在網(wǎng)絡(luò)中傳遞。
一、PCI設(shè)備編號
???????? PCI設(shè)備的ID號由總線號(BUS NUMBER)、設(shè)備號(DEVICE NUMBER)和功能號(FUNCTION NUMBER)組成。
???????? 一條PCI總線的設(shè)備號由PCI設(shè)備的IDSEL信號與PCI總線地址線的連接關(guān)系確定,即每一個PCI插槽的總線號和設(shè)備號都是固定的,這是硬件工程師決定的。
???????? PCI功能號與PCI設(shè)備的具體設(shè)計相關(guān)。在一個PCI設(shè)備中最多有8個功能設(shè)備,而且每一個功能設(shè)備都有各自的PCI配置空間,而在絕大數(shù)PCI設(shè)備中只有一個功能設(shè)備。
lspci? --- 枚舉PCI設(shè)備
???????? 01:00.0 VGA compatible controller: NVIDIA Corporation GM107 [GeForce GTX 745] (rev a2)
??????? (bus number 0~0xff[2^8]):(device number 0~0x1f[2^5]).(function number 0~0x07[2^3])? Class:Vendor Device (revision)
二、PCI配置空間
每個PCI邏輯設(shè)備都有自己的配置空間,里面存儲了一些基本信息,生產(chǎn)商,IRQ中斷號,還有就是定義了mem空間和io空間的起始地址和大小。
HOST主橋使用寄存器號,訪問PCI設(shè)備配置空間的某個寄存器。
三、PCI驅(qū)動函數(shù)接口
???????? 1.? pci驅(qū)動注冊
????????? pci_register_driver(struct pci_driver *drv)
????????? pci_unregister_driver(struct pci_driver *drv)
static struct pci_device_id vt8623_devices[] = {{PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},{0, 0, 0, 0, 0, 0, 0} }; static struct pci_driver vt8623fb_pci_driver = {.name = "vt8623fb",.id_table = vt8623_devices,.probe = vt8623_pci_probe,.remove = vt8623_pci_remove,.suspend = vt8623_pci_suspend,.resume = vt8623_pci_resume, };pci_register_driver(&vt8623fb_pci_driver);????????? 2. 激活PCI設(shè)備
??????????????? 在驅(qū)動程序可以訪問PCI設(shè)備的任何設(shè)備資源之前(I/O區(qū)域或者中斷),驅(qū)動程序必須調(diào)用該函數(shù):
int pci_enable_device(struct pci_dev *dev); /*driver/pci/pci.c*/這個函數(shù)主要就是把PCI配置空間的Command域的0位和1?位置成了1,從而達到了開啟設(shè)備的目的。????????? 3.? 訪問PCI配置空間
int pci_read_config_byte(conststruct pci_dev *dev,int where, u8 *val);/*8位,讀入一個字節(jié)*/int pci_read_config_word(conststruct pci_dev *dev,int where, u16 *val);/*16位,讀入兩個字節(jié)*/int pci_read_config_dword(conststruct pci_dev *dev,int where, u32 *val);/*32位,讀入四個字節(jié)*/ int pci_write_config_byte(conststruct pci_dev *dev,int where, u8 *val);/*8位,寫入一個字節(jié)*/int pci_write_config_word(conststruct pci_dev *dev,int where, u16 *val);/*16位,寫入兩個字節(jié)*/int pci_write_config_dword(conststruct pci_dev *dev,int where, u32 *val);/*32位,寫入四個字節(jié)*/????????? 4. 申請IO端口和內(nèi)存資源
?????????????? 通知內(nèi)核該設(shè)備對應(yīng)的IO端口和內(nèi)存資源已經(jīng)使用,其他的PCI設(shè)備不要再使用這個區(qū)域
???????????? int? pci_request_regions(struct pci_dev *dev, const char *res_name)
???????????? int? pci_release_regions(struct pci_dev *pdev)
???????????? int? pci_request_mem_regions(struct pci_dev *pdev, const char *name)
???????????? int? pci_release_mem_regions(struct pci_dev *pdev)
???????????? int? pci_request_io_regions(struct pci_dev *pdev, const char *name)
???????????? int? pci_release_io_regions(struct pci_dev *pdev)
?
?????????? 5. 訪問PCI的I/O和內(nèi)存空間
???????????? int pci_resource_[start|end|flags|len](struct pci_dev *dev,? int bar)? //Bar值的范圍為0-5
?在硬件加電初始化時,BIOS固件統(tǒng)一檢查了所有的PCI設(shè)備,并統(tǒng)一為他們分配了一個和其他互不沖突的地址,讓他們的驅(qū)動程序可以向這些地址映射他們的寄存器,這些地址被BIOS寫進了各個設(shè)備的配置空間,因為這個活動是一個PCI的標準的活動,所以自然寫到各個設(shè)備的配置空間里而不是他們風格各異的控制寄存器空間里。當操作系統(tǒng)初始化時,他為每個PCI設(shè)備分配了pci_dev結(jié)構(gòu),并且把BIOS獲得的并寫到了配置空間中的地址讀出來寫到了pci_dev中的resource字段中。這樣以后我們在讀這些地址就不需要在訪問配置空間了,直接跟pci_dev要就可以了,我們這里的四個函數(shù)就是直接從pci_dev讀出了相關(guān)數(shù)據(jù)。
Linux認為這個地址是IO地址,如果要訪問的話可以通過ioremap映射到內(nèi)核空間,然后通過readl/writel等IO接口進行操作。
?????????? 6.? 私有數(shù)據(jù)
???????????? pci_set_drvdata??? 設(shè)置驅(qū)動私有數(shù)據(jù)
???????????? pci_get_drvdata??? 獲取驅(qū)動私有數(shù)據(jù)
?????????? 7. 主設(shè)備模式
????????????? pci_set_master??? 設(shè)定設(shè)備工作在總線主設(shè)備模式
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的PCI驱动开发学习笔记(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: h5在线聊天室(附源码)
- 下一篇: rails中关于carrierwave、