整理一下 PCI的Memory Mapped IO vs Port IO

来源于网络

1.http://blog.chinaunix.net/u1/58901/showart_1723814.html

关于外设的memory-mapped I/O 和 port-mapped I/O

在访问外设的时候,对于程序开发人员来说,应当弄清楚这个外设是端口映射还是内存映射到方式。

memory-mapped I/O 把设备寄存器映射成常规的数据空间。对它的访问与访问系统内存空间没有区别。对于 C/C++ 程序员来说,memory-mapped I/O 寄存器看起来或多或少像常规的对象。向 memory-mapped 的设备寄存器存储数据就是向设备发送指令或者数据。从 memory-mapped I/O 寄存器中读取数据就是获取设备的状态或者数据。


设备地址空间是系统内存空间的一部分;
内存映射后的控制寄存器和状态寄存器可以看作是普通的变量,只需声明一个指向此寄存器或者是一组寄存器的指针变量即可,并且要显示的声明这个指针变量的值。

 

下面是port-mapped I/O

而port I/O 把控制和数据寄存器映射到一个单独的数据空间。port I/O 和 memory-mapped I/O 相似,除了,程序必须使用特殊的指令(如 Intel x86 处理器的 in 和 out 指令)来写入或者读取设备寄存器。


独立的io地址空间
必须使用assembly来进行实际的操作。

 

2.http://stenlyho.blogspot.com/2008/08/io.html

I/O對應的方式

  1. I/O mapped I/O(port-mapped I/O或Direct I/O)
    I/O與memory均擁有自己的記憶體空間
    需要特別的指令來處理I/O

    好處是完全不用考慮記憶體空間被I/O佔用,缺點需要額外的指令專門處理I/O存取。
  2. Memory Mapped I/O
    I/O與memory共用記憶體空間
    不需要特別指令來處理I/O
    其實Memory mapped I/O只是將I/O的port或memory 映射(mapping)到記憶體位址(memory address)上,

    其好處就是可以把I/O存取直接當成存取記憶體來用,缺點是有映射到的區域原則上就不能放真正的記憶體。
以PCI Device例子來看:
假設有個PCI的Device它的PFA(PCI Function Address)為(0,6,0)[bus/dev/function]
我們想要對PCI Register 43h bit1寫入1
範例程式碼如下:
mov eax, 80003040h
mov dx, 0cf8h
out dx, eax

mov dx, 0cffh
in al, dx
or al, 00000010b
out dx, al

IO Port 0x0cf8/0x0cfc為PCI Config Address/Data Port
這種方式就是I/O Mapped I/O

如果是PCIe Device的話,原則上原本的0x0cf8/0x0cfc還是可以用,但它只能存取Offset 00h~FFh,
要存取100h以上的空間時,就必需要用MMIO了。
範例程式如下:
假設我們要讀取Device(4,0,0)的register 0,讀2bytes
mov ax,[50400000h]

假設0x50000000是PCIe的Memory Base Address
PCIe PFA[27:20]: Bus information
PCIe PFA[19:15]: Device information
PCIe PFA[14:12]: Function information
PCIe PFA[11: 8]: Extended Register
PCIe PFA[7:2]: DW number
PCIe PFA[1:0]: Byte enable


參考資料來源:
http://biosengineer.blogspot.com/2007/10/bios-pci-scan-9.html
http://www.ltivs.ilc.edu.tw/kocp/mpu/m2/m2-3-2.htm
http://www.ltivs.ilc.edu.tw/kocp/mpu/m2/m2-3-3.htm

 

3.http://www.lslnet.com/linux/f/docs1/i39/big5284996.htm

 

在看到i/o memory i/o region,以及ioremap,mmap時,被這些概念弄糊塗了,看到zhanrk的《Linux對IO端口資源的管理》後,對memory-mapped的i/o還是有些疑問,


引用
3.4 管理I/O端口資源
我們都知道,採用I/O映射方式的X86處理器為外設實現了一個單獨的地址空間,也即「I/O空間」(I/O Space)或稱為「I/O端口空間」,其大小是64KB(0x0000-0xffff)。Linux在其所支持的所有平台上都實現了「I/O端口空間」這一概念。
由於I/O空間非常小,因此即使外設總線有一個單獨的I/O端口空間,卻也不是所有的外設都將其I/O端口(指寄存器)映射到「I/O端口空間」中。比如,大多數PCI卡都通過內存映射方式來將其I/O端口或外設內存映射到CPU的RAM物理地址空間中。而老式的ISA卡通常將其I/O端口映射到I/O端口空間中。
Linux是基於「I/O Region」這一概念來實現對I/O端口資源(I/O-mapped 或 Memory-mapped)的管理的。

文中提到通過內存映射(memory-mapped)的i/o端口(寄存器),這裡的內存映射是用ioremap實現的嗎?
這裡的映射是指直接用ioremap將i/o 端口(register)映射到核心虛地址空間(3GB-4GB)中嗎?

那這句話
「比如,大多數PCI卡都通過內存映射方式來將其I/O端口或外設內存映射到CPU的RAM物理地址空間中」
裡面提到的將i/o映射到cpu的RAM物理地址空間又是什麼意思?
搞不明白內存映射(memory-mapped)的i/o 端口到底和系統的RAM是個什麼關係?
對memory-mapped的i/o端口操作過程中,和系統的RAM 是個什麼關係呢,還是根本就沒關係?

分成兩步你就理解了:

第一步:

硬件級:cpu怎樣訪問外設存儲空間?
一種方式,cpu用單獨的指令訪問,這個單獨的指令需要一個要操作的外設存儲空間的地址,這就是I/O端口(I/O port)。
另一種方式,cpu不用單獨的指令訪問外設存儲空間,用通常的訪問存儲器的方式訪問外設存儲空間,這就是I/O存儲器(memory-mapped)。
memory比port好在它不是固定大小的,只受系統配置的常規存儲器大小和系統地址空間大小的限制。port的空間是固定的,現在有些外設的存儲空間要求很大,port的局限性就顯現出來了,因此,現在的觀點是用memory-mapped的外設存儲空間。

外設存儲空間不能固定,否則,如果某台機器有兩個外設都使用相同存儲空間(port和memory一樣,這裡不區分了),那麼cpu發出的訪問外設存儲空間是那個外設的呢?就衝突了。
因此,這裡存在一個映射關係,在「遠古」的時候,通過調整外設上的跳線來調整(映射),確保在一台機器上的外設存儲空間不發生衝突。在「現代」(例如:pci總線規範中),在機器啟動時,在bios中有個程序來分配資源(這裡用資源因為還包括中斷號的映射),完成外設存儲空間的映射。

第二步:
虛擬存儲空間到物理存儲空間的映射,這個映射就不多說了吧。 

首先,在linux啟動時,要掃瞄pci設備,然後為其分配中斷號、端口號等必須的資源,如果此pci設備有自己的內存,必須將其映射到整個系統的物理內存空間中。然後,還要將這些這塊物理內存映射到內核虛擬地址(通過函數__ioremap調用)。以後,訪問pci的內存只需訪問相應的虛擬地址就可以了。

系統要經過倆次映射:
1.設備上的ram映射到物理空間
2.在把該物理地址映射到虛擬空間去


http://www.lslnet.com/linux/showflat.php?Cat=&Board=linuxK&Number=402001&page=&view=&sb=&o=&vc=1


the memory on pci device is mapped in memory space by hardware.
pci device has registers(base adress register) point out its on-chip memory's base address in system memory space . these register are set by OS(pci bus driver) at system init time.


http://www.lslnet.com/linux/showflat.php?Cat=&Board=linuxK&Number=323326&page=&view=&sb=&o=&fpart=all&vc=1


設備可以根據需要把(設備上的)RAM和寄存器映射到(系統的)內存和I/O區間

PC總線上i/o操作和內存操作對應著不同的總線信號,所以是設備本身決定其資源(寄存器和RAM)是一種I/O資源,還是一種內存資源。
而智能的設備,如PCI設備,都允許系統(HOST CPU)配置設備上的資源(無論是內存還是I/O)在系統整個資源表中的位置,以簡化硬件的管理工作。

 

4.http://compusilli.wordpress.com/2007/08/28/memory-mapped-io-vs-port-io/

Memory Mapped IO vs Port IO

自從 PCI bus 成為一個業界的標準,大部分的 PCI 元件都支援了 IO port space 和 Memory mapped IO space (MMIO) 兩種存取的方法。這樣的支援讓驅動程式得以相容舊式 Port IO 過渡到 MMIO 架構。

這兩種 IO 方法的比較,在網路上必然有很多討論1。大都有的共識是,MMIO 比較有效率,因為在 MMIO 模式 CPU 寫過資料,不需等待該資料到達系統匯流排2,就可以直接處理下一件工作,這樣讓用 MMIO 方法的程式比使用舊式 Port IO 方法的程式稍快一點。

但是使用 MMIO 邏輯和 Port IO 不盡相同。其中最重要的,也最常看到的的錯誤就是時序同步的問題。如果讀寫 IO 的工作有資料同步的要求,那麼 CPU 在資料還沒到達目的地就跑去做下一件工作是否洽當就要考慮清楚。如果 CPU 寫入之後要等待資料到達目的地,那麼 MMIO 就沒有速度上的優勢。

MMIO 主要的優勢應該是它提供比舊式 Port IO 更有效和更大的定址空間,這讓週邊元件可以配置更多的 registers。

參考連結:
Memory Mapped IO is better
IO Port space sucks
MMIO is harder to get Right
Memory mapped IO vs Port IO (a)
Memory mapped IO vs Port IO (b)
A search from Google

註1:這兩種 IO 方法的比較,在網路上必然有很多討論。但關鍵字沒弄對,會出一堆不相關的結果,因為「IO」和「memory」都是電腦科學裡的「菜市仔名」。用字串模式找 “port io” vs “memory mapped io” 會有較正確的結果。

註2:系統匯流排,AKA: System bus, Central bus, Front side bus

 

5.wiki:http://en.wikipedia.org/wiki/Memory-mapped_I/O

你可能感兴趣的:(杂文)