Zgodnie z tym, co przeczytałem do tej pory, „gdy jądro odbiera przerwanie, wywoływane są wszystkie zarejestrowane programy obsługi”.
Rozumiem, że zarejestrowane moduły obsługi dla każdego IRQ można przeglądać za pośrednictwem /proc/interrupts
, a także rozumiem, że zarejestrowane moduły obsługi pochodzą od sterowników, którzy wywołali request_irq
przekazanie wywołania zwrotnego w przybliżeniu w postaci:
irqreturn_t (*handler)(int, void *)
Na podstawie tego, co wiem, każde z tych wywołań obsługi przerwań związanych z danym przerwaniem IRQ powinno zostać wywołane i to od procedury obsługi zależy, czy przerwanie powinno być przez nią obsługiwane. Jeśli moduł obsługi nie obsługuje określonego przerwania, musi zwrócić makro jądra IRQ_NONE
.
Trudno mi zrozumieć, w jaki sposób każdy kierowca powinien ustalić, czy powinien obsłużyć przerwanie, czy nie. Przypuszczam, że mogą śledzić wewnętrznie, jeśli mają spodziewać się przerwy. Jeśli tak, nie wiem, jak poradziliby sobie z sytuacją, w której wielu kierowców stojących za tym samym IRQ spodziewa się przerwania.
Powodem, dla którego próbuję zrozumieć te szczegóły, jest to, że zadzieram z kexec
mechanizmem ponownego uruchamiania jądra w trakcie działania systemu podczas gry z pinami resetującymi i różnymi rejestrami na moście PCIe, a także z dalszym PCI urządzenie. Robiąc to, po restarcie albo wpadam w panikę jądra, albo inni kierowcy narzekają, że dostają przerwania, mimo że żadna operacja nie miała miejsca.
Tajemnica polega na tym, jak przewodnik zdecydował, że przerwanie powinno zostać obsłużone.
Edycja: W przypadku, gdy jest to istotne, rozważana jest architektura procesora x86
.
Odpowiedzi:
Jest to opisane w rozdziale 10 w Linux sterowniki urządzeń , 3. wydanie, przez Corbet et al. Jest dostępny za darmo online lub możesz rzucić szeklami sposób O'Reilly na martwe drzewa lub formularze ebook. Część odnosząca się do twojego pytania zaczyna się na stronie 278 w pierwszym łączu.
Dla tego, co warto, oto moja próba sparafrazowania tych trzech stron oraz innych fragmentów, które przejrzałem w Google:
Po zarejestrowaniu współużytkowanej procedury obsługi IRQ jądro sprawdza, czy:
za. dla tego przerwania nie istnieje żaden inny moduł obsługi, lub
b. wszyscy poprzednio zarejestrowani zażądali również udostępniania przerwania
Jeśli którykolwiek z przypadków ma zastosowanie, sprawdza, czy
dev_id
parametr jest unikalny, aby jądro mogło rozróżnić wiele programów obsługi, np. Podczas usuwania programu obsługi.Kiedy urządzenie sprzętowe PCI¹ podnosi linię IRQ, wywoływany jest niskopoziomowy moduł obsługi przerwań jądra, który z kolei wywołuje wszystkie zarejestrowane moduły obsługi przerwań, przekazując każde z powrotem za pośrednictwem,
dev_id
którego użyto do zarejestrowania modułu obsługirequest_irq()
.dev_id
Wartość musi być unikalna maszynowego. Typowym sposobem na to jest przekazanie wskaźnika do urządzeniastruct
używanego przez sterownik do zarządzania tym urządzeniem. Ponieważ ten wskaźnik musi znajdować się w obszarze pamięci sterownika, aby był użyteczny dla sterownika, jest więc ipso faktyczny dla tego sterownika .²Jeśli dla danego przerwania zarejestrowanych jest wiele sterowników, wszystkie zostaną wywołane, gdy którekolwiek z urządzeń podniesie tę wspólną linię przerwania. Jeśli nie zrobiło to urządzenie twojego kierowcy, moduł obsługi przerwań twojego sterownika otrzyma
dev_id
wartość, która do niego nie należy. Osoba obsługująca przerwania kierowcy musi natychmiast powrócić, gdy to nastąpi.Innym przypadkiem jest to, że sterownik zarządza wieloma urządzeniami. Program obsługi przerwań sterownika otrzyma jedną z
dev_id
wartości znanych sterownikowi. Twój kod powinien sondować każde urządzenie, aby dowiedzieć się, które z nich spowodowało przerwanie.Przykład Corbet i in. daje to port równoległy komputera. Gdy potwierdza linię przerwania, ustawia także górny bit w swoim pierwszym rejestrze urządzenia. (To znaczy
inb(0x378) & 0x80 == true
przy założeniu standardowej numeracji portów we / wy.) Gdy moduł obsługi wykryje to, powinien wykonać swoją pracę, a następnie wyczyścić przerwanie IRQ, zapisując wartość odczytaną z portu we / wy z powrotem do portu z górną krawędzią nieco wyczyszczone.Nie widzę powodu, dla którego ten szczególny mechanizm jest wyjątkowy. Inne urządzenie sprzętowe może wybrać inny mechanizm. Jedyną ważną rzeczą jest to, że aby urządzenie zezwoliło na wspólne przerwania, musi mieć jakiś sposób, aby sterownik mógł odczytać status przerwania urządzenia, i jakiś sposób na usunięcie przerwania. Musisz przeczytać arkusz danych urządzenia lub instrukcję programowania, aby dowiedzieć się, z jakiego mechanizmu korzysta twoje urządzenie.
Kiedy twój program obsługi przerwań informuje jądro, że obsłużył przerwanie, nie powstrzymuje to jądra od dalszego wywoływania innych programów obsługi zarejestrowanych dla tego samego przerwania. Jest to nieuniknione, jeśli użytkownik ma współdzielić linię przerwania podczas korzystania z przerwań wyzwalanych poziomem.
Wyobraź sobie, że dwa urządzenia jednocześnie zapewniają tę samą linię przerwania. (Lub przynajmniej tak blisko, że jądro nie ma czasu na wywołanie procedury obsługi przerwań w celu wyczyszczenia linii, a tym samym postrzegania drugiego potwierdzenia jako osobnego.) Jądro musi wywoływać wszystkie procedury obsługi tej linii przerwań, aby dać każdemu szansę na sprawdzenie powiązanego sprzętu, aby sprawdzić, czy wymaga uwagi. Jest całkiem możliwe, że dwa różne sterowniki z powodzeniem obsługują przerwanie w ramach tego samego przejścia przez listę modułów obsługi dla danego przerwania.
Z tego powodu konieczne jest, aby sterownik poinformował urządzenie, że zarządza, aby wyczyścić swoje potwierdzenie przerwania na jakiś czas przed powrotem procedury obsługi przerwania. Nie jest dla mnie jasne, co stanie się inaczej. Ciągle potwierdzana linia przerwań albo spowoduje, że jądro będzie ciągle wywoływać wspólne procedury obsługi przerwań, albo zamaskuje zdolność jądra do zobaczenia nowych przerwań, tak że programy obsługi nigdy nie zostaną wywołane. Tak czy inaczej, katastrofa.
Przypisy:
Podałem powyżej PCI, ponieważ wszystkie powyższe zakładają przerwania wyzwalane poziomem , tak jak w oryginalnej specyfikacji PCI. ISA zastosowało przerwania wyzwalane zboczem , co w najlepszym wypadku utrudniało dzielenie się i było możliwe nawet wtedy, gdy było obsługiwane przez sprzęt. PCIe wykorzystuje przerwania sygnalizowane komunikatem ; komunikat przerwania zawiera unikalną wartość, której jądro może użyć, aby uniknąć gry polegającej na zgadywaniu w trybie round-robin wymaganej przy udostępnianiu przerwań PCI. PCIe może wyeliminować potrzebę dzielenia przerwań. (Nie wiem, czy tak się dzieje, tylko że ma potencjał).
Wszystkie sterowniki jądra Linuksa współużytkują to samo miejsce w pamięci, ale niezwiązany sterownik nie powinien chować się w przestrzeni pamięci innej osoby. Jeśli nie ominiesz tego wskaźnika, możesz być całkiem pewien, że inny kierowca sam nie wymyśli tej samej wartości.
źródło
dev_id
taki, którego nie jest właścicielem. Wydaje mi się, że istnieje niezerowa szansa, że sterownik, który nie jest właścicielemdev_id
struktury, może nadal pomylić ją z własną, w zależności od tego, jak interpretuje zawartość. Jeśli tak nie jest, to jaki mechanizm temu zapobiegałby?dev_id
wskaźnik do czegoś w przestrzeni pamięci kierowcy. Kolejny kierowca mógł uzupełnićdev_id
wartość, stało się zbliżonej do wskaźnika do pamięci sterownik jest właścicielem, ale to nie zdarzy, bo każdy bawi się zgodnie z zasadami. To jest przestrzeń jądra, pamiętaj: samodyscyplina jest zakładana oczywiście, w przeciwieństwie do kodu przestrzeni użytkownika, który może bezczelnie zakładać, że wszystko, co zabronione, jest dozwolone.dev_id
, którego nie jest właścicielem.dev_id
nie pomaga ustalić, czy tak się stało. Musisz zapytać sprzęt: „Zadzwoniłeś?”kexec
.Gdy sterownik żąda współdzielonego IRQ, przekazuje wskaźnik do jądra do odwołania do struktury specyficznej dla urządzenia w przestrzeni pamięci sterownika.
Według LDD3:
Po sprawdzeniu procedur obsługi IRQ kilku sterowników wydaje się, że sondują one sam sprzęt w celu ustalenia, czy powinien on obsłużyć przerwanie lub powrót
IRQ_NONE
.Przykłady
Sterownik UHCI-HCDW powyższym kodzie kierowca czyta
Sterownik SDHCIUSBSTS
rejestr, aby ustalić, czy nastąpiło przerwanie usługi.Podobnie jak w poprzednim przykładzie, sterownik sprawdza rejestr statusu,
Sterownik Ath5kSDHCI_INT_STATUS
aby ustalić, czy musi obsłużyć przerwanie.Jeszcze tylko jeden przykład.
źródło
Proszę sprawdzić sprawdź ten link :
źródło