Menurut apa yang saya baca sejauh ini, "ketika kernel menerima interupsi, semua penangan terdaftar dipanggil."
Saya memahami bahwa penangan yang terdaftar untuk setiap IRQ dapat dilihat melalui /proc/interrupts
, dan saya juga mengerti bahwa penangan yang terdaftar berasal dari driver yang telah memanggil request_irq
lewat callback kira-kira dalam bentuk:
irqreturn_t (*handler)(int, void *)
Berdasarkan apa yang saya ketahui, masing-masing callback interrupt handler yang terkait dengan IRQ tertentu harus dipanggil, dan tergantung pada handler untuk menentukan apakah interupsi memang harus ditangani olehnya. Jika handler tidak menangani interupsi tertentu, ia harus mengembalikan makro kernel IRQ_NONE
.
Yang saya mengalami kesulitan memahami adalah, bagaimana masing-masing pengemudi diharapkan untuk menentukan apakah harus menangani interupsi atau tidak. Saya kira mereka dapat melacak secara internal jika mereka mengharapkan gangguan. Jika demikian, saya tidak tahu bagaimana mereka dapat menangani situasi di mana beberapa driver di belakang IRQ yang sama mengharapkan interupsi.
Alasan saya mencoba memahami detail ini adalah karena saya mengacaukan kexec
mekanisme untuk mengeksekusi ulang kernel di tengah operasi sistem sambil bermain dengan pin reset dan berbagai register pada PCIe bridge serta PCI downstream alat. Dan dengan melakukan itu, setelah reboot saya mendapatkan panik kernel, atau driver lain mengeluh bahwa mereka menerima interupsi meskipun tidak ada operasi yang terjadi.
Bagaimana pawang memutuskan bahwa interupsi harus ditangani olehnya adalah misteri.
Sunting: Dalam kasus itu relevan, arsitektur CPU yang dimaksud adalah x86
.
Jawaban:
Ini dibahas dalam bab 10 dari Linux Device Drivers , edisi ke-3, oleh Corbet et al. Ini tersedia secara online gratis , atau Anda bisa melempar shekels O'Reilly untuk bentuk pohon mati atau bentuk ebook. Bagian yang relevan dengan pertanyaan Anda dimulai pada halaman 278 di tautan pertama.
Untuk apa nilainya, inilah upaya saya untuk memparafrasekan ketiga halaman tersebut, ditambah bit lain yang telah saya Google-Google:
Ketika Anda mendaftarkan penangan IRQ bersama, kernel memeriksa apakah:
Sebuah. tidak ada pawang lain yang ada untuk gangguan itu, atau
b. semua yang sebelumnya terdaftar juga meminta berbagi interupsi
Jika salah satu kasus berlaku, itu kemudian memeriksa bahwa
dev_id
parameter Anda unik, sehingga kernel dapat membedakan beberapa penangan, misalnya selama penghapusan penangan.Ketika perangkat keras PCI¹ mengangkat garis IRQ, penangan interupsi tingkat rendah dari kernel dipanggil, dan pada gilirannya memanggil semua penangan interupsi yang terdaftar, melewati masing-masing kembali yang
dev_id
Anda gunakan untuk mendaftarkan penangan melaluirequest_irq()
.The
dev_id
nilai perlu mesin-unik. Cara umum untuk melakukannya adalah dengan memberikan pointer ke per-perangkat yangstruct
digunakan driver Anda untuk mengelola perangkat itu. Karena penunjuk ini harus berada dalam ruang memori driver Anda agar berguna bagi driver, itu ipso facto unik untuk driver itu. ²Jika ada beberapa driver terdaftar untuk interupsi yang diberikan, mereka semua akan dipanggil ketika salah satu perangkat menaikkan garis interupsi bersama. Jika bukan perangkat driver Anda yang melakukan ini, pengendali interrupt driver Anda akan diberikan
dev_id
nilai yang bukan miliknya. Handler interrupt pengemudi Anda harus segera kembali ketika ini terjadi.Kasus lain adalah driver Anda mengelola banyak perangkat. Handler interrupt pengemudi akan mendapatkan salah satu
dev_id
nilai yang diketahui pengemudi. Kode Anda seharusnya polling setiap perangkat untuk mencari tahu mana yang mengangkat interupsi.Contoh Corbet et al. berikan adalah port paralel PC. Ketika menegaskan garis interupsi, itu juga menetapkan bit atas dalam register perangkat pertama. (Yaitu
inb(0x378) & 0x80 == true
, dengan asumsi penomoran port I / O standar.) Ketika pawang Anda mendeteksi hal ini, ia seharusnya melakukan tugasnya, lalu menghapus IRQ dengan menuliskan nilai yang dibaca dari port I / O kembali ke port dengan bagian atas. sedikit dibersihkan.Saya tidak melihat alasan mengapa mekanisme khusus itu istimewa. Perangkat perangkat keras yang berbeda dapat memilih mekanisme yang berbeda. Satu-satunya hal yang penting adalah bahwa perangkat mengizinkan interupsi bersama, itu harus memiliki beberapa cara bagi pengemudi untuk membaca status interupsi perangkat, dan beberapa cara untuk menghapus interupsi. Anda harus membaca lembar data atau panduan pemrograman perangkat Anda untuk mengetahui mekanisme apa yang digunakan perangkat khusus Anda.
Ketika interrupt handler memberitahu kernel yang menangani interupsi, itu tidak menghentikan kernel untuk terus memanggil penangan lain yang terdaftar untuk interupsi yang sama. Ini tidak dapat dihindari jika Anda ingin berbagi jalur interupsi saat menggunakan interupsi yang dipicu level.
Bayangkan dua perangkat menegaskan garis interupsi yang sama pada saat yang sama. (Atau paling tidak, sangat dekat dalam waktu sehingga kernel tidak punya waktu untuk memanggil penangan interupsi untuk menghapus garis dan dengan demikian melihat pernyataan kedua sebagai terpisah.) Kernel harus memanggil semua penangan untuk garis interupsi itu, untuk memberikan masing-masing kesempatan untuk menanyakan perangkat keras terkait untuk melihat apakah perlu perhatian. Sangat mungkin bagi dua driver yang berbeda untuk berhasil menangani interupsi dalam pass yang sama melalui daftar handler untuk interupsi yang diberikan.
Karena itu, sangat penting bahwa pengemudi Anda memberi tahu perangkat yang ia kelola untuk menghapus pernyataan interupsinya beberapa saat sebelum pengendali interupsi kembali. Tidak jelas bagi saya apa yang terjadi sebaliknya. Baris interupsi yang ditegaskan secara terus-menerus akan menghasilkan kernel yang terus-menerus memanggil penangan interupsi yang dibagikan, atau itu akan menutupi kemampuan kernel untuk melihat interupsi baru sehingga penangan tidak pernah dipanggil. Either way, bencana.
Catatan kaki:
Saya menentukan PCI di atas karena semua di atas mengasumsikan gangguan yang dipicu tingkat , seperti yang digunakan dalam spesifikasi PCI asli. ISA menggunakan interupsi yang dipicu oleh tepi , yang membuat berbagi menjadi sangat sulit, dan bahkan mungkin hanya ketika didukung oleh perangkat keras. PCIe menggunakan interupsi sinyal-sinyal ; pesan interupsi berisi nilai unik yang dapat digunakan kernel untuk menghindari permainan tebak-tebakan yang dibutuhkan dengan PCI interrupt sharing. PCIe dapat menghilangkan kebutuhan yang sangat besar untuk berbagi interupsi. (Saya tidak tahu apakah itu benar-benar terjadi, hanya saja itu berpotensi.)
Driver kernel Linux semuanya berbagi ruang memori yang sama, tetapi driver yang tidak terkait tidak seharusnya mucking di ruang memori orang lain. Kecuali Anda melewatkan pointer itu, Anda bisa yakin driver lain tidak akan muncul dengan nilai yang sama secara tidak sengaja sendiri.
sumber
dev_id
bukan miliknya. Bagi saya kelihatannya ada kemungkinan non-nol bahwa seorang pengemudi yang tidak memilikidev_id
struktur mungkin masih menganggapnya sebagai miliknya sendiri berdasarkan pada bagaimana ia menginterpretasikan konten. Jika ini bukan masalahnya, mekanisme apa yang akan mencegah hal ini?dev_id
pointer ke sesuatu di dalam ruang memori driver Anda. Pengemudi lain dapat membuatdev_id
nilai yang kebetulan membingungkan dengan pointer ke memori yang dimiliki pengemudi Anda, tetapi itu tidak akan terjadi karena semua orang bermain sesuai aturan. Ini adalah ruang kernel, ingat: disiplin diri diasumsikan sebagai hal yang biasa, tidak seperti dengan kode ruang pengguna, yang mungkin dengan anggapan menganggap bahwa segala sesuatu yang tidak dilarang diperbolehkan.dev_id
yang tidak dimilikinya.dev_id
tidak membantu Anda menentukan apakah ini telah terjadi. Anda harus bertanya pada perangkat keras, "Anda menelepon?"kexec
.Ketika driver meminta IRQ yang dibagikan, ia mengirimkan pointer ke kernel ke referensi ke struktur spesifik perangkat dalam ruang memori driver.
Menurut LDD3:
Setelah memeriksa penangan IRQ beberapa driver, tampaknya mereka menyelidiki perangkat keras itu sendiri untuk menentukan apakah harus menangani interupsi atau kembali
IRQ_NONE
.Contohnya
Driver UHCI-HCDDalam kode di atas, pengemudi membaca
Driver SDHCIUSBSTS
register untuk menentukan apakah ada gangguan pada layanan.Sama seperti pada contoh sebelumnya, pengemudi sedang memeriksa register status,
Pengemudi Ath5kSDHCI_INT_STATUS
untuk menentukan apakah perlu layanan interupsi.Hanya satu contoh lagi.
sumber
Kunjungi kunjungi tautan ini :
sumber