之前調試了幾個PCI網卡驅動,雖然功能沒什么問題,但驅動中調用的某些內核提供的PCI相關的接口一直沒搞太清楚,所以最近準備深入研究一把。
PCI設備的識別及配置方式
PCI總線使用單端并行數據總線,采用地址譯碼方式進行數據傳遞,而采用ID譯碼方式進行配置信息(比如配置某個PCI設備的物理地址)的傳遞。其中地址譯碼方式使用地址信號,而ID譯碼方式使用PCI設備的ID號,包括Bus Number、Device Number、Function Number和Register Number。Linux系統中使用了Bus Number、Device Number和Function Number區分不同的設備;對于有兩個接口的網卡,Linux會按照兩個設備處理,因為這兩個接口會呈現出不同的Function Number。
Posted和Non-Posted傳送方式
PCI總線規定了兩類數據傳送方式,分別是Posted和Non-Posted數據傳送方式。又分別對應了Posted和Non-Posted總線事務。
Posted總線事務指PCI主設備向PCI目標設備進行數據傳遞時,當數據到達PCI橋后,即由PCI橋接管來自上游總線的總線事務,并將其轉發到下游總線。采用這種數據傳遞方式,在數據還沒有到達最終的目的地之前,PCI總線就可以結束當前總線事務,從而在一定程度上解決了PCI總線的擁塞問題,所以這種方式的PCI總線利用率較高。只有存儲器寫請求可以采用Posted總線事務,簡稱為PMW(Posted Memory Write)。
Non-Posted總線事務是指PCI主設備向PCI目標設備進行數據傳遞時,數據必須到達最終目的地之后,才能結束當前總線事務的一種數據傳遞方式。存儲器讀請求、I/O讀寫請求、配置讀寫請求只能采用Non-Posted總線事務。
中斷請求和數據傳送的同步問題(MSI中斷機制不存在這個問題)
在PCI總線中,INTx信號是一個異步信號。所謂異步,是指INTx信號的傳遞并不與PCI總線的數據傳送同步。假設某個PCI設備在使用DMA方式將一組數據寫入存儲器,該設備在最后一個數據離開自己的發送FIFO時,即認為DMA操作已經完成。此時這個設備將通過INTx信號,通知處理器DMA寫操作完成。
但是,當處理器收到INTx信號時,并不意味著PCI設備已經將數據寫入存儲器中,因為PCI設備的數據傳遞需要經過PCI橋/HOST主橋,最終才能到達存儲器。
PCI總線提供了以下兩種方法解決這個同步問題。
(1)PCI設備保證在數據到達目的地之后,再提交中斷請求。具體來說,PCI設備在提交中斷請求之前,向DMA寫的數據區域發出一個讀請求。PCI總線的“序”機制,保證了在這個存儲器讀請求完成前,會將以前發出的DMA數據寫入存儲器。PCI總線規范要求HOST主橋和PCI橋必須保證這種讀操作可以刷新寫操作。但問題是,沒有多少芯片設計者愿意提供這種機制,因為這將極大地增加他們的設計難度。除此之外,使用這種方法也將增加中斷請求的延時。
(2)中斷服務程序在使用“PCI設備寫入存儲器”的這些數據之前,需要對這個PCI設備進行讀操作。這個讀操作也可以強制將數據最終寫入存儲器。這種方法也是利用了PCI總線的傳送序規則,與第1種方法類似。只是這種方法使用軟件方式,而第1種方式使用硬件方式。這是絕大多數處理器系統采用的方法。在中斷服務程序中,往往都是先讀取PCI設備的中斷狀態寄存器,判斷中斷產生原因之后,才對PCI設備寫入的數據進行操作。這個讀取中斷狀態寄存器的過程,一方面可以獲得設備的中斷狀態,另一方面可以保證DMA寫的數據(在被CPU讀取前)已經到達存儲器。
PCI配置空間中的幾個寄存器的作用
(1)Cache Line Size寄存器:記錄HOST處理器使用的Cache Line長度。在PCI總線中和Cache相關的總線事務,如存儲器寫并無效和Cache多行讀等總線事務需要使用這個寄存器。該寄存器由系統軟件設置,但是在PCI設備的運行過程中,只有其硬件邏輯才會使用該寄存器。對于PCIe設備,該寄存器的值無意義,因為PCIe設備在進行數據傳送時,在其報文中含有一次數據傳送的大小,PCIe總線控制器可以使用這個“大小”,判斷數據區域與Cache Line的對應關系。
(2)Interrupt Line寄存器:由系統軟件對PCI設備進行配置時寫入,記錄當前PCI設備使用的中斷向量號。設備驅動程序可以通過這個寄存器,判斷當前PCI設備使用處理器中的哪個中斷向量號,并將驅動程序中的中斷服務例程注冊到操作系統中。但是,目前在絕大多數處理器系統中,并沒有使用該寄存器存放PCI設備使用的中斷向量號。
(3)Base Address Register 0~5 寄存器:簡稱為BAR寄存器。保存的是PCI設備在PCI總線域中的基地址,由操作系統配置。在PCI設備復位之后,該寄存器將存放PCI設備需要使用的基址空間大小、這段空間是I/O空間還是存儲器空間、如果是存儲器空間是否可預取等。
系統軟件對PCI總線進行配置時,先獲取BAR寄存器中的初始化信息,之后根據處理器系統的配置,將合理的基地址寫入相應的BAR寄存器中。系統軟件還可以使用該寄存器獲得PCI設備使用的BAR空間的長度,方法是向BAR寄存器中寫入0xFFFFFFFF,然后再讀取該寄存器。
(4)Command寄存器:在初始化時,其值為0,此時這個PCI設備除了能夠接收配置請求總線事務外,不能接收任何存儲器或者I/O請求。在Linux系統中,設備驅動程序調用pci_enable_device函數(也可以是pci_enable_device_mem-> pci_enable_device_flags-> do_pci_enable_device-> pcibios_enable_device-> pci_enable_resources-> pci_write_config_word),使能該寄存器的I/O和Memory Space位之后,才能訪問該設備的存儲器或者I/O地址空間。
另外,該寄存器中還有Bus Master位表示該設備是否可以作為主設備(Linux驅動程序中調用pci_set_master函數,將此位設置為1,表示設備可作為master)。寄存器中的Interrupt Disable位默認為0,為1時表示不允許該設備使用INTx信號提交中斷請求,當PCI設備使用MSI中斷方式時,該位將被設置為1(Linux驅動程序中調用的函數為pci_alloc_irq_vectors-> pci_alloc_irq_vectors_affinity-> __pci_enable_msi_range-> msi_capability_init-> pci_intx_for_msi-> pci_intx)。
Linux的PCI設備驅動程序中調用的dma_set_mask_and_coherent函數有什么作用
Linux的PCI設備驅動中一般都會調用諸如dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))之類的接口。這是用來通知內核當前設備支持的DMA訪問的尋址能力,作用是限制內核為當前設備分配的內存地址范圍。比如之前的例子就表示當前設備支持64位尋址,并且在此范圍內支持一致性DMA訪問。
Linux的PCI設備驅動程序中調用的pci_disable_link_state函數有什么作用
有些PCI設備的驅動中會調用諸如pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM)之類的接口。其作用是設置PCIe設備的擴展配置空間中的Link Control寄存器。具體到前例,是把Link Control寄存器中的“ASPM Control”字段和“Enable clkreq”字段設置為0,作用分別是禁止PCI設備進入L0s和L1(低功耗)狀態以及禁止CLKREQ功能(相當于禁止設備的時鐘管理功能,起到性能優先的效果,不考慮省電;具體效果還取決于內核中CONFIG_PCIEASPM_XXXX相關的配置)。
-
網卡
+關注
關注
4文章
313瀏覽量
27429 -
PCI
+關注
關注
4文章
671瀏覽量
130418 -
總線
+關注
關注
10文章
2900瀏覽量
88294
發布評論請先 登錄
相關推薦
評論