Linux çekirdeği paylaşılan IRQ'ları nasıl ele alıyor?


14

Şimdiye kadar okuduğum şeye göre, "çekirdek bir kesinti aldığında, tüm kayıtlı işleyiciler çağrılır."

Her bir IRQ için kayıtlı işleyicilerin görüntülenebileceğini /proc/interruptsanlıyorum ve ayrıca kayıtlı işleyicilerin, request_irqkabaca formun geri çağrısında geçiş çağrısında bulunan sürücülerden geldiğini de anlıyorum :

irqreturn_t (*handler)(int, void *)

Bildiklerime dayanarak, belirli IRQ ile ilişkili bu kesme işleyici geri çağrılarının her biri çağrılmalıdır ve kesmenin gerçekten kendisi tarafından işlenip işlenmeyeceğini belirlemek işleyiciye bağlıdır. İşleyici belirli bir kesmeyi işlemezse, çekirdek makrosunu döndürmelidir IRQ_NONE.

Ne anlamakta sorun yaşıyorum, her sürücünün kesmeyi işlemesi gerekip gerekmediğini nasıl belirlemesi bekleniyor. Sanırım bir kesinti beklerse, dahili olarak takip edebilirler. Eğer öyleyse, aynı IRQ'nun arkasındaki birden fazla sürücünün bir kesinti beklediği durumla nasıl başa çıkacaklarını bilmiyorum.

Bu ayrıntıları anlamaya çalışmamın nedeni kexec, bir PCIe köprüsünün yanı sıra bir alt PCI üzerindeki sıfırlama pinleri ve çeşitli kayıtlarla oynarken sistem işleminin ortasında çekirdeği yeniden yürütme mekanizmasıyla uğraşmam. cihaz. Ve bunu yaparken, yeniden başlatmanın ardından çekirdek panikleri ya da başka sürücüler, herhangi bir işlem yapılmamasına rağmen kesinti aldıklarından şikayet ediyorlar.

İşleyicinin kesmenin onun tarafından ele alınması gerektiğine nasıl karar verdiği gizemdir.

Düzenleme: İlgili olması durumunda, söz konusu CPU mimarisi söz konusudur x86.


1
stackoverflow.com/questions/14371513/for-a-shared-interrupt-line-how-do-i-find-which-interrupt-handler-to-usec
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Yanıtlar:


14

Bu kaplıdır bölüm 10 arasında Linux Aygıt Sürücüleri Corbet ve arkadaşlarının, 3. baskı,. Çevrimiçi olarak ücretsiz olarak kullanılabilir , ya da şekel O'Reilly'nin ölü ağaç veya e-kitap formları için yolunu atabilirsiniz . Sorunuzla ilgili bölüm ilk linkteki 278. sayfada başlıyor.

Değeri için, işte bu üç sayfayı ve Google'da bulduğum diğer bitleri açıklama girişimim:

  • Paylaşılan bir IRQ işleyicisini kaydettiğinizde, çekirdek şunlardan birini denetler:

    a. bu kesinti için başka bir işleyici yoktur veya

    b. önceden kaydedilmiş olanların tümü de kesme paylaşımı talep etti

    Her iki durum da geçerliyse, dev_idparametrenizin benzersiz olup olmadığını kontrol eder , böylece çekirdek birden çok işleyiciyi ayırt edebilir, örneğin işleyiciyi kaldırma sırasında.

  • Bir PCI¹ donanım aygıtı IRQ hattını yükselttiğinde, çekirdeğin düşük düzeyli kesme işleyicisi çağrılır ve sırayla , işleyiciyi kaydetmek için kullandığınız her bir geri geçerek kayıtlı tüm kesme işleyicilerini çağırır .dev_idrequest_irq()

    dev_idDeğeri makine-benzersiz olması gerekir. Bunu yapmanın yaygın yolu struct, sürücünüzün o aygıtı yönetmek için kullandığı aygıt başına bir işaretçi geçirmektir . Bu işaretçinin sürücüye yararlı olması için sürücünüzün bellek alanı içinde olması gerektiğinden, bu sürücüye özgü ipso facto'dur.

    Belirli bir kesinti için kayıtlı birden fazla sürücü varsa , aygıtlardan herhangi biri paylaşılan kesme hattını yükselttiğinde hepsi çağrılır . Bunu yapan sürücünüzün cihazı değilse, sürücünüzün kesme işleyicisi buna ait olmayan bir değer geçirilecektir . Bu olduğunda, sürücünüzün kesme işleyicisi derhal geri dönmelidir.dev_id

    Başka bir durum, sürücünüzün birden fazla cihazı yönetiyor olmasıdır. Sürücünün kesme işleyicisi dev_id, sürücü tarafından bilinen değerlerden birini alır . Kodunuzun hangisinin kesmeyi yükselttiğini bulmak için her aygıtı yoklaması gerekiyor.

    Örnek Corbet ve ark. PC paralel bağlantı noktasıdır. Kesme hattını verdiğinde, ilk cihaz kaydındaki üst biti de ayarlar. (Yani, inb(0x378) & 0x80 == truestandart G / Ç bağlantı noktası numaralandırmasını varsayarsak.) İşleyiciniz bunu algıladığında, işini yapması gerekir, ardından G / Ç bağlantı noktasından okunan değeri üstteki bağlantı noktasına yazarak IRQ'yu temizleyin. biraz temizlendi.

    Belirli bir mekanizmanın özel olması için hiçbir neden göremiyorum. Farklı bir donanım aygıtı farklı bir mekanizma seçebilir. Tek önemli şey, bir aygıtın paylaşılan kesintilere izin vermesi için sürücünün aygıtın kesilme durumunu okuması ve kesmeyi temizlemenin bir yolu olması gerekir . Belirli cihazınızın hangi mekanizmayı kullandığını bulmak için cihazınızın veri sayfasını veya programlama kılavuzunu okumalısınız.

  • Kesme işleyiciniz çekirdeğe kesmeyi işlediğini söylediğinde, çekirdeğin aynı kesme için kayıtlı olan diğer işleyicileri çağırmaya devam etmesini durdurmaz. Seviye tetiklemeli kesmeler kullanırken bir kesme çizgisini paylaşacaksanız bu kaçınılmazdır.

    İki cihazın aynı kesme hattını aynı anda savunduğunu düşünün. (Ya da en azından, çekirdeğin hattı temizlemek ve böylece ikinci iddiayı ayrı olarak görmek için bir kesme işleyici çağırmak için zamanı olmadığı kadar yakın.) Çekirdek, ilgilenilmesi gerekip gerekmediğini görmek için ilişkili donanımını sorgulama şansı. İki farklı sürücünün, belirli bir kesme için işleyici listesinden aynı geçiş içindeki bir kesmeyi başarıyla işlemesi oldukça mümkündür.

    Bu nedenle, sürücünüzün, kesme işleyicisi geri dönmeden bir süre önce kesme iddiasını temizlemeyi başardığını cihaza bildirmesi zorunludur. Başka türlü ne olduğu açık değil. Sürekli olarak iddia edilen kesme hattı, çekirdeğin sürekli olarak paylaşılan kesme işleyicilerini çağırmasıyla sonuçlanır veya çekirdeğin yeni kesmeleri görme yeteneğini maskeleyecek, böylece işleyiciler asla çağrılmayacaktır. Her iki şekilde de, felaket.


Dipnotlar:

  1. Yukarıda PCI'yi belirttim, çünkü yukarıdakilerin tümü orijinal PCI özelliklerinde kullanılan seviye tetikli kesintileri varsayar . ISA, kenar tetiklemeli kesmeler kullandı; bu da paylaşımı en iyi şekilde zorlaştırdı ve o zaman bile yalnızca donanım tarafından desteklendiğinde mümkün oldu. PCIe, mesaj-sinyalli kesmeler kullanır ; kesme mesajı, çekirdeğin PCI kesme paylaşımı ile gerekli olan yuvarlak robin tahmin oyunundan kaçınmak için kullanabileceği benzersiz bir değer içerir. PCIe, kesme paylaşımı ihtiyacını ortadan kaldırabilir. (Gerçekten olup olmadığını bilmiyorum, sadece potansiyele sahip olduğunu.)

  2. Linux çekirdek sürücülerinin tümü aynı bellek alanını paylaşır, ancak ilgisiz bir sürücünün başka birinin bellek alanında dolaşması gerekmez. Bu işaretçiyi etrafından geçirmedikçe, başka bir sürücünün yanlışlıkla aynı değere kendi başına gelmeyeceğinden emin olabilirsiniz.


1
Bahsettiğiniz gibi, kesme işleyicisi dev_idkendisine ait olmayan bir geçirilebilir . Bana göre, dev_idyapıya sahip olmayan bir sürücünün , içeriği nasıl yorumladığına bağlı olarak onu yine de kendi gibi yanlış yapma olasılığı sıfır gibi görünüyor . Eğer durum böyle değilse, hangi mekanizma bunu engelleyecektir?
bsirang

dev_idSürücünüzün bellek alanındaki bir şeye işaretçi olarak bunu önlersiniz . Bir başka sürücü olabilir bir makyaj dev_iddeğer oldu sürücü sahibi belleğe bir işaretçi ile confusable olmak, ama bu herkesin kurallara uyduğundan dolayı ne olacak değil. Bu çekirdek-boşluk, unutmayın: öz-disiplin, elbette, yasak olmayan herhangi bir şeye izin verilmediğini açıkça kabul edebilen kullanıcı-alan kodunun aksine, bir konu olarak kabul edilir.
Warren Young

LDD3 bölüm on göre: "İki veya daha fazla sürücünün bir kesme hattı ve donanım kesmeleri o hat üzerinde işlemci paylaştığını zaman, çekirdek her biri kendi geliştirici kimliği geçirerek, bu kesilme icin kayıtlı her işleyici çağırır" bir önceki anlayış gibi görünüyor bir kesme işleyicisinin sahip olmadığı bir işleme geçirilip geçirilemeyeceği konusunda yanlıştı dev_id.
bsirang

Bu benim açımdan yanlış okunuyordu. Bunu yazdığımda iki kavramı karıştırıyordum. Cevabımı düzenledim. Kesme işleyicinizin hızlı bir şekilde geri dönmesini gerektiren koşul, yönetmediği bir aygıtın kesinti iddiası nedeniyle çağrılmasıdır. Değeri dev_id, bunun olup olmadığını belirlemenize yardımcı olmaz. Donanıma sormak zorundasın, "Çaldın mı?"
Warren Young

Evet, şimdi neyle uğraştığımın aslında diğer sürücülerin aygıtlarının çekirdeğin yeniden başlatılmasından sonra "çaldığını" düşünmelerine neden olduğunu anlamaya ihtiyacım var kexec.
bsirang

4

Bir sürücü paylaşılan bir IRQ istediğinde, sürücünün bellek alanındaki aygıta özgü bir yapıya başvurmak için çekirdeğe bir işaretçi iletir.

LDD3'e göre:

İki veya daha fazla sürücü bir kesme hattını paylaştığında ve donanım o satırdaki işlemciyi böldüğünde, çekirdek bu kesme için kaydedilen her işleyiciyi her biri kendi dev_id'ini geçirerek çağırır.

Birkaç sürücünün IRQ işleyicilerini kontrol ettikten sonra, kesme veya geri dönüşü işlemesi gerekip gerekmediğini belirlemek için donanımın kendisini araştırıyorlar IRQ_NONE.

Örnekler

UHCI-HCD Sürücüsü
  status = inw(uhci->io_addr + USBSTS);
  if (!(status & ~USBSTS_HCH))  /* shared interrupt, not mine */
    return IRQ_NONE;

Yukarıdaki kodda, sürücü USBSTSservis kesintisi olup olmadığını belirlemek için kaydı okuyor .

SDHCI Sürücüsü
  intmask = sdhci_readl(host, SDHCI_INT_STATUS);

  if (!intmask || intmask == 0xffffffff) {
    result = IRQ_NONE;
    goto out;
  }

Önceki örnekte olduğu gibi, sürücü SDHCI_INT_STATUSbir kesintiye hizmet vermesi gerekip gerekmediğini belirlemek için bir durum kaydını kontrol ediyor.

Ath5k Sürücüsü
  struct ath5k_softc *sc = dev_id;
  struct ath5k_hw *ah = sc->ah;
  enum ath5k_int status;
  unsigned int counter = 1000;

  if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
        !ath5k_hw_is_intr_pending(ah)))
    return IRQ_NONE;

Sadece bir örnek daha.


0

Lütfen bu bağlantıyı kontrol edin :

Sadece bellek eşlemeli bir kayıttan IRQ durumunu kontrol ettikten sonra IRQ işleyicisindeki alt yarıları veya başka bir mantığı tetiklemek için alışılmış bir uygulamadır. Bu nedenle, sorun varsayılan olarak iyi bir programcı tarafından çözülür.


Bağlantınızın içeriği mevcut değil
user3405291
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.