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