PB173 - Ovladače jádra - Linux VIII. Přerušení Jiri Slabý Fakulta informatiky Masarykova univerzita 11.11.2014 Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 1 / 17 Přerušení LDD3 kap. 7 a 10 O „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) Q Změny v kontextu přerušení « Zámky • Alokace, apod. Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11.2014 2/ 17 Sekce 1 „Měkká" přerušení Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 3/17 Časovače • Documentation/timers/* a Č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 jiffies • 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í: ~ jus Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 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) static void my_fun(unsigned long data); static DEFINE_TIMER(my_timer, myjun, 0, 30); static void my_fun(unsigned long data) { my_timer.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 a jiffies Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 5/17 Pozdržení vykonávání kódu Č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é) O 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) Úkol: spěte 1 vteřinu v moduie_init a vyzkoušejte vložením modulu Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 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) a 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/02 11.11.2014 7/ 17 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 a Lze v něm spát • Spustí se, až se plánovač rozhodne • Lze specifikovat minimální prodlevu • Documentation/workqueue.txt Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 8/17 Workqueue API a linux/workqueue.h, struct work_struct • Definice funkce (práce): declare_works, init_workd • Globální proces: • Zařazení do fronty: scheduie_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: cancel_work_sync (stejně) • Delayed (s min. prodlevou): *_deiayed_work Úkol: V module_init nahrát modul ieee80211 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/02 11.11. 2014 9/17 Tasklet • 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_scheduie • Vyřazení z fronty: tasklet_kill Úkol: vytvořit tasklet, spustit a vypsat posloupnost volání pomocí dump_stack Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 10/17 Sekce 2 „Tvrdá" přerušení (z HW) Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 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í • 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í) Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 12/17 Přerušení v Linuxu • linux/interrupt.h • request_irq, free_irq a Flags: hlavně IRQF_SHARED • Návratová hodnota z obsluhy: IRQ_N0NE, IRQ_HANDLED • /proc/interrupts static irqreturnj 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, my_handler, IRQF_SHARED, "my", my_data); } Úkol: vytvořte obsluhu pro EDU (zatím vracejte IRQ_HANDLED) Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 13/17 Sekce 3 Změny v kontextu přerušení Jiri Slabý (Fakulta informatiky, MU) PB173/02 11.11. 2014 14/17 Přerušení a spinlocky Vlákno spin_lock(&addr_lock); < interrupt > spin_unlock(&addr_lock); Přerušení spin_lock(&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); spin_unlock(&addr_lock); Jiri Slabý (Fakulta intormatiky, MU) PB173/02 11.11. 2014 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/02 11.11. 2014 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_nqne 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/02 11.11. 2014 17/17