PB173 - Ovladače jádra - Linux VIII. Přerušení Jiri Slabý ITI, Fakulta informatiky 12. 11. 2013 LDD3 kap. 7 a 10 • Práce s časem • Pozdržení vykonávání kódu (spánek) • Časovače • Odložené vykonání kódu • Přerušení HW • Změny v kontextu přerušení • Zámky • Alokace Část I „Měkká" přerušení J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 3/ 16 Časovače a Documentation/timers/* • Činnost v nastavených časech (i periodicky) a Kód je volán v kontextu přerušení (nelze spát) • /proc/timer_list (jen nová jádra) Obyčejné časovače a Fungují na každé architektuře • Založené na jiffies • Proměnná zvyšující se o 1 s frekvencí HZ a Rozlišení: 1-10 ms (pro HZ: 1000-100) High-res časovače a linux/hrtimer.h • usleep_range • Rozlišení: ~ jits J. Slabý (ITI, Fl) PB173/02 12.11.2013 4/ 16 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) static void my.fun(unsigned long data); static DEFINE_TIMER(my_timer, my.fun, 0, 30); static void my.fun(unsigned long data) { my.timer.data *= 2; mod.timer(&my.timer, jiffies + msecs.tO-jiffies (data)); } mod-timer(&my_timer, jiffies + msecs.tO-jiffies (100)); deLtimer_sync(&my_timer); Úkol: Každou vteřinu, kdy je modul v systému, vypsat HZ a jiffies J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 5/ 16 Pozdržení vykonávání Čekání na událost trvající pevně danou dobu O Spánek • Zapojení časovače a plánovače • Rozlišení: — 10/xs až 10 ms (HW-závislé) Q Busy-waiting Smyčka • Rozlišení: ns API • linux/delay.h • ad 1. ssleep, msleep, usleep_range • ad 2. mdelay, udelay, ndelay V jádře lze čekat jen omezenou dobu (v řádu jednotek až desítek vteřin) J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 6/ 16 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 • (Na rozdíl od časovačů) 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í) J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 7/ 16 Workqueue • Speciální proces volající funkce ve frontě o 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 • Documentation/workqueue.txt J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 8/ 16 Workqueue API • linux/workqueue.h, struct work_struct • Definice funkce (práce): declare_wdrks, init_wdrkd • Globální proces: • Zařazení do fronty: scheduie_work • Vyřazení z fronty (předčasně): cancei_work_sync a Vlastní proces: • Vytvoření procesu: create_workqueue, destroy_workqueue • Zařazení do fronty: queue_work • Vyřazení z fronty: cancel_work_sync (stejně) • Delayed (s min. prodlevou): *_deiayed_work Úkol: nahrát modul ieee802ll (request_module). Nelze volat přímo v moduie_init a je nutný i vlastní proces J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 9/ 16 Tasklet • Běží v kontextu přerušení (jako časovače) • Nelze spát a 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_scheduie • Vyřazení z fronty: tasklet_kill Úkol: vytvořit tasklet, spustit a vypsat posloupnost volání pomocí dump_stack J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 10/16 Část II „Tvrdá" přerušení J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 11/16 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 • Cyklus? Priority přerušení! • OS musí obsloužit přerušení • Zjistí zdroj a zavolá odpovídající ovladač (jeho obsluhu přerušení) • Přerušeni 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í) J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 12/16 Přerušení v Linuxu • 1inux/int errupt.h • request_irq, free_irq • Flags: hlavně IRQF_SHARED • Návratová hodnota z obsluhy: IRQ_NDNE, IRQ_HANDLED • /proc/interrupts static irqretum.t my.handler(int irq, void *data) { /* data == my-data */ return my.device.raisedJnterrupt ? IRQ.HANDLED : IRQ.NONE; } static int my.probe(struct pci.dev *pdev, ...) { /* here: enable device etc. */ my.data = kmalloc(...); ret = request.irq(pdev->irq, my.handler, IRQF.SHARED, "my", my.data); } Úkol: vytvořte obsluhu pro EDU (zatím vracejte IRQ_HANDLED) J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 13/16 Přerušení a spinlocky Vlákno Přerušení spinJock(&addr_lock); spin.unlock(&addr.lock); spin.lock(&addr.lock); // deadlock 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); spinJock(&addr.lock); spin.unlock(&addr.lock); J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 14/16 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 ve workqueue) J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 15/16 Ú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 Offset Len R/W Contents Meaning 0x0024 4B R bitmap Raised interrupts 0x0060 4B W bitmap Raise interrupts 0x0064 4B W bitmap Acknowledge interrupts Tabulka : Specifikace baru 0 (pokračování z minula) J. Slabý (ITI, Fl) PB173/02 12. 11. 2013 16/16