Ich arbeite mit einer seriellen Hochgeschwindigkeits-Karte für High-Rate-Datenübertragungen von einer externen Quelle zu einer Linux-Box mit einer PCIe-Karte. Die PCIe-Karte kam mit einigen Treibern von Drittanbietern, die dma_alloc_coherent verwenden, um die dma-Puffer zuzuweisen, um die Daten zu empfangen. Aufgrund von Linux-Beschränkungen begrenzt dieser Ansatz die Datenübertragung auf 4 MB. Ich habe mehrere Methoden zum Zuweisen eines großen DMA-Puffers gelesen und ausprobiert und war nicht in der Lage, einen zu aktivieren.Große PCIe DMA Linux x86-64
Dieses System hat 32 GB Speicher und läuft Red Hat mit einer Kernel-Version von 3.10 und ich möchte 4 GB davon für eine zusammenhängende DMA verfügbar machen. Ich weiß, dass die bevorzugte Methode Scatter/Gather ist, aber das ist in meiner Situation nicht möglich, da es einen Hardwarechip gibt, der das serielle Protokoll in einen DMA außerhalb meiner Kontrolle übersetzt, wobei das einzige, was ich kontrollieren kann, ein Offset ist eingehende Adressen (dh die Adresse 0, wie sie von dem externen System aus gesehen wird, kann auf die Adresse 0x700000000 auf dem lokalen Bus abgebildet werden).
Da dies eine einmalige Labor-Maschine ist, denke ich, der schnellste/einfachste Ansatz wäre, mem = 28GB Boot-Konfigurationsparameter zu verwenden. Ich habe das funktioniert gut, aber der nächste Schritt zum Zugriff auf diesen Speicher aus dem virtuellen Raum ist, wo ich Probleme habe. Hier ist mein Code an die entsprechenden Komponenten kondensiert:
Im Kernel-Modul:
size_t len = 0x100000000ULL; // 4GB
size_t phys = 0x700000000ULL; // 28GB
size_t virt = ioremap_nocache(phys, len); // address not usable via direct reference
size_t bus = (size_t)virt_to_bus((void*)virt); // this should be the same as phys for x86-64, shouldn't it?
// OLD WAY
/*size_t len = 0x400000; // 4MB
size_t bus;
size_t virt = dma_alloc_coherent(devHandle, len, &bus, GFP_ATOMIC);
size_t phys = (size_t)virt_to_phys((void*)virt);*/
In der Anwendung:
// Attempt to make a usable virtual pointer
u32 pSize = sysconf(_SC_PAGESIZE);
void* mapAddr = mmap(0, len+(phys%pSize), PROT_READ|PROT_WRITE, MAP_SHARED, devHandle, phys-(phys%pSize));
virt = (size_t)mapAddr + (phys%pSize);
// do DMA to 0x700000000 bus address
printf("Value %x\n", *((u32*)virt)); // this is returning zero
Eine weitere interessante Sache ist, dass vor allem dies zu tun, die physische Die von dma_alloc_coherent zurückgegebene Adresse ist größer als die RAM-Menge auf dem System (0x83d000000). Ich dachte, dass in x86 der RAM immer die niedrigsten Adressen sein würde und daher würde ich eine Adresse von weniger als 32GB erwarten.
Jede Hilfe wäre willkommen.
Err ... '0x770000000ULL' ist 29,75 GB, nicht 28 ... Versuchen Sie' 0x700000000' stattdessen. –
Dopen, dummer Mathefehler. Trotzdem sollte das egal sein, da dieser Bereich immer noch ein gültiger RAM sein sollte. Ich war noch nicht zu einem 4GB Testfall gegangen und benutzte immer noch nur 4MB. Wird die Frage aktualisieren. – LINEMAN78
Ich habe ein 32GB Speichersystem zur Hand. Könnten Sie eine Absolut-Barebone-Datei, aber vollständige Kernel-Modul-Quelldatei sowie ein absolut-Minimum-Usermode-Programm zum Testen bereitstellen? Warum haben Sie auch mit [C++] taggen lassen, wenn der Linux-Kernel ausschließlich [c] ist, und der von Ihnen gezeigte usermode-Snippet ausschließlich C-APIs verwendet? –