標籤

2009年10月21日 星期三

Speed Step

關於1A0(IA32_MISC_ENABLE)以及199(IA32_PERF_CTL),198(IA32_PERF_STATUS),自己project的CPU一定有Spec可以看到的,如果沒有就向Intel的FAE要吧。
; R9 m5 }% ^0 u9 q6 D計匠網論壇IA-32 ASDM volume 3也提到一點點,特別是1A0(IA32_MISC_ENABLE).
/ Y' s* D' A7 i+ |www.ufoit.com
! f& c, E/ n- [6 g5 p oBIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC對於Intel speedstep,我這裡摘抄一篇深圳頂星數碼的同志所發表一篇絕好的技術簡介文檔給你做參考。
1 V3 z' r& x1 s' i$ [0 }4 Q7 vBIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC
; S8 u0 |3 ?8 z2 m2 U( o& d* y H計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC

英特爾增強SpeedStep技術簡介BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC; V+ d7 i+ \3 Q6 J' t
來自:http://www.topstardigital.cn/TechIntro-14.htm

www.ufoit.com# g& @1 a# D/ {. u
計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC# |8 ~% h8 i: F0 G' X
對於英特爾的SpeedStep節能技術,很多人可能已不再陌生。SpeedStep技術是一項旨在徹底區分台式機CPU與筆記本電腦專用CPU的性 能,並與系統運行速度有密切關係的新技術,原來的代號是「Geyserville」。簡單地說,採用SpeedStep技術的筆記本電腦,可以根據不同的 使用環境,對CPU的運行速度進行合理調整。SpeedStep技術的基本工作過程是:如果筆記本電腦使用的是外接電源,CPU將按照正常的主頻率及電壓 運行;當專用軟件檢測到筆記本電腦切換到電池電源供電時,將自動切換筆記本電腦CPU的主頻率及電壓至較低運行狀態;當筆記本電腦恢復使用外接電源 時,CPU又自動切換回到最高主頻率及正常電壓下工作,使之全速運行。從技術上分析可知,同一處理器工作時,運行速度越快,工作電壓越高,功耗也越大;相 反,處理器的運行速度降低後,工作電壓會降低,功耗和發熱量也會降低。 BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC, R, j- `: Y1 `, g" @% s

; _0 U4 k, v( R" g1 x8 }1 Z* [# r# m計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC在 去年(2003年),英特爾又推出了內部代號為「Geyserville III」的增強SpeedStep技術,首先在Pentium M處理器實現,支持的平台包括Odem和Motora等855系列芯片組。其與原有的SpeedStep主要有兩點區別:第一點,增強的 SpeedStep(簡稱EIST)使得原有的性能等級從兩階增加到多階,是的性能切換更加靈活,例如,1.4G Pentium 4M的有600M和1.4G兩檔,但是對於支持1.4G Pentium M處理器而言,就有600M、800M、1G、1.2G和1.4G五個頻率檔次。第二點,增強的SpeedStep可以直接通過對處理器的MSR寄存器編 程來實現頻率,大大減少了頻率切換時間,而原來的SpeedStep依賴於對Chipset的IO端口編程實現,所以切換延時較大。計匠網論壇/ L8 } I+ r! x
BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC/ b6 r# g/ m' B3 y. v4 l% ?8 E
下面我們簡單介紹一下對於SpeedStep的支持固件編程相關知識。計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC0 S, L3 M& R0 |) F' y( B I
www.ufoit.com, r, Q+ A4 ]9 K7 `9 u
我們知道,處理器的性能狀態是由離散的電壓和頻率對定義的。在不同的頻率和電壓下,處理器的執行性能也是不同。EIST提供了一個全新的方法來改變 CPU的性能狀態,這種方法本身是基於CPU MSR寄存器,而不是基於Chipset的,所以這種方法具有硬件軟件的轉變過渡時間少、系統設計簡單等特點。Intel的奔騰M處理器提供了兩個MSR 寄存器來實現EIST功能,一個是IA32_PERF_CTL和IA32_PERF_STS,我們通過寫IA32_PERF_CTL來實現CPU性能的狀 態轉變,主要是設置BUS_RATIO_SEL和VID_SEL位域。一旦設置完之後,CPU隨後馬上進行RATIO和VID的切換,如果在切換的過程中 間有新的值更新IA32_PERF_CTL寄存器,那麼,在CPU完成系統狀態切換之後,CPU馬上進行本次新的性能切換。
4 l/ a; U. ~& ]* ^. U計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC
* e3 f$ K9 U) |( W2 u) W: U 如果我們讀取IA32_PERF_CTL,這只表明上次更新所期望的CPU性能置,並不表示CPU的當前性能值,因為,如果CPU處在thermal throttle的過程中,那麼,CPU會暫停性能的切換,直到thermal throttle的結束。& O9 y8 V$ F1 L/ r) }( U

' h) f6 h1 }) _計匠網論壇 如果我們想確定CPU的當前性能狀態,我們可以通過讀取IA32_PERF_STS寄存器的值來確定。這個寄存器包括一些主要信息,如 BUS_RATIO_STS和VID_STS域表明當前的頻率和電壓值,這些信息是動態更新的。這個寄存器同樣也包括了系統BOOT時和系統所支持的最大 性能點。 BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,計算機研發,EC資料,EC開發,PS/2,KBC5 y* h- K: e1 \2 J& z
BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC) y7 P" I1 p' `* L, ]( g8 G
在Windows XP下,OS查找PSS表,找出其想進入的狀態,查找控制值,然後把控制值寫入控制寄存器中間。系統有兩種方式進入實現控制動作,一種是透過SMM模式進 行,一種是OSPM通過G3寄存器直接寫。到底是採用哪種方式依靠_PCT這個對象決定。而在_PCT內部,實際上是根據系統OSPM的性能確定返回哪種 控制方式的,也就是採用SMM Model和Processor Native Mode。BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC" F! L* n! u( ]
BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC9 F9 V3 m7 X6 F6 D5 u! q5 ?7 |
我們知道,OS是這樣實現處理器性能的控制的,首先,OSPM通過ACPI表得知系統支持的處理器狀態,然後OSPM根據其對於系統當前狀態的評估,確 定進入哪種處理器狀態。在確定進入何種狀態之後,OSPM決定這種方法是否是其支持的方法,否則回去調用CPU的驅動程序完成相關動作。一般OSPM直接 支持的方法就是IO之類的傳統方法。 計匠網論壇6 u o! B- @' o7 {

$ x; w2 X: {9 _! v3 M* \BIOS技術網站,BIOS技術論壇,BIOS入門,BIOS開發,計算機研發,EC資料,EC開發,PS/2,KBC 所 以,如果OSPM不是透過SMM去完成對於MSR的IA32_PERF_CTL和IA32_PERF_STS操作,那麼,OSPM必須去調用處理器的驅動 程序,驅動程序的存在必須告知ACPI,使得ACPI的_PCT的返回是直接對於IA32_PERF_CTL和IA32_PERF_STS操作,而這是依 賴於_PDC這個方法完成的,_PDC是OSPM用來告訴ACPI其是否支持直接對於IA32_PERF_CTL和IA32_PERF_STS操作,是 OSPM向ACPI傳遞消息的一種途徑。
# S3 c3 q0 o& R5 hwww.ufoit.com計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC% h' ^" P8 v4 U7 w' o
_FDC是OSPM在進行所有處理器操作之前首先調用的一個方法,這個方法有處理器的驅動程序向ACPI傳送一個DWORD的變量,這個變量包含由處理器 廠商定義的格式,對於不同處理器的能力。根據_FDC傳遞過來系統軟件支持的能力,ACPI調整_PCT和PSS方法。計算機研發論壇,BIOS技術網站,BIOS技術論壇,BIOS SPEC,BIOS手冊,BIOS入門,ACPI,SMBIOS,BIOS技術,EC資料,EC開發,PS/2,KBC5 @6 Y: p4 f' \/ \ e3 Q) V

; f$ E+ u" G" R' Y" X* z 支持Intel EIST的_FDC的工作原理是這樣的,缺省的,系統BIOS是採用IO地址映射的方式提供_PCT和_PSS的,也就是SMM方式操作CPU的MSR寄 存器直接對IA32_PERF_CTL和IA32_PERF_STS操作。如果沒有處理器驅動程序去調用_PDC這樣,通過系統ACPI、SMI服務例程 和處理器的服務程序,我們可以實現EIST所帶來的優點,達到性能和節電的兼顧。

2009年10月14日 星期三

PCI CLKRUN# & PCIE CLKREQ#

http://www.ufoit.com/bbs/thread-103-1-4.html

PCI設備的Pin定義上有CLOCK RUN這個Option信號.
PCI Express設備有定義CLOCK REQUEST這個Option信號.這兩個信號為了省電的目的而設的.

先看PCI的CLKRUN#,如下圖:

如果PCI Deivce A和B,某個或全部設備在工作時,會激活(low) CLKRUN#,HOST會檢測CLKRUN#是否在活動狀態,如果在活動狀態,那麼.就不驅動STOP PCI的信號給時鐘產生器(Clock generator).如果PCI Deivce A和B都不工作,就會不激活(High) CLKRUN#,HOST在檢測CLKRUN#狀態時,發現沒有任何PCI設備在活動當中.當幾個PCI CLK之後(一般四個左右),就會激活STOP PCI#,讓時鐘產生器放慢或停止產生PCI CLOCK給A和B。如果當A或B設備某一個設備需要處理數據,就會再次激活CLKRUN#,HOST檢測到CLKRUN#活動時,立即停止驅動STOP PCI,時鐘產生器就會立即恢復所有PCI的CLOCK。----當然這僅僅是一種平台的情況。

再看PCI Express CLKREQ#,如下圖:

如果A設備有支持CLKREQ#,那麼在A設備在需要時鐘時,就會驅動CLKREQ#,如果不需要,就不會再驅動CLKREQ#,B設備同理。當然PCIE的CLOCK控制多了幾個Option的信號,複雜一點。具體看SPEC。

詳細資料請翻閱PCI SPEC 3.0以及PCIE spec 2.0

2009年8月31日 星期一

PCIE ASPM

http://www.mem.com.tw/technologyexploring_content.asp?sn=0701020591

PCI-E專欄:PCI Express省電模式剖析 行動平台決戰電池續航力
新電子 2006 年 1 月號 238 期
文.Steve Kolokowsky/Trevor Davis

桌上型與筆記型電腦的演進永無止境,事實上,在討論筆記型電腦或桌上型電腦時,總是會出現 「更快」、「更輕巧」、或 「功能更強」等字眼。我們總是盤算下次何時為系統進行升級,希望在最快的電腦上讓應用程式發揮更大的效能...
桌上型與筆記型電腦的演進永無止境,事實上,在討論筆記型電腦或桌上型電腦時,總是會出現 「更快」、「更輕巧」、或「功能更強」等字眼。我們總是盤算下次何時為系統進行升級,希望在最快的電腦上讓應用程式發揮更大的效能。本文將討論PCI Express新開發的省電模式,此項優勢將協助PCI Express在行動平台方面的普及。

在先前的技術專文中闡述PCI Express存在的重要性,並指出此傳輸技術將全面改變桌上型與筆記型電腦的運作模式,然而有一個尚未討論的問題—那就是PCI Express技術的功耗問題。

行動運算有四大考量因素:記憶體、重量、儲存容量,以及電池續航力。記憶體通常是以Mb或Gb為計量單位,重量則是以盎司計算,儲存容量則以Gb為單位,而電池續航力則是以個人使用的狂熱程度來衡量。這之間的差別在於電池續航力的量測是很主觀的,因為每位使用者不同的使用方式都會影響電持續航力的測量結果。其他項目的量測都能做到相當客觀,例如80Gb硬碟機絕對就只有80Gb的容量;而它的重量是6.5磅,那就是6.5磅,一點也不會少算,但談到電池續航力,就有眾多量測的方法。

事實上,目前有許多不同的「業界標準」方法來測試電池續航力,圖1顯示戴爾電腦在量測搭載Intel Pentium III處理器的Dell Latitude筆記型電腦電池續航力時,其所產生的量測圖表。

圖1顯示戴爾電腦對其產品進行許多標準測試。現今數項主流電池續航力效能量測指標包括BWS BatteryMark、Winstone 2004 Battery-Mark及MobileMark 2002。在日本業界有其電池續航力檢測標準,也就是日本電子與資訊科技產業協會(JEITA)所制定的標準。想像一下在全球眾多廠商致力於延長電池續航力之際,PCI Express方面所產生的變化將會對他們的計畫產生怎樣的影響?

現今普遍致力於如何將筆記型電腦的尺寸變小,再加上大家對於電池續航力的見解與看法大相逕庭的情況之下,導致科技的運用必須著重於系統開發的焦點-電池續航力。設計業者已事先預知此種市場需求,因此當他們在開發PCI Express時就將這些限制納入考量。

PCI Express事先規畫省電效率

標準平行的PCI介面納入許多遵循PCI匯流排電源管理介面規格的省電功能,因此,除了根聯合體(Root Complex)之外,其他所有的PCIe裝置都必須支援這些省電功能。此外,PCIe定義一套名為主動式電源管理(Active State Power Management, ASPM)的機制。主動式電源管理則是進一步擴充PCI電源的管理規格。ASPM與標準PCI電源管理規格之間的主要差別在於ASPM是自動運作的機制。

以往的省電設計中,主機軟體必須與裝置控制器進行互動,相互協調出適合的省電設定。USB就是很好的例子,主機驅動程式必須告訴主機控制器停止傳送開始欄位(Start of Frame, SOF)封包,USB裝置才能切換至低耗電模式。當主機一旦停止傳送SOF封包,USB裝置的耗電量就會大幅降低,從500mA降低至500μA。但由於研判何時關閉這些連結埠的程序相當複雜,Windows主機軟體只有在整部個人電腦進入閒置狀態時,才會讓USB匯流排暫停運作。

另一方面,想像一下,主機在這些裝置進入閒置狀態時,才能關閉這些裝置的運作會是怎樣的狀況?例如除非移動滑鼠,否則滑鼠不會消耗任何電力;另一個例子是試圖存取外接式硬碟時,外接硬碟機才會被啟動。因此,桌上型電腦會變得比較安靜,筆記型電腦會變得更輕巧,而筆記型電腦的電池續航力也會延長一點。

PCIe的ASPM則是能做到接近這種的理想作法,ASPM不需要主機、裝置或者驅動程式的互動,就能自動控制連結狀態。因此,這種設計讓連結能在不論多短暫閒置時間也可立即切換至低耗電狀態。自動電源控制機制亦能縮短連結回覆至全面運作模式延遲時間。

PCIe定義五種電源模式,其中包括正常運作到完全關機模式:

.L0 — 正常運作

.L0s —連結待機

.L1 — 連結閒置

.L2 — 僅啟用輔助電源

.L3 — 關閉電源,裝置關機

PCI Express REV1.1基礎規格

.一個「Yes」的指令即表示須要支援(除非另有說明)、「On」及「Off」的指令表示需要時脈及電源輸送、「On / Off」表示一個設計選擇項目。

PCI Express連結電源管理狀況

L0—正常運作:在L0模式下,連結處在全線運作狀態,所有時脈都啟用,任何傳輸作業都在正常延遲速度下進行,所有裝置都必須支援這種模式。

L0s—連結待機:所有PCIe系統都必須支援L0s模式,在L0s模式中,時脈都維持運作,電源亦保持開啟狀態,但連結不會主動傳送資料。這也意謂著連結從L0s模式回覆正常模式的時候時,必須要重新啟動,但回覆過程的延遲相當短暫。裝置在從L0s回覆時有不同的延遲時間,但是其變幅相當小。連接功能暫存器中定義的L0s延遲範圍為64ns至4μs。

L0s有許多優點,由於不需要端點對端點的互動就能進入L0s模式,因此切換的速度相當快。由於時脈訊號依然保持運作狀態,因此離開的速度也相當快。此外,它能套用至連結的某一端(傳送或接收端),另一端仍能繼續運作。這意謂著系統從一端傳送資料時,在大多數的時間會自動獲得L0s的協助,但在送出訊框完成(FC)封包以及通知(ACK)封包時,連結就會被喚醒。L0s的缺點是時脈訊號一直呈現運作狀態,因此L0s模式會耗用不少電力。

傳送器僅須傳送Electrical Idle指令集,並將PCIe鏈路置於電力待機狀態,就能將接收端置入L0s模式。Electrical Idle指令集是少數在實體層中進行解譯名為Ordered Set的PCIe訊息。Ordered Set指令集長度有四個字元,因此要將連結置入L0s模式時,需要的時間為4×10bits×400ps= 16ns,因此這是相當短的延遲。

因此,從L0s回覆至正常模式也會相當地快,傳送器只須在連結上傳送幾個Fast Training Sequence(FTS)Ordered Sets的指令集,連結就會回覆至正常模式。而且,接收器可以指定要從範圍在1到255的L0s回覆所需的FTS數量。因此,其連結便可以在16ns至 4ms間從L0s回覆至正常的模式,實際時間則視接收器的功能以及時脈來源而定。

L1—低耗電待機模式:L1則是PCIe的一種選項功能,其省電效率遠超過L0s,但是缺點就是延遲時間較為長久。在L1模式中,PCIe參考時脈訊號維持不變,但PCIe裝置使用的內部相鎖迴路(PLL)則被關閉,這種設計讓省電效率得以超越L0s,但卻衍生出較長的延遲和較高的傳輸佔量 (Overhead)。當下游裝置切換至PCI電源管理模式(D1~D3)或是當裝置已準備好透過上述自動電源控制機制ASPM進入L1模式時(圖2),系統就會進入L1模式。由於連結的兩端都須參與作業,因此進入L1模式所涉及的端點對端點互動步驟比進入L0s模式還要多。圖3顯示進入L1模式所需進行的互動步驟。在這個例子中,下游連結埠被指示進入L1模式,並將負責管理傳輸作業。鏈路的其中一端或兩端都可以發出指令,讓鏈路從L0模式轉換至L1模式。

首先,下游連結埠的電源管理邏輯欄位要求進入L1模式,為了要進入L1模式,該連結埠必須:

.阻擋新的傳輸層封包(TLP)傳輸作業

.確定回覆緩衝區已清空資料

.確定已收到足夠的流量控制權限,以便能在每個虛擬通道(VC)與每種資料流上達到最高容量的傳輸

因此,當所有條件都符合的時候,其中下游的連結埠就會開始持續傳送一個PM Active State Request L1的資料鏈結層封包(DLLP),最後直到收到PM Request Ack DLLP為止。在此同時,在上游部份,當收到PM Active State Request L1 DLLP的時候,就會觸發一連串的事件,該連結埠必須:

.阻斷新的傳輸層封包(TLP)傳輸作業

.等待回傳緩衝區清空資料

.等待收到足夠的流量控制權限,以便能在每個虛擬通道(VC)與每種資料流上達到最高容量的傳輸

當上游元件符合所有條件的時後,就會開始傳送一個PM Request Ack DLLP,這個訊號會觸發下游元件轉移至L1模式,並且透過上述的程序使得連結切換至閒置狀態。當連結的上游端收到切換至電源閒置模式的訊號時,它就會進入電源閒置模式。

這種程序看似複雜,但全部都是由PCIe狀態機器負責執行,如果裝置支援L1 ASPM機制,主機軟體甚至完全不必執行任何作業。這就是PCIe電源管理技術的優點。連結的任何一端皆可以讓連結離開L1狀態(圖3),當裝置決定要離開L1模式時,就會開始傳送TS1指令集到連結的另一端。回覆程序會迅速回覆連結的時序,並確保連結的實際參數跟連結關閉時完全一樣,從L1模式回覆所需的時間不到64ms,這個過程的時間愈短代表連結消耗的電力愈少。

L2—輔助電源模式:除了關閉裝置上所有電源外,L2模式是耗電量最低的狀態。在L2模式中,所有裝置的時脈訊號都處在閒置狀態,只剩下用來偵測網路喚醒功能(WAKE)與信標(Beacon)事件的低頻時脈。系統只能利用VAUX為裝置提供電力。若WAKE被啟動時,VAUX則供應高達375mA的電流,若WAKE關閉時,VAUX則只供應20mA的電流,進入L2模式與進入L1模式非常類似,兩者間只有以下差異:

.L2無法透過ASPM來觸發,只能由主機來觸發

.L2模式進入協定會將連結切換至「L2_ready」 狀態。當主機看到下游連結處於L2模式時,就會移除VMAIN。

.裝置須要運用更多的電源關閉步驟來進入L2模式

等候狀態、連結層傳輸、通訊協定電源規畫等,這些都是為了延長電池續航力所需要的關鍵要素。可攜式電子產品節省電力的關鍵在於縮短產品處理作業上的時間,以及縮短元件之間傳輸作業的時間,如此,電子裝置在標準運作模式下的耗電量就愈低。更確切地說,可攜式裝置進出各種作業的速度愈快,省電效率就愈高。為達到這項目標,在開發裝置必須考量PCI Express的能力。

就目前而言,許多業者等候PCI Express大舉進軍桌上型電腦與伺服器產品,根據上述特別的考量因素,PCI Express一直在開發電源敏感度協定。因此,當看到設計業者及工程師將PCI Express視為注重電池續航力的高速資料連結理想介面時,也毋須覺得訝異。考慮到人們對於「更快」、「更輕巧」,以及「功能更強勁」的看法永遠無法一致,業者在開發未來的筆記型電腦與可攜式運算裝置之際,PCI Express必然成為資料連結的最佳選擇。

(本文作者任職於Cypress Semiconductor)

(詳細圖表請見新電子238期1月號)


http://patchwork.kernel.org/patch/42481/

The L0s state can be managed separately for each direction (upstream
direction and downstream direction) of the link. But in the current
implementation, those are mixed up. With this patch, L0s for each
direction are managed separately.

To maintain three states (upstream direction L0s, downstream L0s and
L1), 'aspm_support', 'aspm_enabled', 'aspm_capable', 'aspm_disable'
and 'aspm_default' fields in struct pcie_link_state are changed to
3-bit from 2-bit. The 'latency' field is separated to two 'latency_up'
and 'latency_dw' fields to maintain exit latencies for each direction
of the link. For L0, 'latency_up.l0' and 'latency_dw.l0' are used to
configure upstream direction L0s and downstream direction L0s
respectively. For L1, larger value of 'latency_up.l1' and
'latency_dw.l1' is considered as L1 exit latency.

Signed-off-by: Kenji Kaneshige

---
drivers/pci/pcie/aspm.c | 170 ++++++++++++++++++++++++++++++------------------
1 file changed, 107 insertions(+), 63 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html



Index: 20090818/drivers/pci/pcie/aspm.c
===================================================================
--- 20090818.orig/drivers/pci/pcie/aspm.c
+++ 20090818/drivers/pci/pcie/aspm.c
@@ -26,6 +26,13 @@
#endif
#define MODULE_PARAM_PREFIX "pcie_aspm."

+/* Note: those are not register definitions */
+#define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */
+#define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */
+#define ASPM_STATE_L1 (4) /* L1 state */
+#define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW)
+#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1)
+
struct aspm_latency {
u32 l0s; /* L0s latency (nsec) */
u32 l1; /* L1 latency (nsec) */
@@ -40,19 +47,20 @@ struct pcie_link_state {
struct list_head link; /* node in parent's children list */

/* ASPM state */
- u32 aspm_support:2; /* Supported ASPM state */
- u32 aspm_enabled:2; /* Enabled ASPM state */
- u32 aspm_capable:2; /* Capable ASPM state with latency */
- u32 aspm_default:2; /* Default ASPM state by BIOS */
- u32 aspm_disable:2; /* Disabled ASPM state */
+ u32 aspm_support:3; /* Supported ASPM state */
+ u32 aspm_enabled:3; /* Enabled ASPM state */
+ u32 aspm_capable:3; /* Capable ASPM state with latency */
+ u32 aspm_default:3; /* Default ASPM state by BIOS */
+ u32 aspm_disable:3; /* Disabled ASPM state */

/* Clock PM state */
u32 clkpm_capable:1; /* Clock PM capable? */
u32 clkpm_enabled:1; /* Current Clock PM state */
u32 clkpm_default:1; /* Default Clock PM state by BIOS */

- /* Latencies */
- struct aspm_latency latency; /* Exit latency */
+ /* Exit latencies */
+ struct aspm_latency latency_up; /* Upstream direction exit latency */
+ struct aspm_latency latency_dw; /* Downstream direction exit latency */
/*
* Endpoint acceptable latencies. A pcie downstream port only
* has one slot under it, so at most there are 8 functions.
@@ -84,7 +92,7 @@ static int policy_to_aspm_state(struct p
return 0;
case POLICY_POWERSAVE:
/* Enable ASPM L0s/L1 */
- return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
+ return ASPM_STATE_ALL;
case POLICY_DEFAULT:
return link->aspm_default;
}
@@ -278,36 +286,35 @@ static u32 calc_l1_acceptable(u32 encodi
return (1000 << encoding);
}

-static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state,
- u32 *l0s, u32 *l1, u32 *enabled)
+struct aspm_register_info {
+ u32 support:2;
+ u32 enabled:2;
+ u32 latency_encoding_l0s;
+ u32 latency_encoding_l1;
+};
+
+static void pcie_get_aspm_reg(struct pci_dev *pdev,
+ struct aspm_register_info *info)
{
int pos;
u16 reg16;
- u32 reg32, encoding;
+ u32 reg32;

- *l0s = *l1 = *enabled = 0;
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32);
- *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
- if (*state != PCIE_LINK_STATE_L0S &&
- *state != (PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S))
- *state = 0;
- if (*state == 0)
- return;
-
- encoding = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
- *l0s = calc_l0s_latency(encoding);
- if (*state & PCIE_LINK_STATE_L1) {
- encoding = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
- *l1 = calc_l1_latency(encoding);
- }
+ info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
+ /* 00b and 10b are defined as "Reserved". */
+ if (info->support == PCIE_LINK_STATE_L1)
+ info->support = 0;
+ info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
+ info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16);
- *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+ info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
}

static void pcie_aspm_check_latency(struct pci_dev *endpoint)
{
- u32 l1_switch_latency = 0;
+ u32 latency, l1_switch_latency = 0;
struct aspm_latency *acceptable;
struct pcie_link_state *link;

@@ -320,18 +327,24 @@ static void pcie_aspm_check_latency(stru
acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)];

while (link) {
- /* Check L0s latency */
- if ((link->aspm_capable & PCIE_LINK_STATE_L0S) &&
- (link->latency.l0s > acceptable->l0s))
- link->aspm_capable &= ~PCIE_LINK_STATE_L0S;
+ /* Check upstream direction L0s latency */
+ if ((link->aspm_capable & ASPM_STATE_L0S_UP) &&
+ (link->latency_up.l0s > acceptable->l0s))
+ link->aspm_capable &= ~ASPM_STATE_L0S_UP;
+
+ /* Check downstream direction L0s latency */
+ if ((link->aspm_capable & ASPM_STATE_L0S_DW) &&
+ (link->latency_dw.l0s > acceptable->l0s))
+ link->aspm_capable &= ~ASPM_STATE_L0S_DW;
/*
* Check L1 latency.
* Every switch on the path to root complex need 1
* more microsecond for L1. Spec doesn't mention L0s.
*/
- if ((link->aspm_capable & PCIE_LINK_STATE_L1) &&
- (link->latency.l1 + l1_switch_latency > acceptable->l1))
- link->aspm_capable &= ~PCIE_LINK_STATE_L1;
+ latency = max_t(u32, link->latency_up.l1, link->latency_dw.l1);
+ if ((link->aspm_capable & ASPM_STATE_L1) &&
+ (latency + l1_switch_latency > acceptable->l1))
+ link->aspm_capable &= ~ASPM_STATE_L1;
l1_switch_latency += 1000;

link = link->parent;
@@ -340,33 +353,48 @@ static void pcie_aspm_check_latency(stru

static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
{
- u32 support, l0s, l1, enabled;
struct pci_dev *child, *parent = link->pdev;
struct pci_bus *linkbus = parent->subordinate;
+ struct aspm_register_info upreg, dwreg;

if (blacklist) {
/* Set enabled/disable so that we will disable ASPM later */
- link->aspm_enabled = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
- link->aspm_disable = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
+ link->aspm_enabled = ASPM_STATE_ALL;
+ link->aspm_disable = ASPM_STATE_ALL;
return;
}

/* Configure common clock before checking latencies */
pcie_aspm_configure_common_clock(link);

- /* upstream component states */
- pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled);
- link->aspm_support = support;
- link->latency.l0s = l0s;
- link->latency.l1 = l1;
- link->aspm_enabled = enabled;
-
- /* downstream component states, all functions have the same setting */
+ /* Get upstream/downstream components' register state */
+ pcie_get_aspm_reg(parent, &upreg);
child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
- pcie_aspm_get_cap_device(child, &support, &l0s, &l1, &enabled);
- link->aspm_support &= support;
- link->latency.l0s = max_t(u32, link->latency.l0s, l0s);
- link->latency.l1 = max_t(u32, link->latency.l1, l1);
+ pcie_get_aspm_reg(child, &dwreg);
+
+ /*
+ * Setup L0s state
+ *
+ * Note that we must not enable L0s in either direction on a
+ * given link unless components on both sides of the link each
+ * support L0s.
+ */
+ if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
+ link->aspm_support |= ASPM_STATE_L0S;
+ if (dwreg.enabled & PCIE_LINK_STATE_L0S)
+ link->aspm_enabled |= ASPM_STATE_L0S_UP;
+ if (upreg.enabled & PCIE_LINK_STATE_L0S)
+ link->aspm_enabled |= ASPM_STATE_L0S_DW;
+ link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
+ link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s);
+
+ /* Setup L1 state */
+ if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1)
+ link->aspm_support |= ASPM_STATE_L1;
+ if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1)
+ link->aspm_enabled |= ASPM_STATE_L1;
+ link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
+ link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);

/* Save default state */
link->aspm_default = link->aspm_enabled;
@@ -379,8 +407,7 @@ static void pcie_aspm_cap_init(struct pc
*/
list_for_each_entry(child, &linkbus->devices, bus_list) {
if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
- link->aspm_disable =
- PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
+ link->aspm_disable = ASPM_STATE_ALL;
break;
}
}
@@ -409,19 +436,20 @@ static void pcie_aspm_cap_init(struct pc
}
}

-static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 state)
+static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
{
u16 reg16;
int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);

pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16);
reg16 &= ~0x3;
- reg16 |= state;
+ reg16 |= val;
pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
}

static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
{
+ u32 upstream = 0, dwstream = 0;
struct pci_dev *child, *parent = link->pdev;
struct pci_bus *linkbus = parent->subordinate;

@@ -429,20 +457,27 @@ static void pcie_config_aspm_link(struct
state &= (link->aspm_capable & ~link->aspm_disable);
if (link->aspm_enabled == state)
return;
+ /* Convert ASPM state to upstream/downstream ASPM register state */
+ if (state & ASPM_STATE_L0S_UP)
+ dwstream |= PCIE_LINK_STATE_L0S;
+ if (state & ASPM_STATE_L0S_DW)
+ upstream |= PCIE_LINK_STATE_L0S;
+ if (state & ASPM_STATE_L1) {
+ upstream |= PCIE_LINK_STATE_L1;
+ dwstream |= PCIE_LINK_STATE_L1;
+ }
/*
* Spec 2.0 suggests all functions should be configured the
* same setting for ASPM. Enabling ASPM L1 should be done in
* upstream component first and then downstream, and vice
* versa for disabling ASPM L1. Spec doesn't mention L0S.
*/
- if (state & PCIE_LINK_STATE_L1)
- pcie_config_aspm_dev(parent, state);
-
+ if (state & ASPM_STATE_L1)
+ pcie_config_aspm_dev(parent, upstream);
list_for_each_entry(child, &linkbus->devices, bus_list)
- pcie_config_aspm_dev(child, state);
-
- if (!(state & PCIE_LINK_STATE_L1))
- pcie_config_aspm_dev(parent, state);
+ pcie_config_aspm_dev(child, dwstream);
+ if (!(state & ASPM_STATE_L1))
+ pcie_config_aspm_dev(parent, upstream);

link->aspm_enabled = state;
}
@@ -673,7 +708,10 @@ void pci_disable_link_state(struct pci_d
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
link = parent->link_state;
- link->aspm_disable |= state;
+ if (state & PCIE_LINK_STATE_L0S)
+ link->aspm_disable |= ASPM_STATE_L0S;
+ if (state & PCIE_LINK_STATE_L1)
+ link->aspm_disable |= ASPM_STATE_L1;
pcie_config_aspm_link(link, policy_to_aspm_state(link));

if (state & PCIE_LINK_STATE_CLKPM) {
@@ -742,11 +780,17 @@ static ssize_t link_state_store(struct d
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pcie_link_state *link, *root = pdev->link_state->root;
- u32 state = buf[0] - '0';
+ u32 val = buf[0] - '0', state = 0;

- if (n < 1 || state > 3)
+ if (n < 1 || val > 3)
return -EINVAL;

+ /* Convert requested state to ASPM state */
+ if (val & PCIE_LINK_STATE_L0S)
+ state |= ASPM_STATE_L0S;
+ if (val & PCIE_LINK_STATE_L1)
+ state |= ASPM_STATE_L1;
+
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
list_for_each_entry(link, &link_list, sibling) {

2009年7月21日 星期二

存取記憶體 peekb()

  函數名: peekb
  功 能: 檢查存儲單元
  用 法: char peekb (int segment, unsigned offset);
  segment為段基地址,offset偏移地址。
  程序例:

  #include
  #include
  #include
  int main(void)
  {
  int value = 0;
  printf("The current status of your keyboard is:\n");
  value = peekb(0x0040, 0x0017);
  if (value & 1)
  printf("Right shift on\n");
  else
  printf("Right shift off\n");
  if (value & 2)
  printf("Left shift on\n");
  else
  printf("Left shift off\n");
  if (value & 4)
  printf("Control key on\n");
  else
  printf("Control key off\n");
  if (value & 8)
  printf("Alt key on\n");
  else
  printf("Alt key off\n");
  if (value & 16)
  printf("Scroll lock on\n");
  else
  printf("Scroll lock off\n");
  if (value & 32)
  printf("Num lock on\n");
  else
  printf("Num lock off\n");
  if (value & 64)
  printf("Caps lock on\n");
  else
  printf("Caps lock off\n");
  return 0;
  }


http://baike.baidu.com/view/1983818.html?fromTaglist

2009年7月20日 星期一

取得檔案時間 "findfirst" (struct ffblk)

http://www.delorie.com/djgpp/doc/libc/libc_326.html

findfirst

Syntax

#include

int findfirst(const char *pathname, struct ffblk *ffblk, int attrib);

Description

This function and the related findnext (see section findnext) are used to scan directories for the list of files therein. The pathname is a wildcard that specifies the directory and files to search for (such as subdir/*.c), ffblk is a structure to hold the results and state of the search, and attrib is a combination of the following:

FA_RDONLY

Include read-only files in the search (Ignored.)

FA_HIDDEN

Include hidden files in the search

FA_SYSTEM

Include system files in the search

FA_LABEL

Include the volume label in the search

FA_DIREC

Include subdirectories in the search

FA_ARCH

Include modified files in the search (Ignored.)

If a file has flag bits that are not specified in the attrib parameter, the file will be excluded from the results. Thus, if you specified FA_DIREC and FA_LABEL, subdirectories and the volume label will be included in the results. Hidden and system files will be excluded.

Since findfirst calls DOS function 4eh, it is not possible to exclude read-only files or archive files from the results. Even if the FA_ARCH and FA_RDONLY bits are not specified in the attrib parameter, the results will include any read-only and archive files in the directory searched.

This function supports long file names.

The results of the search are stored in ffblk, which is extended when the LFN API (see section LFN) is supported. Fields marked LFN are only valid if the lfn_magic member is set to "LFN32".



struct ffblk {
char lfn_magic[6]; /* LFN: the magic "LFN32" signature */
short lfn_handle; /* LFN: the handle used by findfirst/findnext */
unsigned short lfn_ctime; /* LFN: file creation time */
unsigned short lfn_cdate; /* LFN: file creation date */
unsigned short lfn_atime; /* LFN: file last access time (usually 0) */
unsigned short lfn_adate; /* LFN: file last access date */
char ff_reserved[5]; /* used to hold the state of the search */
unsigned char ff_attrib; /* actual attributes of the file found */
unsigned short ff_ftime; /* hours:5, minutes:6, (seconds/2):5 */
unsigned short ff_fdate; /* (year-1980):7, month:4, day:5 */
unsigned long ff_fsize; /* size of file */
char ff_name[260]; /* name of file as ASCIIZ string */
}


Return Value

Zero if a match is found, nonzero if none found.

Portability

ANSI/ISO C No
POSIX No

Example



struct ffblk f;
int done = findfirst("*.exe", &f, FA_HIDDEN | FA_SYSTEM);
while (!done)
{
printf("%10u %2u:%02u:%02u %2u/%02u/%4u %s\n",
f.ff_fsize,
(f.ff_ftime >> 11) & 0x1f,
(f.ff_ftime >> 5) & 0x3f,
(f.ff_ftime & 0x1f) * 2,
(f.ff_fdate >> 5) & 0x0f,
(f.ff_fdate & 0x1f),
((f.ff_fdate >> 9) & 0x7f) + 1980,
f.ff_name);
done = findnext(&f);
}