Hallo, vielleicht eine ziemlich blöde Frage, weiß ich nicht. Aber ich stehe vor einem (kleinen?) Problem. Ich habe hier ein PCIe Dev Kit von Altera und soll u. A. Daten vom FPGA an den PC senden. Nachdem ich mir die DMA Beispiele angesehen und die Dokus gelesen habe ist meine Überlegugn nun, ob es nicht auch ohne DMA geht. Der ganze DMA Kram (zumindest in der vorhandenen Beispielanwendung) wird im Design recht groß und ich steige da noch nicht ganz durch (kann sich ja noch ändern). Das Prinzip das hier benutzt wird (Daten vom PC in ein DMA Register im FPGA schreiben, dieser wird dadurch gestartet und schickt die Daten aus dem angegebene Adressbereich an den ebenfalls angegebenen Adressbereich des PCs) klingt für mich simpel. Nun ist die Frage, ob ich das auch ohne DMA (Controller) realisieren könnte. Dann würde doc hschätzungsweise die CPU sich damit rumschlagen müssen!? Wäre kein Problem. Die bestehende anwendung läuft auf einem Pentium I, wird aber durch nen Core2 ersetzt. Was ich damit sagen will, die CPU sollte dafür genügend reserven haben. Ich kann bisher Daten in beide Richtungen senden (nutze bisher Windriver von Jungo, war dabei, bin aber nicht der Softwareexperte und habe daher bisher nur damit rumprobiert, allerdings scheint mir das ganze nur bedingt flexibel zu sein). D. h. ich kann mit dem Windriver Daten ans PCIe Board senden, dort wertet sie meine Logik aus und antwortet z.B. darauf. Nun würde ich halt gerne, nachdem der PC den Befehl gesendet hat, größere Datenmengen (im niedrigen MB Bereich) an den PC senden. DMA kam mir da natürlich als erstes in den Sinn, scheint mir aber recht kompliziert zu implementieren zu sein. Jetzt aber mal zu der eigentlichen Frage: 1. Ist es mein beschriebenes vorgehen (ohne DMA Controler) möglich? Also Daten vom PCIe Board an Speicherbereiche des PCs zu schicken und diese Dort (nachdem z.B. nen Interrupt ausgelöst wurde) auszulesen? 2. Wie reserviere ich für soetwas einen Speicherbereich am PC? Mei nerster Gedanke was malloc(). allerdings wird dies wohl so einfach nicht gehen, der Speicherbereich wird ja für das laufende Programm reserviert und ja auch nur im virtuellen Speicher freigegeben. 3. Falls es so funktioniert wie ich es vor habe, wie sieht es mit Geschwindigkeit aus? 4. Welche Alternativen hätte ich? Vielleicht kann mir da ja jemand helfen, vielleicht bin ich ja auch völlig auf dem Holzweg. KDC
Ich hab da wohl eben ein wenig Halbwissen von DMA durcheinander gebracht. Die eigentlichen Fragen bleiben aber bestehen.
Hallo KDC, also vorab, ich denke, wenn Du so etwas noch nie gemacht hast, brauchst Du ca. 4 Wochen bis das alles läuft wie Du es haben willst. Vielleicht etwas schneller wenn Du das alles mit Junko machen willst. Du brauchst aber auf jeden Fall einen Gerätetreiber. Zu Deiner eigentlichen Frage, ob Du 'einfach' vom End-Point ins PC schreiben kannst, leider nein. Du schreibst ohnehin nie zum CPU sondern der MEM Schreib- oder Lesezugriff von Deinem End-Point wird vom Chipset (z.B. Intel ICH, I/O Controller Host) abgefangen und ins Systemspeicher umgeleitet. Nächster Punkt, es muss vorher ein Zielbereich im System Speicher gelockt werden (sonst kriegs't einen schönen Blue Screen o.ä). Hier gibt es verscheiden Ansätze. Hängt z.B. davon ab, ob Applikations (User Mode) SW auch auf die Adressen zugreifen soll/darf oder nicht. So oder so (User Mode oder Kernel mode only) muss dann die sog. Scatter/Gather List, die den Zielbereich im Speicher beschreibt, an Dein DMA Controller übermittelt werden. Dein HW kann dann diese Adressen verwenden. Wenn Du Windows im Sinn hast, würde ich der umfangreiche WDK (Windows Driver Kit) von der MS Webseite holen und ein sog. KMDF (Kernel Mode Driver Framework) Treiber schreiben. Es gibt einige Beispiele auch für PCI. Wenn Du Linux im Sinn hast, ist m.E. die Information leider recht verteilt. Ein guter Startpunkt ist der Rubini Buch, "Linux Devce Drivers". Es gibt sogar irgendwo eine Online version (google, wikipedia etc.). Die Grundkonzepte zwischen Win und Linux sind recht ähnlich. Zusammengefasst: Wenn Dein End-Point ein DMA Master sein will, brauchst Du leider unbedingt einen Gerätetreiber. Ich denke bis das Fundament steht hast Du schon so ca. 500 'C'-Codezeilen zu schreiben. Das Testen kann nervig sein, vor allem unter MS. Bzgl. des Durchsatzes ohne DMA. Das geht nur wenn die CPU auf Deine Karte schreibt. Hier wirdst Du kaum über 2,5 MByte (typ. Response Zeit von 1.6 us für ein DWord) beim Lesen bzw. 10 MB beim Schreiben kommen (schneller weil keine Completions). Viel Erfolg, Charles
Hi Charles, also erstmal zum Gerätetreiber: Da nutze ich zur Zeit halt den Jungo Treiber, der auch DMA kann. Das Dumme ist nur, dass Altera sowohl von der Hardware als auch vo nder software her keinen Quelltext für die DMA Beispiele zur Verfügung stellt bzw. gibt es für das einzige offene VHDL Beispiel keine spezielle Software die mit dem Beispiel zurechtkommt. Es ist so, dass ich das ganze für meine Diplomarbeit brauche. Bisher habe ich wie gesagt den PCIe Core am laufen, kann auch Daten schreiben (Memory Write Request) und Lesen (Memory Read Request + Completion). Dabei komme ich tatsächlich auf geschwindigkeiten im niedrigen MB/s Bereich. Die Sache ist die, dass ich für den Treiber eigentlich gar nicht zuständig sein sollte, das sollte ein anderer Diplomand machen. Allerdings ist der noch nicht verfügbar. Die Anwendung soll im Endeffekt utner Linux laufen. Da ich aber im Endeffekt mit der Geschichte weniger zu tun haben sollte/wollte, habe ich unter windows den Jungo Treiber verwendet, auf dem basieren auch die Altera Beispiele und man brauchte helt nicht viel machen und er lief out-of-the-Box mit einigen Beispielen (dummerweise kein offenes DMA Beispiel). Linux soll ja im prinzip vom Treiberschreiben einfacher sein. Da gibt es auch einen OpenSource Treiber von einem anderen User, der aber nicht vollständig ist. Könnte ich aber zur Not drauf aufbauen. Zum DMA: Das mit den Adressbereichen und dem freigeben ist mir schon klar, kann ja nicht einfach mal eben irgendwelche wichtigen/benutzten Speicherbereiche platt machen. Bluescreen ich komme! Meine Frage diesbezügliche wäre ja, ob und wie ich die Bereiche für externe Zugriffe freigeben könnte. Ich habe das mit dem DMA bisher so verstanden: Ich schieb dem FPGA Infos in sein Register (Quell Adresse, Ziel Adresse, Länge, etc.) und sag ihm er soll den Transfer starten. Und er überträgt dann die Daten als Memory Write Request mit der entsprechenden PC Adresse die Daten an den PC. Mein Problem ist, dass ich mir gerne den ganzen Kram an DMA Logik im FPGA sparen würde (sofern möglich) da ich nur in Richtung PC senden möchte, und das auch "nur" 4MB und auch nicht in zerstückelte Speicherbereiche sondern am Stück. Vier Wochen wären kein Problem ^^ Meine Frage ist halt, ob/wie ich den Speicherbereich am PC freigeben könnte, ob der Ansatz so funktioniert (also im Endeffekt nur Daten vom FPGA aus an die Speicherbereiche am PC schicken, die Bereiche hab ich dem FPGA natürlich vorher mitgeteilt) und welche Geschwindigkeit dabei zu erzielen ist. Ich hab mit mit dem "Software" Logic-Analyzer halt das angesehen, was das DMA Beispiel im DMA Transfer macht, und das war nur TLPs (Memory Write Req) senden.
Hallo, Ich glaube Du haust da zwei Sachen drucheinander, wenn dein PCIe Core einen Memorywrite initiert IST das ein DMA. Da beisst sich Maus keinen Faden ab. Ich glaube wo Du dich vor fürchtest ist Scatter/Gather sprich eine Liste von (4kB) Blöcken abzuarbeiten, welche Dir der Treiber zur Verfügung stellen muss... Scatter/Gather ist sicherlich guter Stil, jedoch nicht unbedingt notwendig. Wenn Du einen Treiber baust der Dir bei Systemstart einen entsprechend grossen Speicherbereich alozierst, dann bekommst Du den (im Normalfall) auch am Stück zur Verfügung gestellt. Du musst Dir dann noch die physikalische Adresse zu deinem Speicherbereich geben lassen, dafür gibt es Betriebsystemfunktionen. Der rest läuft dann wie Du schon gesagt hast, über einfache Writes. Die zu erzielende Geschwindigkeit ist dabei höher als bei Scatter/Gather, da Dir du keine Zeit zum Übertragen von Tabellen benötigst. Gruß Andreas
Hi KDC, mir ist immer noch nicht ganz klar wie Eure gesamte Arbeit ausschauen soll. Kommt dann noch eine Applikation SW dazu, die die Daten irgendwie visualisieren/auswerten soll oder was macht Ihr damit. Denn, normalerweise wird der Datenverkehr immer von einer Applikation-SW, auch natürlich Demon, Dienst o.ä, eingeleitet. Dein Hardware kann von sich aus eigentlich nur über Interrupts eine Betriebssystem aktivität auslösen aber da wird es richtig aufwendig. Falls Dein HW Daten im Speicher sozusagen auf Vorrat halten soll, dann wird in der Regel ein Treiber vorher einen Speicherbereich reservieren (z.b. kmalloc) und die Adresse von diesem Puffer in die HW schreiben. Das Gesamtsystem würde aber eher so ausschauen. Eine Applikations-SW (auch Demon natürlich) hat z.B. fH = open("/dev/irgendwas", PARAMS); BytesRead = read(fH, buf, sizeof(buf)); Das System weiss welcher Treiber sich hinter "/dev/irgendwas" verbirgt. Dein Treiber hat einen Callback vereinbart der vom System aufgerufen wird als Folge des 'read' Befehls oben. Als Parameter bekommt er einen Zeiger auf 'buf', einen Puffer im User Space. Der Treiber reserviert dann normalerweise Kernelspeicher (kmalloc) und übergibt diese Adresse an Dein HW. Wenn der HW signalisiert hat, dass er fertig ist (Interrupt, Polling eines Status Regs etc. etc.) kopiert der Kernel die Daten nach '*buf' mit copy_to_user() und der read() Befehl wird abgeschlossen. Was ich zeigen will ist, ein DMA Treiber ist alles andere als trivial. Meine persönliche Meinung ist, wenn der Treiber eh von einem Komilitonen geschrieben werden soll und Dein Thema eigentlich der HW ist, konzentriere Dich doch lieber auf einer vernünftigen Simulation für Dein Konzept. Die Altera Umgebung ist doch diesbzgl. gar nicht so schlecht. Die gewünschte Übertragungsrate wirdst Du auf jeden Fall im Zielsystem erreichen. Mit DMA kommst Du problemlos in Richtung 100 MByte vielleicht sogar bis hinauf zu ca. 180 MByte oder so (x1 PCIe). Letzendlich muss nur der Treiber Dein HW schnell genug mit Zieladressen versorgen. Ein Vorschlag für Dein DMA Controller wäre ein 64bit x N Zieladressen-FIFO, der vom Treiber periodisch gefüllt wird. 64 Bit weil 48 Bit Start-Adresse (IA64 Hardware) + Grösse des Zielbereichs. Du spezifizierst dann Deinen Komilitonen was die maximale Bereichsgrösse ist, die Du bearbeiten kannst (z.B. 32 KByte oder 64 KByte). Dein Controller holt sich dann sequentiell Ziel-Deskriptoren aus diesem FIFO und beschreibt sie mit posted PCIe Pakete. Du brauchst natürlich auch ein Signalisierungsmechanismus wenn ein Bereich abgeschlossen ist (Interrupt, Register Polling, Stempel an eine andere Speicheradresse etc etc.) Nochmals, viel Erfolg Charles
Danke ihr beiden! Das hat mir schon einiges gebracht, in dem es mich im Endeffekt bestätigt hat, dass meine grundsätzliche Idee nicht ganz bescheuert war ;) Die Anwendung gibt im Endeffekt gelegentlich (natürlich von einer Software gesteuert) Befehle an eine Logik, die damit einen Testchip beschaltet. Irgendwann ist der Punkt erreicht, wo der Speicher im Testchip ausgelesen werden soll. Das sind maximal 4 MB. Daher reicht es mir im Endeffekt, Daten als normalen Memory Write Request an das FPGA zu schicken, und halt nach einiger Zeit(dann aber halt auch möglichst schnell) die Daten aus dem Chip Speicher zu lesen. Wie gesagt, der Rest funktioniert soweit ganz gut, ich würde jetzt halt nur gerne den Abtransport der Daten realisieren. Dazu nochmal meine überlegungen: 1. PC reserviert Speicher. 2. PC Teilt FPGA die Adresse des reservierten Speichers mit 3. FPGA sendet die Daten (sofern PCIe Core sagt es sei Ready) hintereinander weg an die (natürlich mit Inkrementierung) erhaltene Speicheradresse 4. Wenn das FPGA fertig ist sendet es eine MSI mit Interrupt an den PC 5. Wenn der PC den Interrupt empfängt (alternativ Polling) holt die Software sich die Daten und wertet sie aus/speichert sie in eine Datei Das war im Prinzip so, wie ich es mir vorgestellt hatte, und wie ihr es auch beschrieben habt, oder? Dann noch zwei kurze Fragen dazu: 1. Wie groß können die reservierten Speicherbereiche sein? 2. Wenn ich es z. B. mit kmalloc mache, habe ich dann die tatsächliche physikalische Adresse? Oder wie komme ich da dran? Und der Chipsatz/PCIe Bus kann einfach in den Speicherbereich schreiben auch wenn ich ihn (in der anwendung) reserviert habe? Reservierung ist also nur für das Betriebsystem? Zum Thema Simulieren: Ja, von Altera gibt es da Simulationswerkzeuge, wobei mir eigentlich der praktische Test immer lieber ist (zumindest bei so einer Anwendung).
Hi KDC, Deine Punkt 1) bis 5) sind so in Ordnung. Nur nebenbei, MSI ist aus PCIe sicht kein Interrupt sondern ein Memory Write an eine vom System vorgegebene Adresse. Der 1 DWord Payload wird, bis auf den unteren acht Bits (der Vektor), auch vom System vorgegeben. Noch ein Punkt: Windows-XP (und früher) kann kein MSI. Ach ja noch ein Punkt, wenn Dir PCIe Kompatibilität im Sinne der Spec. ein Anliegen ist, musst Du auch Legacy Interrupts (INTA bis INTD Messages) unterstützen, wenn Du Interrupts implementierst. Das System 'entscheidet' dann welches Du benutzen darfst und trägt das in die Konfiguration Space ein. kmalloc() reserviert physischen Speicher und zwar bis zu einer maximalen Größe von ca. 128 KByte (ja, Kilo). Für größere Bereiche gibt's vmalloc() aber dann musst Du (genauer gesagt Dein Treiber Kollege) letzendlich eine Scatter/Gather Liste der physischen Adressen anfordern und dies dann an den FPGA übertragen. vmalloc() bekommt einen virtuellen Speicherbereich. Ich denke, wenn Du ein S/G-Listen FIFO in Deinem DMA Kanal implementierst, bist Du hier sehr flexibel auch gegen späteren Änderungen im Treiber Konzept. Der Treiber muss Dein HW nur mit Adressen versorgen. Es ist dann egal, ob der Treiber mit einem grossem (virtuellen) Puffer, mit Wechsel Puffer oder noch was arbeitet. Dein HW arbeitet natürlich mit physischen Adressen. Das mit dem Simulieren verstehe ich. Auch ich sehe natürlich lieber persönlich nach, ob etwas 'blinkt und rappelt' nur ab einer gewissen System Komplexität ist das leider nicht mehr effektiv. Vor allen die Fehleranalyse kann uferlos sein. M.E. hast Du diese Komplexitätsschwelle schon überschritten. Ich würde wenigstens zweigleisig fahren. Grüße, Charles
Das MSI kein Interrupt ist war mri schon klar, gibt je keine weiteren Signalleitungen sondern geht alles über die eine tx Leitung, somit muss das ja quasi ein normales Datenpaket mit speziellem Inhalt sein. Aber danke nochmal für den Hinweise. Genauso dass XP kein MSI kann, hatte ich irgendwo schon gelesen, aber wieder verdrängt. Ich bin grad dabei mich mal ein wenig mit Linux auseinander zu setzen. Es gibt ja dieses Buch aus dem O'Reilly Verlag welches kostenlos als pdf zur Verfügung steht über Linux Treiber. Da steht übrigens drinne, dass mit free_pages (oder so) und order=9 irgendwas um die größenordnung 512kB möglich sein soll. Bei so großen Bereichen muss man ja aber sicherlich drauf aufpassen, ob die wirklich allociert werden können wenn sie am Stück zur Verfügung stehen müssen. Da gehts dann vielleicht, wie du ja auch vorschlägst, Richtung Scatter/Gather. Muss ich mir mal ansehen. Und nochmal zur Simulation: Ich hab bisher nur einmal diesen Altera BFM verwendet und ein Beispiel zu testen. Ist das wirklich viel effizienter das darüber zu machen als mit SignalTap sich einfach z.B. den Datenverkehr und einige andere Signale anzusehen? Wie gesagt, Simulieren habe ich bisher vernachlässigt, nur um einzelne Logik Blöcke zu testen habe ich das benützt.
Ein paar Fragen sind so heute beim lesen noch aufgetaucht: 1. Wie bekomme ich unter Windows nen zusammenhängenden physikalischen Adressbereich und dessen Adresse? 2. Kann ich per Memory Write Request ohne sonstige Einstellungen in den Speicher schreiben (vom FGPA aus) oder muss ich am PC dafür noch irgendwas vorbereiten? (ausser Bereich freigeben) 3. Wenn ich am PC in den Speicherbereich vom PCIe Board schreibe(also z. B. das erste Byte von Bar0) wird dass dann vom Root Complex automatisch in ein TLP umgewandelt oder muss ich da selber aktiv werden. Ich glaub das wars. Windows deswegen, weil ich da halt mit Windriver von Jungo nen einfaches Toolkit habe, womit ich auch schon kleine Testsoftware geschrieben habe und was für mich, der sich eigentlich nicht um die Treiberseite kümmern soll, wesentlich simpler und unaufwendiger ist. Die dritte frage richtet sich aber doch eher an Linux, damit hab ich heute rumgespielt, aber leider kein Modul geladen bekommen :/
Hi KDC, mit den 512 KB wäre ich tatsächlich vorsichtig. Ich kenne nur die Angabe, dass kmalloc() bis 128 KByte spezifiziert ist. Kann schon sein, dass neuere Kernel Versionen diese Zahl noch mal erweitert haben. Habe ich mich ehrlich gesagt nicht drum gekümmert. Ich verwende meistens vmalloc(). Wenn kmalloc() nicht die gewünschte Anzahl zurückliefern kann, liefert er meines Wissens keine (retcode = 0). Als Vergleich, unter Windows habe ich mal in einen Treiber ein Tracer eingebaut, der die Größe der einzelnen S/G-List Elementen ausgegeben hat. Gleich nach dem Laden habe ich 4 mal 20 MByte angefordert (für 4 DMA Kanäle). Ich habe nie gesehen, dass ein S/G Element größer als 3 Seiten (3 x 4K Byte) war. Ich bin noch nicht dazu gekommen, die Messung unter Linux zu wiederholen. Bzgl. der Simulation, das Problem mit dem SignalTap ist, dass Du nur ein oder wenige Übertragungen anschauen kannst. Mit der Simulation, kannst Du z.B. eine ganze Regression Sequenz übers Wochenenende laufen lassen. Es ist eine Weile her seitdem ich mir das Altera BFM angeschaut habe. Damals zumindest war es auf verilog bassiert, sah aber sehr vernünftig aus. Ich hoffe, dass Dein Simulator mixed language (VHDL/Verilog) kann. Grüße, Charles
@KDC 2.) ohne IOMMU nicht, also generell nicht 3.) ja Passend fuer die Anwendung ist pci_alloc_consistent wenn man frueh nach dem booten alloziiert bekommt man auf jeden Fall 2 MB. Bei entsprechender Fragmentierung bekommt man aber nicht mehr als 4kB. (bzw. eine page)
Danke euch beiden für die Antworten! Wobei ich mir jetzt bei Frage drei nicht sicher bin mit deiner Antwort. Ich mach sowas auch, aber auf "oder-Fragen" mit ja antworten ist immer etwas unglücklich ;) aber ich nehme mal an du meinst er macht daraus automatisch nen TLP (sonst hättest du ja evtl. noch mehr dazu geschrieben). Wie gesagt, danke euch allen, das einzige was ich leider immer noch ned wei ist, wie ich bei Windows an freien physikalischen Speicher kommen. Aber das lässt sich ja hoffentlich rausfinden. KDC
@KDC Ja, hab die Frage nicht ganz gelesen, wird natuerlich automatisch umgewandelt. BTW. ich wuerde an deiner Stelle den Treiber selbst schreiben und auch etwas testcode, denn Du weisst nicht wielange es dauert bis der andere Diplomand mit seinem Zeug voran kommt. Mach daraus einfach noch ein Kapitel in deiner DA.
Hi KDC, wie Du unter Windows an physischen Speicher kommst ist aus dem Stand nicht so einfach. Aus dem User Mode (d.h. Borland, VisualXxx usw.) geht das überhaupt nicht. Windows versucht verzweiflet den unbedarften vor sich selbst zu schützen. Am Anfang hast Du erwähnt, Du würdest mit Jungo arbeiten. Falls Jungo die Einbindung von Funktionen aus der Windows WDK erlaubt, würde ich versuchen Speicher in der gewünschten Größe aus dem Kernel non-paged Pool anzufordern. Aber 4 MByte ist schon ziemlich Richtung Obergrenze für Speicher Blöcke, die aus dem Pool angefordert werden sollten. Der Aufruf wäre ExAllocatePoolWithTag(type, nbytes, tag) type : NonPagedPool tag : Ein Bezeichner, wenn ich mich recht errinnere, max 6 Zeichen und vermutlich auch noch als UNICODE string. Ich muesste nachschauen. Rückgabe Wert ist ein Pointer auf eine Virtuelle Adresse. Du kannst MmGetPhysicalAddress(PVOID baseAddr) verwenden um die physische Adresse zu bekommen. Nachdem ich das gesagt habe, muss ich leider auch gleich sagen, Microsoft weisst darauf hin, dass diese Methode nicht für DMA verwendet werden soll. Ich habe es nur erwähnt, weil es zusammen mit Jungo funktionieren könnte (nie probiert, habe kein Jungo). Wenn man es 'richtig' machen will, wird es wirklich kompliziert. Vergiss nícht, ich habe schon am Anfang von ca. vier Wochen gesprochen. Wenn Du wirklich ein eigener Bonsai Treiber schreiben willst, damit Du z.B. den TLP Inhalt in einem Borland/VisualXxx Program sehen möchtest, hast Du einiges vor Dir. Als erstes, WDK und SDK von der Microsoft Seite laden. Da ist die ganze Docu drin und viele viele Beispiele. 1) Für Dein Treiber (hier empfehle ich dringendst das KMDF Treiber Model (s. WDK), alles andere ist viel zu kompilziert) brauchst Du einen Registry Eintrag, damit Deine Applikations SW es überhaupt finden kann. Hierzu brauchst Du einen sog. GUID (globally unique Id). Die wird mit GENGUID.exe aus der SDK generiert. Den String hieraus kommt als '#DEFINE' in Deinen Treiber, Deine Applikation SW und Deine *.INF Datei Dein Treiber wird übrigens immer mit dem WDK C-Compiler in einem DOS Box übersetzt. VisualStudio usw. kann das nicht. 2) In der Applikations Software (Borland/VisualXxx) verwendest Du SetupDiGetClassDevs() SetupDiEnumDeviceInterfaces() SetupDiGetDeviceInterfaceDetail() um einen Handle zu Deinem Treiber aufzubauen. (s. Beispiel in der SDK) 3) Mit CreateFile() ReadFile(drvHandle, buf,....) kannst Du dann Daten von Deinem Treiber abholen. --------------- Nun zum Treiber: 1) genauso wie unter Linux musst Du letzendlich einige Callbacks vereinbaren. Vor allem, DriverEntry() EVT_WDF_DRIVER_DEVICE_ADD EVT_WDF_DEVICE_PREPARE_HARDWARE In Deiner EVT_WDF_DEVICE_PREPARE_HARDWARE erfährst Du, wie Deine PCI Base Address Register gemapped sind 2) Mindestens ein IO-Queue Anlegen. Das Betribssystem leitet Deine ReadFile() Aufrufe hierhin. Die KMDF bietet dann einige Aufrufe um Queue Einträge abzuholen. Oder genauer, KMDF ruft Deine Callbacks auf, wenn Queue Einträge vorhanden sind. 3) Aus Deinem Queue Eintrag (IRP, I/O Request Packet in Windows Jargon) musst Du nun Zugang zum 'buf' aus Deinem ReadFile bekommen (am besten den sog. DMA_DIRECT Methode verwenden. Auch hier s. KMDF Docu) Mit WdfDmaTransactionInitializeUsingRequest(..CallbackFuerDma()...) WdfRequestRetrieveOutputBuffer() wird im Wesentlichen Deine DMA Übertragung gestartet. Deine Routine CallbackFuerDma(), bekommt dann die Scatter/Gather Liste zu Deinem 'buf' im User Space vom System mitgeteilt und diese Adressen schreibst Du in Dein Hardware. 4) Mit WdfRequestComplete() wird das ganze abgeschlossen. Das hier sind eigentlich nur als Stichwörter/Orientierungspunkte gemeint für Dein Studium der WDK Beispielen. Es lässt sich wirklich nicht umfassend auf nur einer HTML Seite beschreiben. Ab besten, den PLX 9x5x bzw. pcidrv Beispiele aus der WDK anschauen. Rechne, wie gesagt, mit einigen hundert Code Zeilen, viele Blue Screens und natürlich vier Wochen. Grüße, Charles
cfgardiner schrieb: > Rechne, wie gesagt, mit > einigen hundert Code Zeilen, viele Blue Screens und natürlich vier > Wochen. Nicht zu vergessen das Serial oder FireWire Kabel sowie ein 2. Rechner für den Kernel-Debugger :)
Hi Christian, ach für einen Bonsai Treiber braucht man das alles eigentlich nicht, auch wenn es MS vorschreibt. Klar man kommt vielleicht damit etwas schneller ans Ziel. Sofern man sich z.B. mit dem ganzen PnP Zeug nicht auseinander setzen muss, kann man schon darauf verzichten. Wen ich z.B. für einen Demo oder auch kleineres Projekt o.ä einen Treiber schreibe, mache ich immer nur folgendes: - Compilere mit Debug - Verify aktivieren - Nach einem Reboot, Crash Mini-Dumps mit WinDbg analysieren. Die angemeckerte Zeilen sind meistens in der Nähe vom tatsächlichen Fehler, zumindest sofern man mit dem KMDF Model gearbeitet hat. Klar, alles Abwägung. Grüße, Charles
Ich seh schon, zumindest nen komplett eigener Treiber droht mir überden Kopf zu wachsen. Bei Linux bekomme ich nicht mal ein Modul compiliert/geladen und an Windows will ich lieber gar nicht denken ;-) Nunja, der Jungo Treiber hat eine funktion um Speicher für DMA zu reservieren, allerdings weiß ich nicht ob die für meine Zwecke funktioniert, das werde ich dann mal als nächstes testen. Dann habe ich gehört, dass es hier im Haus auch schon ne treiberentwicklung gab, für eben dieses Board aber eine anderen Anwendung. Da bin ich auch dran mit den Code mal zu besorgen. Ansonsten muss doch Linux herhalten. Ich schau mal was sich machen läßt.
So, ich wollte mich nochmal bei allen bedanken, die mir geholfen haben. Bin zwar was den DMA Teil angeht noch nicht fertig, aber das Prinzip funktioniert soweit super! Und um noch ein bisschen Wissen beizusteuern: mit __get_free_pages(GFP_KERNEL, 10) läßt sich unter Linux im Treiber ein zusammenhängender Speicher von 4 MB reservieren. Der aktuelle Kernel kann meines Wissens auch noch order (ist das zweite Argument, 2^n * 4kB) 11, also 8 MB. GFP_KERNEL geht in meinem Falle, da mein PCI (Express) Board 64 bit Adressen verwalten kann, falls das nicht geht muss man es um __GFP_DMA ergänzen, damit ist bei mir aber dann die zweite oder dritte Allozierung schief gegangen. So, wie gesagt, vielen Dank euch allen nochmal! KDC
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.