FreeBSD PCI interrupt routing

14.05.2006 13:37

PCI interrupt routing je procedura , ktora stoji za popisanie , takze som sa rozhodol trocha priblizit tento proces.
Budem teda pojednavat o PCI interruptoch vo FBSD 4.x,5.x,6.x.

Prerusenia pre PCI zariadenia su rozdelene do dvoch kategorii: INTx prerusenia a novsia trieda MSI prerusenia.
Rozoberieme si teda princip INTx preruseni, ktore sa v sucastnosti pouzivaju.

Kazde PCI zariadenie ma 4 prerusovacie linie. INTA, INTB, INTC a INTD. Takze mozeme povedat ,ze samotne PCI prerusenie pozostava z BUS-u,SLOT-u a PIN-u. Napriklad zariadenia 3, INTA pin na pci zbernici 0 by vyzeralo takto: (0,3,INTA).
Kazda PCI funkcia ma prave jedno INTx prerusenie. Bus a slot je urcene podla pozicie tejto funkcie v PCI hierarchii a PIN je urceny z intpin PCI config registra.
PCI neurcuje ako je prerusenie dorucene na CPU - toto je vsetko vec architektury, chipsetu...

Na x86, su dva typy hardwaru pre pracu s prerusovacimi signalami. Prvy je par 8259A interrupt controlerov, ktore mozu byt k nahliadnutiu na vsetkych PC-AT strojoch.
Ten druhy typ hardwaru je APIC subsystem. Kazdy processor obsahuje lokalny APIC , ktory je schopny primat spravy od inych APIC a vie posielat spravy inym lokalnym APIC. Kazdy I/O APIC obsahuje individualne od 4 po 32 prerusovacie piny.
Jednoduho povedane, PCI interrupt routing je mapovanie ( bus, slot, pin ) PCI prerusovacich trojic do ( pic, pin) x86 presurovacich dvojic.
Teda IRQ premena je nejaky cookie sluziaci na bindovanie prerusenia zariadenia

BIOS ako taky neoperuje s APICs , aspon nie pre handlovanie device preruseni, ale pouziva jednoduche mapovanie , kde IRQs 0-7 koresponduju k 0-7 pinom na mastrovi 8259A a IRQs 8-15 sa mapuju na piny 0-7 na slavovi 8259A. Vsetky druhy FBSD pouzivaju rovnake mapovanie pre IRQ coockie premien pri pouziti 8259As na routovanie preruseni.
Freebsd 5.2 a vyssie povoluje ACPI model kde IRQ-cka 0-n koresponduje k pin 0-n prveho I/O APIC. , IRQ-cka n+1 na (N+1)+m sa mapuje na pin 0 na m sekundarneho I/O APIC.

FBSD 4.x je v tomto komplikovanejsie. Dovod je , ze cpl a spl interrupt masky 32bitove integery s 8 bitami su pre softwarove prerusenia (SWIs) a cpl ma len 24 bitov volnych na hardwarove prerusenia. Preto sa fbsd 5.2> nizsie je limitovane na IRQ premenne 0-23 a nemoze pouzit jednoduchy intuitivny model ktory ma fbsd 5.2_ a pouzivat ACPI. Co robi fbsd 4.x je,ze mapuje ISA prerusenia priradene k prvemu I/O APIC do IRQ 0,1 a 3-15, toto nechava volne len IRQ 2 a 16-23 pre ostatne APIC prerusovacie piny.

Kedze kazdy PIC device registre a interrupt handler pre specificky (apic,pin) n-nasobok, kde x86 interrupt je mapovany na jeden z poslednych parov IRQ-ciek. Ked su pouzite uz vsetky IRQ-cka, kernel zacne pridelovat niekolko (apic,pin) nasobkov na rovnake IRQ, toto spravi prerusenia ktore budu zdielane v softwari koli cpl limitaci aj ked niesu sharovane v hardwari. To je to co diferencuje IRQ premenne u 4.x a 5.2+ a Linuxa ktory pouziva ACPI global interrupt number model.

Preberme si najskor non-ACPI system.
Existuju tam dve moznosti, prva je, ze PCI device interrupt (bus,tuple,pin) je pripojeny priamo na individualne piny na PCI. Je to dost casty jav, ze su prerusenia priamo pripojene, nez aby pouzivali APICs. Ked sa pozrieme na mtable do sekcie preruseni, uvidime zaznamy , kore sa mapuju prerusenia pre (pci bus,slot, a pin) do APIC id a intpinu na APIC. Sposob akym tu je interrupt routing implementovany je ,ze ked ideme naroutovat prerusenie pre dany PCI device , prehladame mtabulku pre dany zaznam. Potom si pozrieme asociovany APIC cez APIC id , spytame sa na dany pin a jeho IRQ. Ked nexus(4) robi bus_setup_intr() , preposiela dany IRQ do x86 intr_machdep kodu , ktory pouziva IRQ ako nejaky index pre jeho presurovacie zdrojove pole a skonci s prerusovacim zdrojovym objektom pre danu (apic,pin) skupinu , ktora sa pouziva. Tieto IRQ su iba coockie , ktory je indexom do globalneho pola preruseni na x86.

Routovane prerusenia s tymto sposobom su natvrdo spojene na doske.
OS nema ziadnu moznost ako moze zmenit, ktory (pic,pin) PCI device prerusenie bude pouzivat.

Pre druhy sposob non_ACPI. PCI device prerusenia su vacsinou pripojene k pinu na programmable interrupt router (PIR). Kazdy z tychto pinov sa vola pci link device. Niekolko PCI device preruseni mozu byt nadratovane na rovnaku linku zariadenia .Systemy maju vacsinou 4-8 linky na zariadeni.

Kazde linkove zariadenie moze byt ihned routovane na patricny (pic,pin) a je limitovane moznymi IRQ, potom kazde zo zariadeni pripojenymi do oboch zlinkovanych zariadeni skoncis so sharovanymi IRQ.

Tabulka, ktoru poskytuje BIOS a obsahuje informaciu o linkovanom zariadeni sa vola PIR ( hlada sa v RAM ). Mozeme to vidiet pri verbose boot dmesgu. Je to tabulka ktora mapuje dany (bus,slot,intpin) PCI nasobok do link indexu. Kazdy zaznam ma taktiez aj bitmask moznych ISA IRQ-ciek, kde specificky link index moze byt routovany. Sposob akym interrupt routing funguje s PIR je ten , ze ked je routovany PCI interrupt , prehladavame tabulku pre zhodujuci sa zaznam , aby sme dostali link index. PIR kod je umiestneny v sys/i386/pci/pci_pir.c, obsahuje list link objektov , ktory manipuluju status kazdeho linku. Ten kod najde data, asociovane s link indexom a vidi, ci uz ma IRQ naroutovane. Ak ano, tak je to IRQ device interrpt ktory je asociovany. Ked IRQ este nieje naroutovane , tak musi pouzit algoritmus , ktory mu jedno IRQcko najde, spravi BIOS volanie na routovanie linky na vybrate IRQ a priradi PCI interuupt device na dane IRQ.

Sposob akym funguje ACPI routing je taky, ze kazdy PCI bus v ACPI namespace ma PRT metodu ktora vracia tabulku routing zaznamov. Kazdy zaznam obsahuje slot a intpin ktory aj handluje ( takze mozeme zostrojit (bus, slot,intpin) PCI nasobok ( bus pozname z PCI devicu a PTR je jeho child. Ked link device referencia je prazdna alebo NULL, vtedy je prerusenie hard-wired prerusenie take ako to s MP tabulkov , a zdrojovy index je global interrupt number (==IRQ), ktory mozeme pouzit pre dane prerusenie. Pokial link device reference nieje prazdne, tak je to meno ACPI device objektu, ktory managuje jednoduchy pci link device. Kazdy link device objekt zahrna metody na dotazovanie, na ktory IRQ je prave naroutovany., zobere list IRQ vypne link device a naroutuje link device na specificke IRQ. Je to podobne , link objektu ktory je v $PIR kode. ACPI pridavas este dalsi zavit v ktorom BIOS moze pouzit link device z ACPI ( MP tabulka sa nehandluje). Existuju aj nejake nvidia chipsety pre amd64 , ktore routuju PCI device prerusenia na link device, ktore v ACPI mode moze byt routovane na akekolvek IRQ 20-23.
Co sa tyka Intelu a PCI-X, PCI-E host bridgov vo FreeBSD, koli nedodrzovani standardov ako su MP tabulky a ACPI ( zrejme predpokladaju, ze cely svet je windows), intel pouziva nepekny "hack", ktory vsak velmi zle interoperuje s FreeBSD, koli ktorym vznikaju neziaduce stavy s pouzitim ACPI pri niektorych doskach.

iso