PB173 - Ovladače jádra - Linux VIII. Přerušení Jiri Slabý Fakulta informatiky Masarykova univerzita 19. 11. 2015 Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 1 /17 Přerušení LDD3 kap. 7 a 10 Q „Měkká" přerušení • Časovače • Pozdržení vykonávání kódu (spánek) • Odložené vykonání kódu Q „Tvrdá" přerušení (z HW) ^ Změny v kontextu přerušení • Zámky • Alokace, apod. Jiri Slabý (Fakulta informatiky, MU) PB173/04 19.11.2015 2/ 17 Sekce 1 „Měkká" přerušení Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 3/ 17 Časovače • Documentation/timers/* • Činnost v nastavených časech (i periodicky) • Kód je volán v kontextu přerušení (nelze spát) • /proc/timer_iist (jen nová jádra) Obyčejné časovače • Fungují na každé architektuře • Založené na jiff ies • Proměnná zvyšující se o 1 s frekvencí hz • Rozlišení: 1-10 ms (pro hz: 1000-100) High-res časovače • linux/hrtimer.h • usleep_range • Rozlišení: ~ /is Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 4/17 Obyčejné časovače API linux/timer . h, struct timer_list DEFINE_TIMERS, setup_timerD mod_timer (=del_timer+add_timer) del_timer_sync {POZOR) Příklad static void my_fun(unsigned long data); static DEFINE_TIMER(my_timer, myjun, 0, 30); static void my_fun(unsigned long data) { myjimer.data *= 2; mod_timer(&my_timer, jiffies + msecs_toJiffies(data)); } mod_timer(&my_timer, jiffies + msecs_toJiffies(100)); del_timer_sync(&my_timer); Úkol: Každou vteřinu, kdy je modul v systému vypsat HZ (°/0u) a jiffies (°/.lu) Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 5/17 Pozdržení vykonávání kódu Čekání na událost trvající pevně danou dobu (linux/delay h) O Spánek o Zapojení časovače (tikni za ...) a plánovače (... a vzbuď mě) • Rozlišení: ^ 10 jus až 10 ms (HW-závislé) • ssleep, msleep, usleep_range O Busy-waiting • Smyčka • Rozlišení: ns • mdelay, udelay, ndelay V jádře lze čekat jen omezenou dobu (v řádu jednotek až desítek vteřin) Úkol: spěte 3 vteřiny v module.init a vyzkoušejte vložením modulu Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 6/17 Odložené vykonání kódu Při potřebě vykonat kód, který nelze vykonat teď • Držím zámek, jsem v přerušení, ... • Není nutno specifikovat pevně daný moment • (Narozdíl od časovačů) • Ale je to možné 2 druhy O Workqueue O Tasklet Rozdíly • Rychlost zavolání (tasklet dřív) • Kontext zavolání (tasklet z přerušení, workqueue z procesu) • Množství kódu (tj. rychlost vykonání) Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 7/17 Workqueue • Documentation/workqueue.txt • Speciální proces volající funkce řazené do fronty • Globální, společný pro všechny - většinou stačí • Vlastní - pro speciální případy • Lze v něm spát • Spustí se, až se plánovač rozhodne • Lze specifikovat minimální prodlevu Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 8/17 Workqueue API • linux/workqueue.h, struct work_struct • Definice funkce (práce): declare_works, init_workd • Globální proces: • Zařazení do fronty: schedule.work • Vyřazení z fronty (předčasně): cancei_work_sync • Vlastní proces: • Vytvoření procesu: create_workqueue, destroy_workqueue • Zařazení do fronty: queue.work • Vyřazení z fronty: cancei_work_sync (tj. stejně) • Delayed (s garantovanou prodlevou): *_deiayed_work Úkol: v module.init nahrát modul ieee802ll nebo mac80211 (request.module), request.module nelze volat přímo V module_init a je nutný i vlastní workqueue proces. Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 9/17 Tas kl et • Běží v kontextu přerušení (jako časovače) • Nelze spát • Musí být rychlý • Spustí se po příštím přerušení API • linux/interrupt.h, struct tasklet_struct • Definice funkce (taskletu): declare_tasklets, taskiet_initD • Zařazení do fronty: taskiet.schedule • Vyřazení z fronty: taskiet.kili Úkol: vytvořit tasklet, spustit a vypsat posloupnost volání pomocí dump_stack Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 10/17 Sekce 2 „Tvrdá" přerušení (z HW) Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 11/17 Přerušení HW • HW informuje o změně stavu • Časovač tiknul, přišel paket, přečten blok z disku, ... • CPU přeruší chod programu/jádra a zavolá jádro • Ví, koho volat, má tabulku (IDT) • Cyklus? Priority přerušení! • OS musí obsloužit přerušení o Zjistí zdroj a zavolá odpovídající ovladač (jeho obsluhu přerušení) • Přerušení je identifikováno číslem (IRQ) • Vynuluje přerušení na řadiči přerušení Nutná podpora HW (CPU, řadiče, sběrnice, zařízení) Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 12/17 Přerušení v Linuxu linux/interrupt.h request_irq, free_irq Flags: hlavně irqf.shared Návratová hodnota z obsluhy: irq.none, irq.handled /proc/interrupts Příklad static irqreturn_t my_handler(int irq, void * data) { /* data == my_data */ return my_device_raised_interrupt ? IRQ_HANDLED : IRQ_NONE; } static int my_probe(struct pci_dev *pdev,...) { /* here: enable device etc. */ my_data = kmalloc(...); ret = request_irq(pdev->irq, myjnandler, IRQF_SHARED, "my", my_data); } Úkol: vytvořte obsluhu pro EDU (zatím vracejte irq.handled) Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 13/17 Sekce 3 Změny v kontextu přerušení Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 14/17 Přerušení a spinlocky Vlákno Přerušení spin_lock(&addr_lock); spin_ Jock(&addr_lock); spin_unlock(&addr_lock); // AAA deadlock AAA spin_ _unlock(&addr_lock); irq* varianty Zákaz přerušení, poté spinlock Vlákno Přerušení spin_lock_irq(&addr_lock); // interrupt cannot trigger spin_unlock_irq(&addr_lock); spin_lock(&addr_lock); spi n_u n 1 ock(&add rj ock); Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 15/17 Kontext přerušení Další změny • Alokace • gfp.atomic • A tedy nevelké alokace • Kód • Rychlý, krátký • (Víc kódu později v taskletu, ještě víc třeba ve workqueue) Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 16/17 Úkol Práce s přerušením (součást domácího) O Vytvořit pojmenování (makra) pro registry (v tabulce) O Spustit 100ms periodický časovač (pro každé EDU zařízení) • Vyvolat z EDU přerušení 0x1000 (registr 0x60) O Navázat se v probe na přerušení (request.irq) O Implementovat obsluhu • Přečíst stav (registr 0x24), vypsat stav - limitované • Nenula: odsouhlasit přerušení (registr 0x64), vrátit irq.handled • Jinak: vrátit irq.none Specifikace baru 0 (pokračování z minula) Offset Len R/W Contents Meaning 0x0024 4B R bitmap Raised interrupts 0x0060 4B W bitmap Raise interrupts 0x0064 4B W bitmap Acknowledge interrupts Jiri Slabý (Fakulta informatiky, MU) PB173/04 19. 11. 2015 17/17