PCI (Peripheral Component Interconnect) Bus Standartına Giriş)

Serbay Özkan
14 min readMar 19, 2021

--

Gömülü sistemler alanında özellikle cihaz sürücüsü (device driver) ve BSP (Board Support Package) geliştiricileri yazılım disiplinlerinin yanı sıra bilgisayar mimarisi ve işletim sistemleri hakkında da yetkin bir bilgi seviyesine sahip olması gerekiyor. İyi bir yazılım bilgisine sahip olmak bir cihaz sürücüsü veya BSP yazarken ilgili teorinin koda dönüşmesinde, işin teorisini ve arka planını bilmek de bu kodlama sürecinin doğru yönde ilerlemesinde çok önemli bir rol üstlenmektedir.

Bu yazımda PCI Bus standartına giriş tadında bir yazı hazırlamaya çalıştım. Standartın hepsini tüm ayrıntılarıyla bir blog yazısına çevirmek mümkün olmasa da (PCI/PCIe IP Core yazmadığımız sürece zaten bu kadar ayrıntıya da gerek yok) elimden geldiği kadar PCI Bus standartında karşımıza çıkan teknik jargondan bahsetmeye çalışacağım.

PCI (Peripheral Component Interconnect) Bus işlemci ile çevresel birimleri birbirine bağlayan bir lokal veri yoludur. 2003 yılına kadar PCI ve PCI-X (PCI Extended) yaygın olarak kullanılsa da bu yıldan sonra artık PCI ve PCI-X’in yerini avantajları sebebiyle PCIe (PCI Express) almaya başlamıştır ve şu anda da defacto bir standart gibi çok yaygın bir şekilde kullanılmaktadır. PCIe de olsa PCI-X de olsa PCI da olsa bunları genel olarak PCI Bus olarak isimlendiriyoruz. Bilgisayarlarımızda anakart üzerindeki Wi-Fi, Ethernet, USB controller, SSD ve grafik kartları bu veri yolu üzerinden haberleşmektedir.

PCIe’nin PCI ve PCI-X’in yerini almasındaki en önemli nedenleri aşağıdaki gibi sıralayabiliriz.

  • PCI ve PCI-X parelel bus topolojisine sahipken PCIe seri bus topolojisine sahiptir. Bu yüzden de PCIe ile bus için gerekli pin sayısı düşürülmüştür ve tasarım karmaşıklığı da azaltılmıştır.
  • PCI slotları 32 bit slot (124 pin) ve 64 bit slot (188) pin olmak üzere iki form’da bulunmaktadır. PCIe ile birlikte bu slotlar farklı varyantlar halinde (x1, x2, x4 … x32 Lanes) sunularak tasarım esnekliği sağlanmıştır.
  • PCIe bus hızları (kendi içinde versiyon ve lane sayısına göre değişse de) PCI ve PCI-X’e göre çok ciddi şekilde yükseltilmiştir.
  • PCIe ile latency faktörünü yükseltmeden handle edilebilecek interrupt sayısı yükseltilmiştir. Gelişmiş Interrupt Management özellikleri (Message Based Interrupt) sunulmaya başlanmıştır.

PCIe’nin x1, x2, x4, x8, x16, x32 fiziksel formları bulunmaktadır. Buradaki numaralar lane anlamına geliyor. Lane iki tane differential sinyal çiftinden oluşmaktadır. Bu sinyal çiftlerinden biri veri gönderimi için biri de veri alımı için kullanılmaktadır böylelikle eş zamanlı olarak gönderim/alım işlemleri yapılabilmektedir.

PCIe x32 sadece özel yerlerde kullanıldığı için çok yaygın değildir. PCIe x12 genelde sunucularda kullanılmaktadır. PCIe x2 de genelde iç arayüz olarak kullanılıyor ve extension slot olarak tercih edilmiyor zaten bu yüzden de genelde PCIe slot form factor yerine M.2 form faktöründe bulunuyor. Bu bilgiler eşliğinde bahsi geçen versiyonları filtrelediğimizde en cok gördüğümüz PCIe formları PCIe x1, x4, x8, x16 oluyor.

PCI/PCIe Slotları

PCIe kendi içerisinde sadece lane sayısına göre değil versiyonlarına göre de birbirinden hız anlamında değişiklik göstermektedir. PCIe versiyonlarına ve lane sayılarına bağlı olarak haberleşme hızlarını belirten tablo aşağıda paylaşılmıştır.

Uyumluluk

  • 32 Bit PCI 64 Bit PCI ile uyumlu değilken 64 Bit PCI cihazlar 32 Bit ile uyumludur.
  • PCIe cihazlar kendi içerisinde uyumludur. Örneğin bir PCIe x16 slotuna PCIe x1, x4 veya x8 kart takabiliriz sadece haberleşme hızları kendi lane sayısının izin verdiği hızlarda olacaktır.
  • PCIe versiyonları kendi arasında uyumludur. Örneğin PCIe 3.0 versiyon bir kartı 2.0 destekleyen bir board üzerinde kullanabiliriz ama doğal olarak hızı 2.0 ile sınırlanacaktır.
  • PCI ve PCIe kendi aralarında uyumlu değil. Yazılımsal olarak aynı driver’ı kullanabilsek de fiziksel olarak PCI yerine PCIe ya da tam tersi bir kullanım yapılamamaktadır.

PCIe Topology

PCI Express Topolojisi

Transaction

Bus üzerinde yapılan yazma/okuma rutinlerine verilen genel isimdir.

Link

Her bir PCI cihaz kendisine ait özel bir bus üzerinde bulunur ve bu bus’a PCI Link ismi verilmektedir.

Port

Lane’lerin birleşip PCI Link ile oluşturduğu arayüze denir.

  • Upstream Port: Root Complex yönünde olan portlara denir.
  • Downstream Port: Root Complexten uzaklaşan ve ayrı bir PCI link kurulmasına izin veren portlardır.

Yukarıdaki portlardan harici olarak iki port terminolojisi daha bulunmaktadır. Ingress Port paket alan porttur. Egress Port ise paket gönderen eden porttur.

Root Port

Root Complex üzerinde yer alan portlara denilmektedir.

Root Complex

Root Complex CPU ve Memory’yi PCI Express Fabric’e bağlamaktadır. Birden fazla PCIe portunu destekleyebilmektedir. Yukarıdaki örnek gösterimde 3 port desteklemektedir. Her bir port bir endpointe veya hierarşik bir yapı kurulabilmesi amacıyla kullanılan bir switch’e bağlıdır. Root Complex CPU komutlarına karşılık olarak configuration, memory ve IO transactionları üretmektedir. Root Complex ilgili portlarını kullanarak paketleri karşıya iletmekte ve gelen paketleri de yine bu portlar ile alarak CPU veya Memory’e yönlendirmektedir. Multi-port Root Complex opsiyonel olarak bir porttan gelen mesajları başka bir porta yönlendirebilecek yetenekte olabilir. Bu özellik PCIe bus standartına yer alan bir özellik değildir ancak bazı mimarilerde opsiyonel olarak desteklenebilmektedir.

Requester

Transaction başlatan cihazdır. Root Complex ve endpointler requester device olarak örnek verilebilir.

Completer

Requester tarafından adreslenen veya hedef olarak gösterilen cihazdır. Requester completer’dan veri okur veya completer’a veri yazar. Yine Root Complex ve endpointler completer olarak örnek verilebilir.

Yani Root Complex ve Endpoint cihazlar hem Requester hem de Completer olarak görev alabilir.

Endpoints

Transactionların requesterları ve completerları diyebiliriz bunlara. Endpointler genellikle Ethernet, USB, Graphic kartları gibi cihazlardır. Endpointler requester olarak transcation başlatabilir veya completer olarak transcationlara cevap verebilir.

İki tür endpoint bulunmaktadır.

⦁ PCI Express Endpoints

⦁ Legacy Endpoints

Legacy endpointler birçok IO transcation ve locked transcation semantiğini completer olarak destekler ancak requester olarak desteklemezler.

PCI Express (Native) endpointler IO ve locked transactions semantiklerini desteklemek zorunda değildir ama MSI (Message Signalled Interrupt) üretimini desteklemek zorundadir. Ayrıca 64-Bit memory adreslemeyi de desteklemek zorundadır.

Her bir endpoint bus number, device number ve function numberdan oluşan bir ID ile ilklendirilir.

Bridge

PCI Bridge iki PCI Bus arasında bir yol/arayüz sağlamaktadır. Bir bridge aynı bus’a da arayüz sağlayabilir. Örneğin PCI-to-PCI (P2P) bridge ile tamamen ayrı bir ikincil bus yaratılarak bus’a daha fazla yük eklenmesine imkan verebilmektedir. Bridgeler aynı zamanda switch konseptinin implement edilmesinde görev almaktadırlar.

Bus enumeration sürecinde sadece P2P bridgelerin downstream portları hesaba alınır. Bu enumeration süreci için çok önemli bir ayrıntıdır.

Switch

Switchler birden fazla cihazın tek bir root port’a attach olabilmesine imkan sağlamaktadır. Switchler sadece bir upstream port’a sahiptir ama bazen birden fazla downstream port’a sahip olabilirler. Packet router olarak davranabilecek kadar gelişmiş yapılardır.

Switchler iki veya daha fazla PCI-to-PCI (P2P) bridgelerden meydana gelir. Switch downstream portları (bir tür virtual port) P2P bridgeleridir. Sadece PCI-PCI Bridge ile sunulan switch downstream portları internal bus’ta görünür.

PCI Adres Uzayları (Address Spaces)

PCI/PCI-X/PCIe cihazlarda 3 tane farklı adres uzayı bulunmaktadır. Bunlar aşağıdaki gibidir.

  • Konfigürasyon Adres Uzayı (Configuration Address Space)
  • I/O Adres Uzayı (I/O Address Space)
  • Bellek Adres Uzayı (Memory Address Space)

Konfigürasyon Adres Uzayı (Configuration Address Space)

Cihazın konfigürasyonunu içeren, cihaz hakkında temel bilgilerin yer aldığı aynı zamanda da BIOS veya Kernel tarafından programlanarak da yapılandırılabilen bir adres uzayıdır.

PCI standartında bu adres uzayı 256 Byte iken PCIe ile birlikte 4KB’a çıkarılmıştır.

Konfigürasyon adres uzayı memory mapped bir uzaydır. Yani bu adres uzayı aslında processor belleğinden allocate edilir. 4KB’lik bir konfigürasyon adres uzayı düşünürsek bu alan aslında processor memory’den allocate ediliyor.

PCI konfigürasyon adres uzayının ilk 64 Byte’i standart haldedir geri kalan bytelar ise kullanıcı veya üretici firma tanımlı konfigürasyonlar için kullanılabilmektedir.

Konfigürasyon adres uzayının header yapısı iki farklı türde olmaktadır ve cihazın endpoint, bridge veya root complex olmasına göre değişmektedir. İlgili header içerikleri aşağıda belirtilmiştir.

Configuration Address Space

Header isimlendirmelerinden gördüğümüz üzere Type 0 ve Type 1 adında iki farklı header türü bulunmaktadır. Type 0 header Endpoint cihazlar için kullanılırken Type 1 header ise Root Complex ve Bridge-Switch cihazlar için kullanılmaktadır.

I/O Adres Uzayı (I/O Address Space)

Intel ilk zamanlarda Port Mapped I/O (PMIO) adres uzayı yapısını çıkarmıştı ve uzun bir süre bir çok cihaz bu adres uzayını kullandı ancak daha sonra dezavantajlarından dolayı Memory-Mapped I/O (MMIO)’ya geçilmeye başlandı.

PCIe standartları bu adres uzayının kullanılmasını teşvik etmiyor. Gelecekteki standartlarda bu adres uzayının deprecate edilme durumu öngörülmektedir.

Bellek Adres Uzayı (Memory Address Space)

MMIO’da cihazın peripheral registerları aslında processor belleğine map ediliyor yani biz bir cihazın peripheral registerlarına erişmek istediğimizde direk processor belleği üzerinde map edilmiş bir adres bloğu üzerinden işlem yaparak aslında cihaz ile konuşmuş oluyoruz.

PCI standartında bu bellek alanların fiziksel adresleri Konfigürasyon Header içinde yer alan BAR (Base Address Register) olarak tanımlanmıştır.

BAR (Base Address Register)

BAR (Base Address Register) PCI cihazların processor bellek alanında hangi fiziksel adrese map edildiği, cihazın ne kadar bellek alanı ve bellek tipine ihtiyaç duyduğu gibi bilgileri sağlamaktadır.

Type 0 header 5 adete kadar BAR register desteklerken Type 1 header 2 adete kadar BAR register desteklemektedir. Bu sayılar zorunlu desteklenmesi gereken BAR register sayısı değildir. Örneğin elimizde bir ethernet controller olsun ve endpoint (type 0) olarak çalıştığını varsayalım. Bu cihaz’ın destekleyebileceği max BAR register 5 adet olmasına rağmen cihaz üreticisi tarafından sadece 2 tane tanımlı BAR olabilir.

BAR registerlarının okunması ve processor alanına map edilmesi işletim sisteminin sorumluluğundadır. BAR registerları bir kere konfigüre edildikten sonra artık PCI cihazlar bu ilgili adres üzerinden processor ile haberleşmektedir.

Driver yazacağımız cihaz ve işletim sistemi ne olursa olsun işletim sisteminin sağladığı arayüzleri kullanarak bu BAR registerlarına erişebilmemiz mümkündür. BIOS veya Kernel bu BAR registerlarının MSB bitinden başlayarak sağa doğru 1 yazmaya başlar. En son nereye 1 yazabilmiş ise bunu n. LSB biti olarak kabul edersek ilgili BAR’ın talep ettiği bellek alanını 2^n olarak hesaplar ve bu bilgiyi driver geliştiricisine sunar. Aynı zamanda BAR registerların ilk 4 bitine göre de yukarıdaki görselde görüldüğü üzere Memory/IO, 32/64 Bit, Non-Prefetchable/Prefetchable gibi ilgili parametreleri de parse edilerek yine driver geliştiricisine sunulabilir.

Driver geliştirici tarafından bu bilgiler eşliğinde ilgili bellek alanlarını processor bellek alanından allocate edilir, map edilen bu alanın başlangıç adresi de BAR registerin adres bitlerine yazılır. Artık bu aşamadan sonra CPU ile bu fiziksel adres üzerinden haberleşir.

Birden fazla BAR register olması durumunda da süreç yine aynıdır ve doğal olarak birden fazla bellek alanı CPU bellek alanından allocate edilir.

PCI Bus Taraması (Scanning) ve Numaralandırma (Enumeration)

İşletim sistemi ayağa kalkarken BIOS veya Kernel içinde PCI Core Code dediğimiz bir yazılım tarafından PCI bus taraması ve numaralandırması yapılır.

PCI’da numaralandırma işlemi Bus:Device.Function formatında ve hex formunda olmaktadır (başında 0x bulunmaz). Örneğin 00:01.03 olarak numaralandırılmış bir cihazda Bus : 0x00, Device : 0x01 ve Function: 0x03'tür

PCI standartına göre kısıtlamalar aşağıdaki gibidir.

  • En fazla 256 bus olabilir. (8 Bit)
  • Her bir bus üzerinde en fazla 32 device olabilir. (5 Bit)
  • Her bir device en fazla 8 function destekleyebilir. (3 Bit)

Bus 0 her zaman Root Complex internal bus’a atanır. Numaralandırma işlemi Depth-First Search (DFS) algoritmasına dayanır (Linux’da bu algoritma yerine başka algoritma kullan diyebiliyoruz). Normalde bu algoritmada rasgele bir düğüm seçilerek işleme başlanır ama PCI numaralandırma işleminde ilk düğüm Root Complex seçilerek başlamaktadır.

PCI Core kodu PCI Bus’ı tararken üç olasılık bulunmaktadır.

  • Bus üzerinde PCI cihaz olmayabilir. (Device not Present)
  • Bus üzerinde PCI cihaz olabilir ama cihaz henüz hazır olmayabilir. (Device not Ready)
  • PCI cihaz var ve hazır. (Device Ready)

Eğer numaralandırma sırasında hedef cihaz bus üzerinde yoksa PCI Core kodu tarafından gönderilen Configuration Read Request sorgusu zaman aşımına uğrar ve ilgili yazılım tarafından Master Abort Error hatası üretilir. Bus’ı süren herhangi bir cihaz olmadığından ve bütün sinyaller pull-up olduğundan data bitlerin hepsi 1 olarak gözükür ve vendor ID 0xFFFF olarak görülür. 0xFFFF Vendor ID reserve edilmiştir bu yüzden bu değerin okunması bus üzerinden bir cihazın olmadığını göstermektedir.

Diğer durumda ise hedef cihaz resetlendikten sonra cihazın konfigürasyon registerlarını ilgili EEPROM’undan veya başka non-volatile bir bellek biriminden çekmesi için belli bir zamana ihtiyacı olmaktadır. PCI cihaz henüz bu registerlarını çekip hazır hale gelemediyse Configuration Read Request sorgusuna karşılık Configuration Request Retry Status (CRS) adında bir status dönmektedir. Bu durumda Root Complex bu cihaza geçici bir değer veriyor ve bus taramasına devam ediyor daha sonra bu cihaza geri dönerek cihaza tekrardan Configuration Read Request göndermektedir.

Peki PCI Core kodu cihazın endpoint veya bridge mi olduğunu nasıl anlıyor?

Her bir cihazın configuration header’ına sahipolduğunu söylemiştik. Cihaz endpoint de olsa bridge de olsa 0Ch offsetinde yer alan Header Type adında bir register’i bulunmaktadır. PCI Core kodu bu register’i aşağıdaki gibi parse ederek cihazın tipini ve fonksiyonellik tipini öğrenebilmektedir.

Header Type Register

Header Type kodlaması da aşağıdaki gibidir.

  • 0 = Endpoint
  • 1 = PCI-to-PCI bridge (P2P)
  • 2 = CardBus Bridge (Günümüzde artık kullanılmıyor)

Böylelikle configuration header içerisinde yer alan bu 8 bitlik register parse edilerek cihazın türünü ve tek fonksiyonelliğe mi yoksa çoklu fonksiyonelliğe mi sahip olduğu belirlenmektedir. Eğer PCI cihaz multi-function bir cihaz ise cihazın kaç tane fonksiyon desteklendiği PCI Core kodu tarafından Configuration Read Request sorgusunun içerisinde yer alan function number register’inin 1 arttırılarak iteratif olarak sorgulanması ile elde edilir.

Configuration Read/Write Request Format

Aşağıdaki görselde örnek bir numaralandırılmış bir PCI topolojisi belirtilmiştir. Şimdi bu topoloji üzerinden şimdiye kadar verdiğim bilgiler ışığında numaralandırma sürecini düğüm bazında inceleyelim.

PCI Bus Enumeration
  1. PCI Core kodu Root Complex internal bus’ı yani Host/PCI Bridge bus’ını 0 ile numaralandırır.
  2. Bridge A’dan başlayarak PCI Core kodu Bus 0 üzerinde teorik olarak bulunabilecek olası maksimum 32 cihaz için Function 0'dan Vendor ID’leri okur. Eğer Bus 0 Device 0 Function 0'dan geçerli bir Vendor ID dönerse demek ki en az 1 function var demektir. Eğer Device 0'dan geçerli bir Vendor ID dönmez ise bu sefer Bus 0 Device 1 Function 0 olacak şekilde sorgu yapılır.
  3. Hatırlarsak PCI cihazın Header Type register’ına göre single-function/multi-function ve Endpoint/Bridge olduğunu anlayabiliyorduk. PCI Core kod bu bilgiyi parse ederek yukarıdaki örnek topolojimizde Bus 0 Device 0'in single-function yapıda olduğunu ve bir bridge olduğunu anlamıştır.
  4. PCI Core kodu bir bridge gördüğü için bu bridge’den sonraki yeni bus’ı numaralandırır. Yani artık bridge A’nin aslında bir primary bir de secondary bus’ı olacaktır. Örnek topolojimizde bridge A için primary bus 0 secondary bus ise 1 ile numaralandırılmıştır.
  5. PCI Core kodu artık Bus 1 için yani Bus 1 Device 0 Function 0 ile başlayarak sorgulama yapar ve bu sefer Bridge C’den geçerli bir Vendor ID döndüğü için Bridge C için bus numaralandırması yapar. Bridge C’nin primary bus numarası 1 secondary bus numarası 2 olur.
  6. PCI Core kodu Bus 2 için yukarıdaki aynı mantıkla bus’ı sorgular ve bir bridge daha görür yani yazılım perspektifi ile bakarsak geçerli bir Vendor ID döner ve header type’ına göre de bridge olduğunu anlar. Bridge D’yi de primary bus 2 secondary bus 3 olacak şekilde numaralandırır.
  7. PCI Core kodu Bus 3 için sorgulama yapar ve cihazın endpoint ve multi-function özelliğe sahip olduğunu anlar. Endpoint olduğu için artık yeni bir bus numaralandırması yapmaz ve bu cihazın kaç function’a sahip olduğunu anlamak için Bus 3 Device 0 Function 0'dan başlayarak Bus 3 Device 0 Function 8'e kadar sorgulama yapar. Geçerli bir Vendor ID dönen function numaraları artık bilinmiş olur.
  8. PCI Core kodu endpoint bir cihaza ulaştığı için ve artık burada numaralandıracağı bir bus kalmadığı için geriye doğru ilerleyerek başka bir bridge olup olmadığını sorgular ve Bridge E’den geçerli bir Vendor ID döndüğü için bu sefer Bridge E’yi numaralandırır. Bridge E’nin bus numaraları primary bus 2 secondary bus 4 olur.
  9. PCI Core kodu Bus 4 için yine önceki adımlardaki aynı mantıkla sorgusunu yapar ve single-function endpoint bir cihaz ile karşılaşır. Endpoint cihaz olduğu için artık yeni bir bus numaralandırması yapamaz ve geriye doğru ilerler.
  10. Bridge A, C, D ve E’yi daha önceden numaralandırdığı için Root Complex portuna kadar geriye doğru ilerler ve henüz numarlandırmasını yapmadığı Bridge B’ye geçer. Bridge B’nin bus numaralandırmasını primary bus 0 secondary bus 5 olacak şekilde yapar ve alt bridge’lere ilerler.
  11. F ve G bridgelerini numaralandırmayı tamamladıktan sonra H bridge’ine geçer ve burada sorguladığı cihazın yine bir bridge olduğunu görür ancak bu sefer bridge bir switch oluşturmak için değil de aynı PCI bus üzerinden birden fazla device’in attach olması için kullanılmaktadır.
  12. PCI Core kodu Bridge I’yı numaralandırdıktan sonra Bus 9 üzerinde sırasıyla geçerli vendor ID dönen bütün cihazları sırayla sorgular bu cihazların endpoint ve single-function’a sahip olduğunu anlar.
  13. Son olarak da Bridge J’yi numaralandırarak ve cihazın endpoint ve single-function özelliğe sahip olduğunu belirledikten sonra artık numaralandıracak bir bus olmadığı için ve muhtemel bütün dallara indiği için numaralandırma işlemini bitirir.

Bu aşamadan sonra board üzerinde kaç tane PCI Controller varsa ve PCI buslar üzerinde kaç tane endpoint, switch ve bridge varsa bunların hepsinin bilgisini elde etmiş oluyoruz.

PCI Device Driver yazarken de driver yazacağımız cihazın Vendor ID ve Device ID bilgilerine göre de işletim sistemi bize ilgili cihazın veri yapısını döndürmekte ve biz bu veri yapısı üzerinden numaralandırılmış cihaza erişebilmekteyiz.

Linux makinemizde işletim sistemi açılışında numaralandırılmış PCI cihazların listesini aşağıdaki komut ile görebilmemiz mümkündür.

Yukarıda da görüldüğü gibi PCI numaralandırma Bus:Device.Function formatında yapılmıştır ve onun hemen yanında cihazın türünün ne olduğu gözükmektedir.

Peki PCI cihazın endpoint mi bridge mi olduğunu configuration header’ından anlıyorduk tamam anladık güzel de yukarıdaki görselde genious bir abinin yazdığı PCI shell programı cihazın direk Host Bridge, USB Controller, SATA Controller olduğunu çiçek gibi yazmış. Bu bilgiyi nasıl elde ediyoruz hocam?

Bu bilgiyi de yine configuration header içerisinde yer alan Class Code register’indan anlıyoruz. Hem type 0 hem de type 1 için de 08h offset’inde Class Code adı verilen bir register bulunmaktadır. Her bir Class Code’un karşılık geldiği bir cihaz türü bulunmaktadır. Bu liste yazılım tarafından kodlanarak class code’a karşılık gelen cihaz türü bulunmaktadır. Class Code register farkettiyseniz 24 bit bir register. Bunun ilk 8 biti Base class, ikinci 8 biti Sub-Class üçüncü 8 biti ise Programming Interface anlamına gelmektedir. Aşağıda örnek olsun diye listenin bir kısmını koydum. Tüm listeyi merak edenler bu linkten erişebilirler.

Ek olarak cihazların sonunda yazan revision bilgisi de yine configuration header içerisinde 08h offset’inde yer alan Revision ID register’dan elde edilmektedir.

Interrupt Yönetimi

PCIe Bus Standartında 3 farklı interrupt türü bulunmaktadır.

  • Legacy Interrupts
  • MSI (Messaged Signalled Interrupts)
  • MSI X (eXtended MSI)

PCI Legacy INT-X-based Interrupts

Legacy Interrupt yönetimi PCI INT-X interrupt hatlarına dayanmaktadır ve INTA, INTB, INTC ve INTD olmak üzere 4 interrupt sinyalinden oluşmaktadır. Bu interrupt hatları sistemde yer alan bütün PCI cihazları arasında paylaşılmaktadır. PCI Legacy Interrupt handle etme adımları aşağıdaki gibidir.

  • PCI cihaz interrupt üretmek için INT# pinlerinden birini assert eder aynı zamanda configuration header içinde status register’da yer alan interrupt status bitini set eder.
Status Register (Configuration Header 04h offset)
  • Processor interrupt’i algılar ve driver aracılığı ile INT# hattına bağlı her bir PCI cihazı poll edilir bu yüzden de interrupt’ı servis etmek için gerekli zaman INT# hattını paylaşan cihaz sayısına bağlı olarak değişecektir. Interrupt’ın nedenini bulmak için cihazın internal registerları okunur.
  • ISR interrupt’ın servis edilmesi için aksiyon alır.

MSI (Messaged Signalled Interrupt) ve MSI-X (eXtended MSI)

MSI PCI cihazın interrupt’ı tanımlayan verisini özel bir memory-mapped I/O adresine yazmasına imkan veren bir mekanizmadır. Daha sonra Root Complex bu interrupt verisi ile ilgilenerek interrupt’ın handle edilmesi sağlanmaktadır. PCI MSI handle etme adımları aşağıdaki gibidir.

  • PCI cihaz MSI Memory Write Upstream göndererek interrupt üretir.
  • Processor interrupt’un doğruluğunu onaylar ve uygun ISR’i çağırır. Interrupt MSI Vector’de tanımlı olduğundan daha önceden bilinmektedir.
  • ISR interrupt’ın servis edilmesi için aksiyon alır.

MSI ile ilgili veri yapıları Capability Structure adı verilen bir yapı içerisinde bulunur.

MSI-X sadece PCIe içinde yer alan MSI’in genişletilmiş halidir. MSI’ya göre daha fazla bilgi taşıyabilir ve daha esnektir. PCIe hem MSI hem de MSI-X’i desteklemektedir. MSI-X ilk PCIe 3.0 ile tanımlanmıştır.

Capability Structure

Capability Structure PCI/PCI-X/PCIe ile desteklenen yönetimsel araçların veri yapılarıdır. Bunlar configuration header içerisinde yer almaktadır.

Capability structure bir linked-list veri yapısıdır ve bu veri yapısının ilk başlangıç noktası Configuration Header içerisinde 34h offsetinde yer alan Capability Pointer ile sağlanmaktadır.

Örneğin elimdeki Realtek Ethernet Controller kartının Capability Pointer’ini 0x40 olarak okudum. Bu da şu anlama geliyor bu ethernet controller kartının 40h offsetinde bir tane capability structure bulunmaktadır.

Capability structure içerisinde capability ID denilen bir ID bulunmaktadır. Bu ID capability structure’in türünü belirtmektedir ve standartlara göre bu ID ile eşleşen capability structure özellikleri aşağıdaki gibidir.

  • 01 : Power Management Capability Structure
  • 02 : AGP Capability Structure
  • 03 : VPD Capability Structure
  • 04 : Slot Numbering Capability Structure
  • 05 : MSI Capability Structure

şeklinde ilerlemektedir. Tam listeyi bu linkten görebilirsiniz.

Bu bir linked-list yapısı olduğu için her bir capability structure kendi içerisinde bir Pointer to Next Capability adında bir register tutar. Bu structure üzerinde işlem yapan bir yazılım yazıyorsak bu next pointer değerini kulanarak veri yapısı içerisinde ileriye doğru gitmemiz mümkündür. Next capability pointer değeri 0 ise artık veri yapısının sonuna geldiğimizi anlayabiliyoruz. Örnek bir Capability Structure aşağıda paylaşılmıştır.

Power Management Capability Structure (Capability ID : 01)

Diğer yazılarımda görüşmek üzere…

Referanslar ve Faydalı Kaynaklar

--

--

No responses yet