Open Source im professionellen Einsatz
Linux-Magazin 06/2016
© psdesign1, Fotolia

© psdesign1, Fotolia

Kernel- und Treiberprogrammierung mit dem Linux-Kernel – Folge 86

Kern-Technik

,

Beim DMA-Transfer klemmt sich die CPU vom Bus ab und überlässt einem DMA-Controller die Regie, der Datenblöcke effizienter kopiert als sie selbst. Der Programmierer muss etwas Basiswissen über Speicherverwaltung, Adressvarianten und Cache-Kohärenz vorweisen. Nach dieser Kern-Technik kann er das.

814

Ein paar Grundlagen in technischer Informatik und etwas Mathematik reichen, um auszurechnen, dass auf der CPU ausgeführter Treibercode die beachtlichen Datenübertragungsraten von SSDs oder Gigabit-Ethernet nicht zustande bringt.

Die meisten Rechnerarten sind deswegen mit einem Controller ausgestattet, der das Kopieren von Daten selbstständig ohne Beteiligung der CPU und schnell genug für SSDs oder modernes Ethernet realisiert. Ob es sich um einen extra Baustein handelt oder ob der Controller zusammen mit der CPU (und anderen Units) auf demselben Chip sitzt, ist funktionell wenig bedeutsam.

Mit einer Quelladresse, einer Zieladresse und der Menge der zu kopierenden Daten gefüttert, kopiert der Controller in Windeseile Daten innerhalb des Hauptspeichers, aber auch zwischen Hauptspeicher und Peripherie beziehungsweise Peripherie und Hauptspeicher. Dazu hijackt er normalerweise den Systembus, greift also ohne Umwege direkt auf den Speicher zu. Daher auch der Name: Direct Memory Access (DMA).

Nützlich nicht nur für schnelle Blocktransfers

Entwickler kopieren aber nicht nur Daten per DMA, sondern realisieren damit Zero-Copy und halten harte Realzeit-Anforderungen ein. Noch pfiffiger: Sie steuern damit Pulsweiten-moduliert Gleichstrommotoren oder andere Hardware an. Wen wundert's also, dass moderne Prozessoren gleich mehrere DMA-Einheiten mitbringen?!

Der Raspberry Pi beispielsweise bietet 16 DMA-Kanäle, einige davon darf der Programmierer mit selbst geschriebenem Kernelcode und etwas Hintergrundwissen für seine Zwecke einsetzen. Dazu reserviert er einen DMA-Kanal, spezifiziert den Quell- und den Ziel-Adressbereich und startet schließlich den Kopiervorgang. Doch bis ein DMA-Controller die richtigen Daten tatsächlich von A nach B transferiert, gibt es einige Klippen zu umschiffen.

So bietet Linux derzeit kein auf alle unterstützten Plattformen portiertes vollständiges DMA-Subsystem. Es bleibt daher nur, auf plattformspezifische Funktionen auszuweichen. Auf dem Raspberry Pi reserviert die Funktion »bcm_dma_chan_alloc()« im Kernel die DMA-Kanäle (Tabelle 1). Mit den richtigen Parametern aufgerufen, liefert sie die Nummer des reservierten DMA-Kanals. Sind alle Kanäle belegt, quittiert die Funktion den Aufruf mit einem negativen Rückgabewert.

Tabelle 1

DMA-Funktionen auf dem Raspberry Pi

Prototyp

Beschreibung

Raspi-spezifisch

int bcm_dma_chan_alloc(unsigned preferred_feature_set, void __iomem  out_dma_base, int *out_dma_irq)

reserviert einen DMA-Kanal und gibt die Kanalnummer und die physische Adresse der Controllerregister zurück

int bcm_dma_chan_free(int channel)

gibt den reservierten Kanal frei

void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block)

startet den DMA-Vorgang

void bcm_dma_wait_idle(void __iomem *dma_chan_base)

wartet aktiv (Busyloop) auf das Ende des gesamten DMA-Transfers

Allgemeine Funktionen

void * dma_alloc_coherent (struct device * dev, size_t size, dma_addr_t * handle, int gfp)

reserviert Cache-kohärenten Speicher für den DMA-Transfer

void dma_free_coherent (struct device * dev, size_t size, void * cpu_addr, dma_addr_t handle)

gibt den reservierten Speicher frei

dma_addr_t dma_map_single (struct device * dev, void * cpu_addr, size_t size, enum dma_data_direction dir)

bereitet einen physisch-kontinuierlichen Speicherbereich für den DMA-Transfer vor

void dma_unmap_single (struct device * dev, dma_addr_t handle, size_t size, enum dma_data_direction dir)

macht die Abbildung eines DMA-Speicherbereichs wieder rückgängig

Geschlossene Veranstaltung

Quell- und Zielbereich gibt der Programmierer in einem DMA-Kontrollblock (Control Block, CB) an. Der ist ebenfalls plattformspezifisch. Der Raspberry Pi hält dafür die Datenstruktur »struct bcm2708_dma_cb« vor, die Variablen für die Quelle, für das Ziel, für die Anzahl der zu transferierenden Bytes und einige weitere enthält. Besonders bedeutsam ist »next« , in der entweder »NULL« oder die Adresse eines nachfolgenden Kontrollblocks liegt (Abbildung 1).

Abbildung 1: Der DMA-Controller arbeitet im Endlosbetrieb, wenn die Kontrollblöcke eine geschlossene Liste bilden.

Hat der DMA-Controller den im Control Block spezifizierten Auftrag abgearbeitet, stoppt er nicht zwingend den Transfer, sondern arbeitet den in »next« referenzierten Control Block ab. Die Kontrollblöcke lassen sich somit in einer Liste hintereinanderhängen. Zeigt der Next-Zeiger des letzten Listenelements wieder auf das erste Element (geschlossene Liste), setzt das sogar einen Endlosbetrieb in Marsch. Erst wenn der Next-Zeiger »NULL« ist, stoppt der DMA-Controller.

Im DMA-Kontrollblock ist zudem noch zu spezifizieren, ob der Controller die Daten innerhalb des normalen Hauptspeichers transferieren soll oder ob Quelle oder Ziel Peripheriebausteine sind, etwa eine serielle Schnittstelle. Genauer gesagt gibt der Programmierer an, ob jede Einzelübertragung zugleich Quell- und Zieladresse inkrementiert oder eben nicht (Abbildung 2). Da die meiste Peripherie über ein einzelnes Register angesprochen wird, ist Inkrementieren oft kontraproduktiv.

Das Element »stride« ermöglicht ein Umsortieren der Daten während des Kopierens. Handelt es sich bei einem zu transferierenden Datenblock beispielsweise um eine Matrix, so lässt sich diese per DMA transponieren, also drehen (Abbildung 3). Das ist nicht nur für Grafikanwendungen ein nützliches Gimmick [1].

Abbildung 2: Per DMA lassen sich Speicherbereiche innerhalb des Hauptspeichers kopieren, aber auch in Kombination mit Peripherie.
Abbildung 3: Das stride-Element kann veranlassen, dass der DMA-Controller eine Matrize umsortiert.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 6 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Linux-Kernel: Schwachstelle in RDS-Sockets
  • Kern-Technik

    Fertige Bibliotheken nehmen Programmierern Arbeit ab. Auch der Kernel bietet Hilfsfunktionen, obwohl er keinen Zugriff auf Libraries wie die Glibc hat. Von der Stringumwandlung bis zur Listenverwaltung findet sich allerlei Nützliches, das dieser Artikel erklärt und übersichtlich auflistet.

  • Linux-Kernel: Angreifer kann Kernelspeicher lesen
  • Cell-Kulturen

    Die Synergistic Processing Elements (SPEs) sind die Leistungsträger der Cell Broadband Engine, bekannt als Cell-Prozessor. Die Programmierung der geselligen Arbeitstiere ist allerdings etwas trickreich. Dieser Artikel erklärt sie anhand eines einfachen Beispiels unter Linux.

  • Wasserzeichen setzen

    Kleine GUI-Anwendungen eignen sich gut als Einstieg für Programmierer. Dieser Artikel zeigt, wie ein Wasserzeichen-Plugin für das KDE Imaging Plugin Interface entsteht.

comments powered by Disqus

Ausgabe 07/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.