Mengganggu dari perangkat eksternal dalam sistem x86. Bagian 3. Mengkonfigurasi perutean interupsi dalam chipset menggunakan contoh coreboot

Kami terus mempertimbangkan untuk mengonfigurasi interupsi dari perangkat eksternal di sistem x86.
Pada bagian 1 ( Evolusi pengendali interupsi ), kami menguji dasar-dasar teoritis pengendali interupsi dan istilah umum, di bagian 2 ( opsi boot kernel Linux ), kami melihat bagaimana dalam praktiknya OS membuat pilihan antara pengontrol. Pada bagian ini, kita akan melihat bagaimana BIOS mengkonfigurasi routing IRQ untuk pengontrol interupsi dalam chipset.

Tidak ada perusahaan pengembangan BIOS modern (AwardBIOS / AMIBIOS / Insyde) yang mengungkapkan kode sumber program mereka. Tetapi untungnya ada Coreboot , sebuah proyek untuk menggantikan BIOS yang dipatenkan dengan perangkat lunak bebas. Dalam kodenya, kita akan melihat bagaimana interrupt routing di chipset dikonfigurasi.




Teori


Pertama, menyegarkan dan melengkapi pengetahuan teoritis kami. Di Bagian 1, kami mengidentifikasi jalur interupsi umum untuk kasus PIC dan APIC.

Foto:



APIC:



Dalam angka-angka ini, perangkat PCI → pemetaan PIR ditampilkan secara abstrak, bahkan agak rumit. Pada kenyataannya, setiap perangkat PCI memiliki 4 jalur interupsi (INTA #, INTB #, INTC #, INTD #). Setiap perangkat PCI dapat memiliki hingga 8 fungsi dan setiap fungsi sudah memiliki satu interupsi INTx #. Baris INTx # mana yang masing-masing fungsi perangkat akan tarik, apakah diperbaiki dalam perangkat keras atau ditentukan oleh konfigurasi perangkat.



Intinya, fungsi adalah blok logis yang terpisah. Misalnya, dalam satu perangkat PCI mungkin ada fungsi pengontrol Smbus, fungsi pengontrol SATA, fungsi jembatan LPC. Di sisi OS, setiap fungsi adalah perangkat terpisah dengan ruang konfigurasi PCI Config-nya sendiri.

Dalam kasus paling sederhana (dan paling umum) dalam perangkat PCI, hanya ada satu fungsi, yaitu interupsi dari yang melalui baris INTA #. Tetapi secara umum, perangkat ini bahkan mungkin memiliki lebih dari 4 fungsi (seperti yang kami katakan sebelumnya 8), maka beberapa dari mereka harus ditanam pada satu baris INTx # (interupsi PCI dapat berbagi garis). Juga, untuk perangkat PCI yang termasuk dalam chipset dengan menulis ke register khusus, seringkali dimungkinkan untuk menunjukkan fungsi mana yang menggunakan baris INTx # mana (dan apakah mereka digunakan sama sekali).

Dengan mensistematisasikan pengetahuan kami, kami menunjukkan jalur (perutean) interupsi dari fungsi PCI apa pun melalui INTx # → PIRQy → IRQz, di mana:

  • INTx # - line INT # (INTA #, INTB #, INTC #, INTD #) dari perangkat PCI yang akan digunakan fungsi tersebut
  • PIRQy - garis PIRQ (PIRQA, PIRQB, ...) dari PIR yang terhubung dengan garis INTx #
  • IRQz - IRQ line (0, 1, 2, ...) pada interrupt controller (APIC / PIC), yang terhubung ke jalur PIRQy

Mengapa Anda tidak bisa menghubungkan di mana saja INTA # → PIRQA, INTB # → PIRQB, ...?


Mengapa repot-repot mengatur perutean sama sekali? Misalkan kita memutuskan untuk tidak repot dan mendapatkan semua jalur interupsi dari semua perangkat PCI ke jalur PIRQ yang sama. Katakan ini:

  • INTA # → PIRQA
  • INTB # → PIRQB
  • INTC # → PIRQC
  • INTD # → PIRQD

Seperti yang kami katakan di atas, kasus yang paling umum adalah ketika perangkat PCI memiliki satu fungsi, dan gangguannya terhubung ke baris INTA # (karena mengapa pengembang perangkat harus memulainya secara berbeda?). Jadi jika kita tiba-tiba memutuskan untuk memulai semua baris seperti yang kita tulis, maka hampir semua interupsi dari perangkat akan dibagi menjadi baris PIRQA. Katakanlah dia berakhir di IRQ16. Kemudian setiap kali prosesor diberitahu bahwa interupsi telah terjadi pada jalur IRQ16, ia harus menginterogasi driver semua perangkat yang terhubung ke jalur IRQ16 (PIRQA) jika mereka memiliki interupsi untuk itu. Jika ada banyak perangkat seperti itu, ini secara alami tidak akan mempercepat respons sistem terhadap gangguan. Dan baris PIRQB-PIRQD dalam hal ini sebagian besar akan menganggur. Untuk kejelasan, gambar yang menggambarkan masalah:



Tapi semuanya bisa dilakukan seperti ini:



Gambarnya agak membingungkan, tetapi intinya adalah kita cukup menghubungkan garis INTx # dengan PIRQy ke round-robin (PIRQA, PIRQB, PIRQC, PIRQD, PIRQA, PIRQB, PIRQC, PIRQD, PIRQA, PIRQB, PIRQC, PIRQD,. ..)

Perlu dicatat bahwa di sini perlu untuk memperhitungkan tidak hanya bahwa jumlah fungsi PCI yang sama dimuat pada setiap baris PIRQ. Bagaimanapun, beberapa fungsi dapat membuat interupsi sangat jarang, dan beberapa secara permanen (misalnya Ethernet controller). Dalam hal ini, bahkan alokasi jalur PIRQ terpisah untuk gangguan dengan fungsi seperti itu dapat dibenarkan.

Berdasarkan hal tersebut di atas, pengembang BIOS, antara lain, memiliki tugas untuk memastikan bahwa jalur PIRQ dimuat secara seragam dengan interupsi.

Apa yang harus dilakukan BIOS?


Kami mensistematisasikan pada gambar:



  • 1) Tunjukkan baris INTx # yang masing-masing menarik fungsi perangkat PCI
    Untuk perangkat PCI eksternal, item ini tidak dilakukan, tetapi untuk fungsi perangkat PCI yang termasuk dalam chipset, itu mungkin saja.
  • 2) Konfigurasikan INTx # → pemetaan PIRQy untuk setiap perangkat PCI
    Perlu dicatat bahwa mungkin ada lebih dari empat sinyal PIRQy standar (PIRQA, PIRQB, PIRQC, PIRQD). Misalnya 8: PIRQA-PIRQH.

Sinyal PIRQy digunakan pada jalur IRQz dari pengontrol interupsi yang dipilih (APIC / PIC). Karena kami ingin mendukung semua metode pemuatan yang mungkin (lihat bagian 2 ), kami perlu mengisi kedua pemetaan:

  • 3a) Isi pemetaan PIRQy → IRQz1 untuk komunikasi PIR → I / O APIC
    Tapi biasanya ini tidak perlu, karena jalur PIRQy ditetapkan pada jalur APIC. Solusi umum adalah PIRQA → IRQ16, PIRQB → IRQ17, ... Solusi paling sederhana, karena Dengan menempatkan garis PIRQy pada garis pengontrol ≥16, Anda tidak perlu khawatir tentang konflik dengan interupsi yang tidak terpisahkan dari perangkat ISA.
  • 3b) Isi pemetaan PIRQy → IRQz2 untuk komunikasi PIR → PIC
    Ini harus disediakan jika kita menggunakan perutean melalui pengontrol PIC. Tidak ada solusi yang ambigu seperti dalam kasus APIC, karena dalam kasus PIC, orang harus menyadari kemungkinan konflik dengan interupsi yang tidak terpisahkan dari perangkat ISA.

Item keempat terakhir diperlukan untuk membantu OS dalam menentukan rute interupsi. Perangkat itu sendiri biasanya tidak menggunakan register ini.

  • 4) Isi register Interrupt Line / Interrupt Pin untuk setiap fungsi PCI
    Secara umum, register Interrupt Pin secara otomatis terisi dan biasanya Read-Only, jadi mengisi kemungkinan besar hanya akan memerlukan mengisi daftar Interrupt Line. Ini harus disediakan jika kita menggunakan perutean melalui pengontrol PIC tanpa memberi OS tabel apa pun tentang perutean perutean (lihat lagi bagian 2 ). Jika tabel disediakan dan pemetaan ini konsisten dengan tabel perutean ($ PIR / ACPI), maka OS sering meninggalkannya.

Perlu dicatat bahwa kita belum menyentuh tabel $ PIR / MPtable / ACPI dan mempertimbangkan cara mengkonfigurasi register chipset dalam hal perutean interupsi sebelum mentransfer kontrol ke loader sistem. Tabel interupsi adalah topik untuk artikel terpisah (mungkin yang akan datang).

Jadi, dasar-dasar teoretis dipelajari, akhirnya kita mulai berlatih!

Berlatih


Sebagai contoh untuk artikel dalam seri ini, saya menggunakan papan kustom dengan prosesor Intel Haswell i7 dan chipset LynxPoint-LP. Di forum ini, saya meluncurkan coreboot bersama dengan SeaBIOS. Coreboot menyediakan inisialisasi khusus perangkat keras, dan muatan SeaBIOS menyediakan antarmuka BIOS untuk sistem operasi. Pada artikel ini, saya tidak akan menjelaskan proses mengkonfigurasi coreboot, tetapi coba tunjukkan dengan contoh pengaturan BIOS seperti apa yang harus dibuat dalam chipset untuk routing interupsi IRQ dari perangkat eksternal.

Karena proyek coreboot sedang aktif dikembangkan sehingga artikel selalu up to date, kami akan mempertimbangkan kode menggunakan contoh versi tetap terbaru 4.9 (rilis 2018-12-20).

Motherboard terdekat dengan saya adalah Google Beltino dengan variasi Panther. Folder utama untuk motherboard ini adalah folder "src \ mainboard \ google \ beltino" . Semua pengaturan terkonsentrasi di sini dan kode khusus untuk board ini.

Jadi, mari kita mulai memilah mana item-item di atas dikonfigurasi:

1) Tunjukkan baris INTx # yang masing-masing menarik fungsi perangkat PCI


Informasi ini didefinisikan dalam file “src / mainboard / google / beltino / romstage.c” di struktur rcba_config melalui register DxxIP (Device xx Interrupt Pin Register (IP)). Register ini menunjukkan pin INTx # (A / B / C / D) mana yang masing-masing fungsi perangkat menghasilkan interupsi.

Opsi yang memungkinkan (lihat file "src / southbridge / intel / lynxpoint / pch.h" ):

0h = No interrupt 1h = INTA# 2h = INTB# 3h = INTC# 4h = INTD# 

Diasumsikan bahwa beberapa fungsi menggunakan pin yang sama.

Diasumsikan bahwa fungsi tidak boleh menggunakan pin untuk interupsi (Tanpa interupsi).
Semuanya seperti yang kita lihat pada gambar di awal artikel.

Kode lengkap bertanggung jawab atas barang yang ditunjuk oleh kami:

 /* Device interrupt pin register (board specific) */ RCBA_SET_REG_32(D31IP, (INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP)), RCBA_SET_REG_32(D29IP, (INTA << D29IP_E1P)), RCBA_SET_REG_32(D28IP, (INTA << D28IP_P1IP) | (INTC << D28IP_P3IP) | (INTB << D28IP_P4IP)), RCBA_SET_REG_32(D27IP, (INTA << D27IP_ZIP)), RCBA_SET_REG_32(D26IP, (INTA << D26IP_E2P)), RCBA_SET_REG_32(D22IP, (NOINT << D22IP_MEI1IP)), RCBA_SET_REG_32(D20IP, (INTA << D20IP_XHCI)), 

Untuk pemahaman yang lebih baik, pertimbangkan beberapa contoh:

Contoh 1:

Perangkat 0x1d (29 dalam desimal) memiliki satu fungsi (pengontrol EHCI).

Dalam hal ini, tetapkan interupsi ke INTA #.

00: 1d.0 - INTA #

 RCBA_SET_REG_32(D29IP, (INTA << D29IP_E1P)), 

Contoh 2:
Perangkat 0x1f (31 dalam desimal) memiliki fungsi Pengontrol Sensor Termal (00: 1f.6), pengontrol SATA 2 (00: 1f.2), pengontrol SMBus (00: 1f.3), pengontrol SATA 1 (00: 1f .2). Kami hanya ingin menggunakan pengontrol SMBus, pengontrol SATA 1 dan pengontrol Sensor Termal.

00: 1f.2 - INTA # (pengontrol SATA 1)
00: 1f.3 - INTB # (pengontrol SMBus)
00: 1f.2 - Tidak ada interupsi (pengontrol SATA 2 tidak digunakan)
00: 1f.6 - INTC # (Pengontrol Sensor Termal)

Untuk konfigurasi ini, Anda harus menulis:

 RCBA_SET_REG_32(D31IP, (INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP)), 

Contoh 3:

Dalam satu Perangkat, jumlah fungsi yang kami butuhkan lebih dari 4. Di perangkat 0x1c, setiap fungsi bertanggung jawab untuk port PCI Express. Agar port 0-5 berfungsi, dan menyela agar didistribusikan secara merata, Anda dapat mengonfigurasi ini:

00: 1c.0 - INTA # (PCI Express Port 0)
00.1c.1 - INTB # (PCI Express Port 1)
00.1c.2 - INTC # (PCI Express Port 2)
00.1c.3 - INTD # (PCI Express Port 3)
00.1c.4 - INTA # (PCI Express Port 4)
00.1c.5 - INTB # (PCI Express Port 5)
00.1c.6 - Tidak ada interupsi (port tidak digunakan)
00.1c.7 - Tidak ada interupsi (port tidak digunakan)

 RCBA_SET_REG_32(D28IP, (INTA << D28IP_P1IP) | (INTB << D28IP_P2IP) | (INTC << D28IP_P3IP) | (INTD << D28IP_P4IP) | (INTA << D28IP_P5IP) | (INTB << D28IP_P6IP) | (NOINT << D28IP_P7IP) | (NOINT << D28IP_P8IP)), 

2) Konfigurasikan INTx # → pemetaan PIRQy untuk setiap perangkat PCI


Informasi ini juga didefinisikan dalam file "src \ mainboard \ google \ beltino \ romstage.c"
dalam struktur rcba_config, tetapi sudah melalui register DxxIR (Device xx Interrupt Route Register).

Informasi dalam register ini menunjukkan baris PIRQx mana (A / B / C / D / E / F / G / H) setiap baris interupsi INTx # yang terhubung.

 /* Device interrupt route registers */ RCBA_SET_REG_32(D31IR, DIR_ROUTE(PIRQG, PIRQC, PIRQB, PIRQA)),/* LPC */ RCBA_SET_REG_32(D29IR, DIR_ROUTE(PIRQD, PIRQD, PIRQD, PIRQD)),/* EHCI */ RCBA_SET_REG_32(D28IR, DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD)),/* PCIE */ RCBA_SET_REG_32(D27IR, DIR_ROUTE(PIRQG, PIRQG, PIRQG, PIRQG)),/* HDA */ RCBA_SET_REG_32(D22IR, DIR_ROUTE(PIRQA, PIRQA, PIRQA, PIRQA)),/* ME */ RCBA_SET_REG_32(D21IR, DIR_ROUTE(PIRQE, PIRQF, PIRQF, PIRQF)),/* SIO */ RCBA_SET_REG_32(D20IR, DIR_ROUTE(PIRQC, PIRQC, PIRQC, PIRQC)),/* XHCI */ RCBA_SET_REG_32(D23IR, DIR_ROUTE(PIRQH, PIRQH, PIRQH, PIRQH)),/* SDIO */ 

Contoh 1:

Perangkat 0x1c (28 dalam sistem desimal) adalah port PCIe seperti yang sudah kita ketahui.

Kami membuat koneksi "langsung":

  • INTA # → PIRQA
  • INTB # → PIRQB
  • INTC # → PIRQC
  • INTD # → PIRQD

 RCBA_SET_REG_32(D28IR, DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD)) 

Contoh 2:

Perangkat 0x1d (29 dalam desimal) - satu fungsi (pengontrol EHCI) pada INTA #, baris lain tidak digunakan.

Hubungkan baris INTA # ke PIRQD:

 RCBA_SET_REG_32(D29IR, DIR_ROUTE(PIRQD, PIRQD, PIRQD, PIRQD)) 

Dalam hal ini, hanya catatan PIRQD pertama (untuk INTA #) yang masuk akal, sisanya tidak masuk akal.

3a) Isi pemetaan PIRQy → IRQz1 (PIR → APIC)


Seperti yang telah kami katakan, pemetaan sering diperbaiki di sini, dan kasus ini tidak terkecuali.

  • PIRQA → IRQ16
  • PIRQB → IRQ17
  • ...
  • PIRQH → IRQ23

3b) Isi pemetaan PIRQy → IRQz2 (PIR → PIC)


Dalam coreboot, isi untuk mengisi register ini didefinisikan dalam file devicetree.cb di folder motherboard "src \ mainboard \ google \ beltino \".

devicetree.cb (nama devicetree untuk komunikasi dengan konsep serupa di kernel Linux, dan "cb" adalah kependekan dari coreboot) adalah file khusus yang mencerminkan konfigurasi motherboard ini: prosesor, chipset yang digunakan, perangkat mana yang disertakan pada mereka, yang off dll Selain itu, informasi khusus untuk konfigurasi chipset dapat ditentukan dalam file ini. Ini hanya kasus yang kita butuhkan:

 register "pirqa_routing" = "0x8b" register "pirqb_routing" = "0x8a" register "pirqc_routing" = "0x8b" register "pirqd_routing" = "0x8b" register "pirqe_routing" = "0x80" register "pirqf_routing" = "0x80" register "pirqg_routing" = "0x80" register "pirqh_routing" = "0x80" 

Baris-baris ini menentukan pemetaan PIRQy → IRQz2. Dalam kode, setelah mengurai file devicetree.cb, mereka ditransformasikan menjadi variabel "config-> pirqX_routing".

Variabel "config-> pirqa_routing = 0x8b" akan berarti bahwa PIRQA terhubung ke jalur interupsi IRIC11 (0x0b = 11) dari pengontrol PIC, namun, bit yang lebih tinggi (yaitu 0x80) berarti bahwa interrupt routing tidak dilakukan. Jujur, dalam pengalaman saya ini adalah kesalahan, secara default layak menyalakan PIC routing, sistem operasi itu sendiri akan dapat beralih ke I / O APIC dengan mengatur bit ini ke 1 jika perlu.

Artinya, dalam hal ini akan lebih tepat untuk menulis:

 register "pirqa_routing" = "0x0b" register "pirqb_routing" = "0x0a" register "pirqc_routing" = "0x0b" register "pirqd_routing" = "0x0b" register "pirqe_routing" = "0x80" # not used register "pirqf_routing" = "0x80" # not used register "pirqg_routing" = "0x80" # not used register "pirqh_routing" = "0x80" # not used 

Kami tidak mengaktifkan 4 interupsi terakhir, karena Interupsi IRQ0 selalu digunakan di bawah pengatur waktu sistem dan jelas tidak tersedia (lihat Informasi Interupsi Kompatibel IBM-PC Umum ).

Tetapi jika kita melihat lebih dekat pada poin 2), kita akan melihat bahwa beberapa perangkat PCI menggunakan jalur PIRQE-PIRQH, jadi membiarkannya tidak terhubung adalah cara yang tepat untuk perangkat yang rusak.

Jadi lebih baik menulis sesuatu seperti ini:
 register "pirqa_routing" = "0x03" register "pirqb_routing" = "0x04" register "pirqc_routing" = "0x05" register "pirqd_routing" = "0x06" register "pirqe_routing" = "0x0a" register "pirqf_routing" = "0x0b" register "pirqg_routing" = "0x0e" register "pirqh_routing" = "0x0f" 


Pengisian aktual dari register yang sesuai terjadi di file src \ southbridge \ intel \ lynxpoint \ lpc.c pada fungsi pch_pirq_init.

Cuplikan kode yang bertanggung jawab untuk mengisi register:

 /* Get the chip configuration */ config_t *config = dev->chip_info; pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing); pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing); pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing); pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing); pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing); pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing); pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing); pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing); 

Konstanta alamat register dijelaskan dalam file pch.h yang sama

 #define PIRQA_ROUT 0x60 #define PIRQB_ROUT 0x61 #define PIRQC_ROUT 0x62 #define PIRQD_ROUT 0x63 #define PIRQE_ROUT 0x68 #define PIRQF_ROUT 0x69 #define PIRQG_ROUT 0x6A #define PIRQH_ROUT 0x6B 

Memetakan PIRQy → IRQz2 untuk chipset ini ditulis ke perangkat LPC PCI (alamat 00: 1f.0) di register PIRQy_ROUT. Perlu dicatat bahwa sering kali tidak semua 15 IRQz2 baris per PIC diizinkan untuk digunakan, tetapi hanya sebagian (misalnya, 3,4,5,6,7,9,10,11,12,14,15). Deskripsi register ini harus berisi informasi tentang IRQ mana yang tersedia untuk menetapkan interupsi dari jalur PIRQ kepada mereka. Jadi, pemetaan yang diusulkan oleh kami di atas hanya mungkin jika penugasan PIRQ pada jalur IRQ3, IRQ4, IRQ5, IRQ6, IRQ10, IRQ11, IRQ14, IRQ14, IRQ15 tersedia. Tetapi jika kita hati-hati melihat komentar sebelum fungsi pch_pirq_init, kita akan melihat bahwa itu adalah:

 /* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control * 0x00 - 0000 = Reserved * 0x01 - 0001 = Reserved * 0x02 - 0010 = Reserved * 0x03 - 0011 = IRQ3 * 0x04 - 0100 = IRQ4 * 0x05 - 0101 = IRQ5 * 0x06 - 0110 = IRQ6 * 0x07 - 0111 = IRQ7 * 0x08 - 1000 = Reserved * 0x09 - 1001 = IRQ9 * 0x0A - 1010 = IRQ10 * 0x0B - 1011 = IRQ11 * 0x0C - 1100 = IRQ12 * 0x0D - 1101 = Reserved * 0x0E - 1110 = IRQ14 * 0x0F - 1111 = IRQ15 * PIRQ[n]_ROUT[7] - PIRQ Routing Control * 0x80 - The PIRQ is not routed. */ 

4) Isi register Interrupt Line / Interrupt Pin untuk setiap fungsi PCI


Dalam ruang konfigurasi PCI (setiap PCI memiliki fungsi sesuai standar) ada 2 register yang menarik bagi kami:

  • 3Ch: Interrupt Line - di sini Anda perlu menulis nomor IRQz2 (angka dari 0 hingga 15), angka interupsi yang akhirnya menarik fungsi ketika menggunakan pengontrol PIC
  • 3Dh: Interrupt Pin - menunjukkan baris INTx # (A / B / C / D) mana yang digunakan fungsi

Mari kita mulai dengan yang terakhir. Register Interrupt Pin akan diisi secara otomatis berdasarkan pengaturan chipset (register DxxIP) yang dibuat oleh kami dalam paragraf 1 dan akan menjadi Read-Only.

Jadi yang tersisa hanyalah mengisi register Interrupt Line dengan interupsi IRQz2 untuk setiap fungsi PCI.

Mengetahui pemetaan PIRQy → IRQz2 (item 3b), dan pemetaan INTx # → PIRQy (item 2), Anda dapat dengan mudah mengisi register Interrupt Line untuk setiap fungsi, mengetahui INTx # interrupt yang digunakannya (item 1).

Di coreboot, register Interrupt Line juga terisi dalam file src \ southbridge \ intel \ lynxpoint \ lpc.c dalam fungsi pch_pirq_init:

 /* Eric Biederman once said we should let the OS do this. * I am not so sure anymore he was right. */ for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) { u8 int_pin=0, int_line=0; if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI) continue; int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN); switch (int_pin) { case 1: /* INTA# */ int_line = config->pirqa_routing; break; case 2: /* INTB# */ int_line = config->pirqb_routing; break; case 3: /* INTC# */ int_line = config->pirqc_routing; break; case 4: /* INTD# */ int_line = config->pirqd_routing; break; } if (!int_line) continue; pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line); } 

Untuk beberapa alasan, kode ini menyiratkan bahwa pemetaan dalam hal apapun INTA # → PIRQA, INTB # → PIRQB, INTC # → PIRQC, INTD # → PIRQD. Meskipun dalam praktiknya kami melihat bahwa itu mungkin berbeda (lihat paragraf 2).

Umumnya "Eric Biederman pernah berkata", dan kami menyalinnya di mana saja:

 $ grep "Eric Biederman once said" -r src/ src/southbridge/intel/fsp_bd82x6x/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/i82801gx/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/i82801ix/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/lynxpoint/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/sch/lpc.c: /* Eric Biederman once said we should let the OS do this. 

Secara umum, coreboot tidak terlalu peduli dengan dukungan interrupt legacy. Sangat terkejut dengan kesalahan ini tidak layak. Saat memuat OS modern, ini tidak akan mengganggu Anda, tetapi jika Anda tiba-tiba perlu memuat Linux dengan opsi "acpi = off nolapic", maka ini hampir tidak mungkin dilakukan.

Kesimpulan


Sebagai kesimpulan, kami akan mengulangi informasi khas yang perlu dikonfigurasi dalam chipset untuk routing interupsi PCI:

  1. Tunjukkan baris INTx # mana yang setiap fungsi PCI tarik
  2. Konfigurasikan INTx # → pemetaan PIRQy untuk setiap perangkat PCI
  3. Isi pemetaan PIRQy → IRQz1 (PIR → APIC) dan pemetaan PIRQy → IRQz2 (PIR → PIC)
  4. Isi register Interrupt Line / Interrupt Pin dari ruang konfigurasi PCI untuk setiap fungsi PCI.

Source: https://habr.com/ru/post/id440304/


All Articles