吹個牛先:計劃寫三篇文章,本文主要描述PCIe設備識別過程,接下來會完成兩篇,(二)中斷,(三)數據傳輸
博觀而約取,厚積而薄發
寫在開始的話,不知道看了多少資料才總結出一點知識,能輸入已經很不容易,何況想要輸出,有十能輸出一二就算不錯了。所以這個過程中真的很難堅持下來,何況沒有實際項目作爲載體,真的不知道實際運用中這些知識夠不夠用,這只是基於我之前的經驗,認爲一個全新的硬件模塊中需要掌握的部分。
1 首先要了解這個硬件的用途,物理接口,pin定義。
2 要知道需要做什麼樣的配置才能使得設備達到我們的預期。
3 設備工作中最重要的就是三個模塊,正確識別,註冊中斷以及終端處理函數,數據傳輸。
完成以上三步一個硬件模塊的bringup就完成了。本文忽略了大部分細節,只爲了用最短的篇幅描述好PCIe。
MSI、MSI-X中斷和TLP這裏不詳細展開去說,必要的時候會帶出來。
首先用一張圖來直觀的呈現出要了解PCIe,我們需要知道的一些基本概念。
由於PCI/PCIe常見設備分爲Bridge和Agent兩種,這兩種設備的區分是寫在配置空間的header字段中的,所以配置空間也有兩種類型:
其中Agent的配置空間類型稱爲Type 00h,Bridge的配置空間,它的類型被稱爲Type 01h。
PCI/PCIe的配置地址空間Configuration Space是一個與Memory空間和IO空間並列的獨立的空間。
- 對Legacy PCI來講,Configuration Space有256 Bytes
- 對於PCIe, Configuration Space有4096 Bytes
BAR(Base Address Registers):決定PCI/PCIe設備空間映射到系統空間具體位置的寄存器,映射方式有兩種,分別是IO和Memory映射,因此配置空間的訪問方式也有兩種: - IO方式(CF8h/CFCh)
- Memory方式(ECAM)
https://blog.csdn.net/vc66vcc/article/details/81014637
https://blog.csdn.net/huangkangying/article/details/50570612
用華爲hisi的芯片來描述PCIe在linux中的驅動註冊過程,可以參考本文:https://blog.csdn.net/chengch512/article/details/52635736?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
參考文章鏈接:
https://www.cnblogs.com/szhb-5251/p/11620310.html
https://www.cnblogs.com/yangxingsha/p/11551472.html
https://blog.csdn.net/kunkliu/article/details/94380357
https://www.sohu.com/a/300238384_505795
https://blog.csdn.net/buyi_shizi/article/details/51068609
https://blog.csdn.net/abcamus/article/details/74157026
https://blog.csdn.net/abcamus/article/details/74157026
一個PCIe設備能夠被識別,大致需要經過以下步驟:
上述過程的詳細描述可以參考這個鏈接:
https://blog.csdn.net/maxwell2ic/article/details/90759280
https://blog.csdn.net/yijingjijng/article/details/48196531
上面的描述我們也能看到,一個設備之所以能夠被檢測並正確的識別,需要很多個過程,首先這個設備能夠從物理上被識別到。而識別到這個設備的第一個關鍵步驟就是物理層上能夠檢測到。在設備中按照OSI模型,都會有多個層次結構。對於PCIe同樣也不例外,下圖就是一個PCIe的層次結構。
此處只簡單描述下PHY層(也就是物理層)中的鏈路訓練狀態機(LTSSM,Link Training and Status State Mechine)。
主要包含五類狀態:
1 鏈路訓練狀態(Link Training State)
Detect
Polling
Configuration
2 重訓練狀態(Re-Training(Recovery)State)
Recovery
3 軟件驅動功耗管理狀態(Software Driven Power Managment State)
L2
L0
L1
4 活動狀態功耗管理狀態(Active-State Power Management State,ASPM State)
L1
L0s
5 其它狀態(Other State)
From Configuration or Recovery :Disabled\External Loopback。
From Recovery: Hot Reset。
具體我們可以通過這張圖來了解一下LTSSM:
這一部分更爲詳細的描述,我們可以通過這個鏈接來看:https://blog.csdn.net/kunkliu/article/details/94594501
以上是在理論層面上全面的瞭解了PCIe,具體我們在使用的過程中,需要通過軟件的方式來實現,從而能夠正確的被上層應用使用。
pci驅動在linux中的描述如下:
Once the driver knows about a PCI device and takes ownership, the
driver generally needs to perform the following initialization:
Enable the device
Request MMIO/IOP resources
Set the DMA mask size (for both coherent and streaming DMA)
Allocate and initialize shared control data (pci_allocate_coherent())
Access device configuration space (if needed)
Register IRQ handler (request_irq())
Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip)
Enable DMA/processing engines
When done using the device, and perhaps the module needs to be unloaded,
the driver needs to take the follow steps:
Disable the device from generating IRQs
Release the IRQ (free_irq())
Stop all DMA activity
Release DMA buffers (both streaming and coherent)
Unregister from other subsystems (e.g. scsi or netdev)
Release MMIO/IOP resources
Disable the device
PCIe的BAR地址是如何分配的呢?
在PCIE配置空間裏,0x10開始後面有6個32位的BAR寄存器,BAR寄存器中存儲的數據是表示PCIE設備在PCIE地址空間中的基地址,注意這裏不是表示PCIE設備內存在CPU內存中的映射地址,至於這兩者之間如何轉換,就是前面提到的TLP的工作。
枚舉的過程描述可以參考:
http://blog.chinaaet.com/justlxy/p/5100053320
https://blog.csdn.net/buyi_shizi/article/details/51068609枚舉
總結如下:
1 向BAR空間寫1。
2 讀取BAR值,確定地址空間大小和類型。
3 像高比特寫入地址空間地址(系統分配的)。