PB173 - Ovladače jádra - Linux x. Jiří Slabý ITI, Fakulta Informatiky 29.11. 2011 J. Slabý (ITI) PB173/02 29. 11. 2011 1 / 11 Paměť jinak II. LDD3 kap. 15 (zastaralá) a I. (minule): Mapování paměti jádra (mmap) • II. (dnes): Přímý přístup do paměti (DMA) J. Slabý (ITI) PB173/02 29.11.2011 2/ 11 DMA Přímý přístup do paměti a Prozatím jsme ze/do zařízení četli/zapisovali přes CPU • Tj. standardními operacemi s (přemapovanou) pamětí • Velké přenosy = velká zátěž CPU • Cykly, čekání na pomalou sběrnici atd. • Místo toho naprogramujeme HW, aby přenášel data sám • Nutná podpora HW (sběrnice - arbitrace, zařízení - přenosy) J. Slabý (ITI) PB173/02 29. 11. 2011 3/11 Princip DMA Princip O Alokace (speciální) paměti 0 Pro TX: vyplnění daty (paket, zvuk, data na disk,...) 0 Předání ukazatele do zařízení O Odstartování přenosu v zařízení 0 Přerušení či jiná signalizace konce přenosu od zařízení 0 Pro RX: práce s příchozími daty (paket, data z disku,...) J. Slabý (ITI) PB173/02 29. 11. 2011 4/11 DMA v Linuxu API alokace • linux/dma-mapping.h, Documentation/DMA-* • dma_alloc_coherent, dma_f ree.coherent void *dma_alloc_coherent (struct device *dev, size.t size, dma_addr_t *dma_handle, gfp.t gfp) • dev - zařízení, které bude k paměti přistupovat (null == neznáme) a size - velikost, jakou požadujeme • dma_handie - fyzická adresa (návratová hodnota) - pro zařízení a návratová hodnota - virtuální adresa - pro nás J. Slabý (ITI) PB173/02 29. 11. 2011 5/11 DMA v Linuxu - příklad int my.dO-DMA(struct device *dev) { dma.addr.t phys ; void * v i rt ; virt = dma-alloc-coherent (dev, 100, &phys , GFP.KERNEL) ; if (! virt ) return -ENCMEM; memset( virt , 0, 100) ; my.HW.set.addr(dev, phys); my.HW.start.transfer(dev) ; while (my.HW.working(dev)) /* polling */ msleep(100) ; printk (KERN.INFO "%s" , virt); return 0; Úkol: alokujte pomocí dma_* 1 stránku paměti (pro dev = null) J. Slabý (ITI) PB173/02 29. 11. 2011 6/11 DMA pro PCI Navíc • Nastavení masky adres • Ne všechna zařízení zvládnou adresovat celý fyzický prostor • pci_set_dma_mask (pdev, DMA_BIT_MASK (27) ) • Zapnutí „spravování sběrnice" • Tj. zařízení umí samo iniciovat přenosy apod. • pci_set_master (pdev) int my.probe (struct pci.dev *pdev, ...) { dma.addr.t phys ; void * v i rt ; ret = pci.set.dma.mask(pdev , DMA.BIT.MASK(27)) ; pci.set.master (pdev) ; virt = dma.alloc.coherent(&pdev->dev, 100, &phys, GFP.KERNEL) ; } J. Slabý (ITI) PB173/02 29. 11. 2011 7/11 Combo a DMA • Zvládá 32-bitové adresy • DMA řadič napojený na LocalBus (1), PCI (2) a PowerPC (4) • Generuje přerušení 8 na kartě Úkol: upravte předešlou alokaci (set_dma_mask, setjnaster, dev) J. Slabý (ITI) PB173/02 29. 11. 2011 8/11 Combo DMA registry Offset Len R/W Contents Meaning 0x0080 4B R/W src Source address 0x0084 4B R/W dst Destination address 0x0088 4B R/W count Transfer count 0x008c 4B R/W cmd Command register Tabulka: Specifikace baru 0 (pokračování z minula) • cmd registr • Bit 0: run (transfer now) • Bits 1-3: source bus • BitS 4-6: destination bus • Bit 7: noint (do not generate interrupt after transaction) • Bit 31: ackint (acknowledge interrupt) J. Slabý (ITI) PB173/02 29. 11. 2011 9/11 Úkol Práce s DMA O Naalokovat stránku DMA prostoru O 10B inicializovat textovým řetězcem 0 Přenést 10B na PowerPC sběrnici na adresu 0x40000 • Nastavit všechny 4 registry • Bez přerušení (nastavit noint) • Počkat na nulovou hodnotu bitu run (na dokončení přenosu) O Přenést 10B z PowerPC na DMA stránku + 10 • Vznikne za sebou 2 x stejný řetězec J. Slabý (ITI) PB173/02 29. 11. 2011 10/ 11 Úkol DMA s přerušením (domácí) O Rozšířit předchozí o přerušení • Přidat ještě jeden přenos z PowerPC na DMA + 20 • Přenos bude bez noint • Je třeba povolit 8. (0x100) přerušení na kartě Q Obsloužit přerušení • ACK přerušení a DMA a Iniciovat tasklet O V taskletu vypsat obsah DMA paměti + 20 O DMA stránku vystavit přes mmap Pozn.: pokud se zařízení zasekne (např. špatně nastaveným DMA), je nutné stroj vypnout a zapnout, reboot nepomůže J. Slabý (ITI) PB173/02 29. 11. 2011 11 / 11