€•ÛIŒsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ(/translations/zh_CN/core-api/dma-isa-lpc”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ(/translations/zh_TW/core-api/dma-isa-lpc”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ(/translations/it_IT/core-api/dma-isa-lpc”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ(/translations/ja_JP/core-api/dma-isa-lpc”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ(/translations/ko_KR/core-api/dma-isa-lpc”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ(/translations/pt_BR/core-api/dma-isa-lpc”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ(/translations/sp_SP/core-api/dma-isa-lpc”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒDMA with ISA and LPC devices”h]”hŒDMA with ISA and LPC devices”…””}”(hh¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhh·h²hh³ŒB/var/lib/git/docbuild/linux/Documentation/core-api/dma-isa-lpc.rst”h´KubhŒ field_list”“”)”}”(hhh]”hŒfield”“”)”}”(hhh]”(hŒ field_name”“”)”}”(hŒAuthor”h]”hŒAuthor”…””}”(hh×h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhhÒh³hÊh´KubhŒ field_body”“”)”}”(hŒ!Pierre Ossman ”h]”hŒ paragraph”“”)”}”(hŒ Pierre Ossman ”h]”(hŒPierre Ossman <”…””}”(hhíh²hh³Nh´NubhŒ reference”“”)”}”(hŒdrzeus@drzeus.cx”h]”hŒdrzeus@drzeus.cx”…””}”(hh÷h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”Œmailto:drzeus@drzeus.cx”uh1hõhhíubhŒ>”…””}”(hhíh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Khhçubah}”(h]”h ]”h"]”h$]”h&]”uh1håhhÒubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÐh³hÊh´KhhÍh²hubah}”(h]”h ]”h"]”h$]”h&]”uh1hËhh·h²hh³hÊh´Kubhì)”}”(hŒËThis document describes how to do DMA transfers using the old ISA DMA controller. Even though ISA is more or less dead today the LPC bus uses the same DMA system so it will be around for quite some time.”h]”hŒËThis document describes how to do DMA transfers using the old ISA DMA controller. Even though ISA is more or less dead today the LPC bus uses the same DMA system so it will be around for quite some time.”…””}”(hj#h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Khh·h²hubh¶)”}”(hhh]”(h»)”}”(hŒHeaders and dependencies”h]”hŒHeaders and dependencies”…””}”(hj4h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj1h²hh³hÊh´K ubhì)”}”(hŒ5To do ISA style DMA you need to include two headers::”h]”hŒ4To do ISA style DMA you need to include two headers:”…””}”(hjBh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Khj1h²hubhŒ literal_block”“”)”}”(hŒ3#include #include ”h]”hŒ3#include #include ”…””}”hjRsbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1jPh³hÊh´Khj1h²hubhì)”}”(hŒ‰The first is the generic DMA API used to convert virtual addresses to bus addresses (see Documentation/core-api/dma-api.rst for details).”h]”hŒ‰The first is the generic DMA API used to convert virtual addresses to bus addresses (see Documentation/core-api/dma-api.rst for details).”…””}”(hjbh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Khj1h²hubhì)”}”(hŒüThe second contains the routines specific to ISA DMA transfers. Since this is not present on all platforms make sure you construct your Kconfig to be dependent on ISA_DMA_API (not ISA) so that nobody tries to build your driver on unsupported platforms.”h]”hŒüThe second contains the routines specific to ISA DMA transfers. Since this is not present on all platforms make sure you construct your Kconfig to be dependent on ISA_DMA_API (not ISA) so that nobody tries to build your driver on unsupported platforms.”…””}”(hjph²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Khj1h²hubeh}”(h]”Œheaders-and-dependencies”ah ]”h"]”Œheaders and dependencies”ah$]”h&]”uh1hµhh·h²hh³hÊh´K ubh¶)”}”(hhh]”(h»)”}”(hŒBuffer allocation”h]”hŒBuffer allocation”…””}”(hj‰h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj†h²hh³hÊh´Kubhì)”}”(hŒ‹The ISA DMA controller has some very strict requirements on which memory it can access so extra care must be taken when allocating buffers.”h]”hŒ‹The ISA DMA controller has some very strict requirements on which memory it can access so extra care must be taken when allocating buffers.”…””}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Khj†h²hubhì)”}”(hŒ(You usually need a special buffer for DMA transfers instead of transferring directly to and from your normal data structures.)”h]”hŒ(You usually need a special buffer for DMA transfers instead of transferring directly to and from your normal data structures.)”…””}”(hj¥h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K"hj†h²hubhì)”}”(hŒ¸The DMA-able address space is the lowest 16 MB of _physical_ memory. Also the transfer block may not cross page boundaries (which are 64 or 128 KiB depending on which channel you use).”h]”hŒ¸The DMA-able address space is the lowest 16 MB of _physical_ memory. Also the transfer block may not cross page boundaries (which are 64 or 128 KiB depending on which channel you use).”…””}”(hj³h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K%hj†h²hubhì)”}”(hŒrIn order to allocate a piece of memory that satisfies all these requirements you pass the flag GFP_DMA to kmalloc.”h]”hŒrIn order to allocate a piece of memory that satisfies all these requirements you pass the flag GFP_DMA to kmalloc.”…””}”(hjÁh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K)hj†h²hubhì)”}”(hŒÔUnfortunately the memory available for ISA DMA is scarce so unless you allocate the memory during boot-up it's a good idea to also pass __GFP_RETRY_MAYFAIL and __GFP_NOWARN to make the allocator try a bit harder.”h]”hŒÖUnfortunately the memory available for ISA DMA is scarce so unless you allocate the memory during boot-up it’s a good idea to also pass __GFP_RETRY_MAYFAIL and __GFP_NOWARN to make the allocator try a bit harder.”…””}”(hjÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K,hj†h²hubhì)”}”(hŒ„(This scarcity also means that you should allocate the buffer as early as possible and not release it until the driver is unloaded.)”h]”hŒ„(This scarcity also means that you should allocate the buffer as early as possible and not release it until the driver is unloaded.)”…””}”(hjÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K0hj†h²hubeh}”(h]”Œbuffer-allocation”ah ]”h"]”Œbuffer allocation”ah$]”h&]”uh1hµhh·h²hh³hÊh´Kubh¶)”}”(hhh]”(h»)”}”(hŒAddress translation”h]”hŒAddress translation”…””}”(hjöh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjóh²hh³hÊh´K4ubhì)”}”(hXTo translate the virtual address to a bus address, use the normal DMA API. Do _not_ use isa_virt_to_bus() even though it does the same thing. The reason for this is that the function isa_virt_to_bus() will require a Kconfig dependency to ISA, not just ISA_DMA_API which is really all you need. Remember that even though the DMA controller has its origins in ISA it is used elsewhere.”h]”hXTo translate the virtual address to a bus address, use the normal DMA API. Do _not_ use isa_virt_to_bus() even though it does the same thing. The reason for this is that the function isa_virt_to_bus() will require a Kconfig dependency to ISA, not just ISA_DMA_API which is really all you need. Remember that even though the DMA controller has its origins in ISA it is used elsewhere.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K6hjóh²hubhì)”}”(hŒ©Note: x86_64 had a broken DMA API when it came to ISA but has since been fixed. If your arch has problems then fix the DMA API instead of reverting to the ISA functions.”h]”hŒ©Note: x86_64 had a broken DMA API when it came to ISA but has since been fixed. If your arch has problems then fix the DMA API instead of reverting to the ISA functions.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K=hjóh²hubeh}”(h]”Œaddress-translation”ah ]”h"]”Œaddress translation”ah$]”h&]”uh1hµhh·h²hh³hÊh´K4ubh¶)”}”(hhh]”(h»)”}”(hŒChannels”h]”hŒChannels”…””}”(hj+h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj(h²hh³hÊh´KBubhì)”}”(hŒA normal ISA DMA controller has 8 channels. The lower four are for 8-bit transfers and the upper four are for 16-bit transfers.”h]”hŒA normal ISA DMA controller has 8 channels. The lower four are for 8-bit transfers and the upper four are for 16-bit transfers.”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´KDhj(h²hubhì)”}”(hŒÐ(Actually the DMA controller is really two separate controllers where channel 4 is used to give DMA access for the second controller (0-3). This means that of the four 16-bits channels only three are usable.)”h]”hŒÐ(Actually the DMA controller is really two separate controllers where channel 4 is used to give DMA access for the second controller (0-3). This means that of the four 16-bits channels only three are usable.)”…””}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´KGhj(h²hubhì)”}”(hŒ?You allocate these in a similar fashion as all basic resources:”h]”hŒ?You allocate these in a similar fashion as all basic resources:”…””}”(hjUh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´KKhj(h²hubhì)”}”(hŒmextern int request_dma(unsigned int dmanr, const char * device_id); extern void free_dma(unsigned int dmanr);”h]”hŒmextern int request_dma(unsigned int dmanr, const char * device_id); extern void free_dma(unsigned int dmanr);”…””}”(hjch²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´KMhj(h²hubhì)”}”(hŒªThe ability to use 16-bit or 8-bit transfers is _not_ up to you as a driver author but depends on what the hardware supports. Check your specs or test different channels.”h]”hŒªThe ability to use 16-bit or 8-bit transfers is _not_ up to you as a driver author but depends on what the hardware supports. Check your specs or test different channels.”…””}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´KPhj(h²hubeh}”(h]”Œchannels”ah ]”h"]”Œchannels”ah$]”h&]”uh1hµhh·h²hh³hÊh´KBubh¶)”}”(hhh]”(h»)”}”(hŒ Transfer data”h]”hŒ Transfer data”…””}”(hjŠh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj‡h²hh³hÊh´KUubhì)”}”(hŒ3Now for the good stuff, the actual DMA transfer. :)”h]”hŒ3Now for the good stuff, the actual DMA transfer. :)”…””}”(hj˜h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´KWhj‡h²hubhì)”}”(hŒÌBefore you use any ISA DMA routines you need to claim the DMA lock using claim_dma_lock(). The reason is that some DMA operations are not atomic so only one driver may fiddle with the registers at a time.”h]”hŒÌBefore you use any ISA DMA routines you need to claim the DMA lock using claim_dma_lock(). The reason is that some DMA operations are not atomic so only one driver may fiddle with the registers at a time.”…””}”(hj¦h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´KYhj‡h²hubhì)”}”(hXThe first time you use the DMA controller you should call clear_dma_ff(). This clears an internal register in the DMA controller that is used for the non-atomic operations. As long as you (and everyone else) uses the locking functions then you only need to reset this once.”h]”hXThe first time you use the DMA controller you should call clear_dma_ff(). This clears an internal register in the DMA controller that is used for the non-atomic operations. As long as you (and everyone else) uses the locking functions then you only need to reset this once.”…””}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K^hj‡h²hubhì)”}”(hŒ¥Next, you tell the controller in which direction you intend to do the transfer using set_dma_mode(). Currently you have the options DMA_MODE_READ and DMA_MODE_WRITE.”h]”hŒ¥Next, you tell the controller in which direction you intend to do the transfer using set_dma_mode(). Currently you have the options DMA_MODE_READ and DMA_MODE_WRITE.”…””}”(hjÂh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Kdhj‡h²hubhì)”}”(hXSet the address from where the transfer should start (this needs to be 16-bit aligned for 16-bit transfers) and how many bytes to transfer. Note that it's _bytes_. The DMA routines will do all the required translation to values that the DMA controller understands.”h]”hX Set the address from where the transfer should start (this needs to be 16-bit aligned for 16-bit transfers) and how many bytes to transfer. Note that it’s _bytes_. The DMA routines will do all the required translation to values that the DMA controller understands.”…””}”(hjÐh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Khhj‡h²hubhì)”}”(hŒFThe final step is enabling the DMA channel and releasing the DMA lock.”h]”hŒFThe final step is enabling the DMA channel and releasing the DMA lock.”…””}”(hjÞh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Kmhj‡h²hubhì)”}”(hŒ¯Once the DMA transfer is finished (or timed out) you should disable the channel again. You should also check get_dma_residue() to make sure that all data has been transferred.”h]”hŒ¯Once the DMA transfer is finished (or timed out) you should disable the channel again. You should also check get_dma_residue() to make sure that all data has been transferred.”…””}”(hjìh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Kphj‡h²hubhì)”}”(hŒ Example::”h]”hŒExample:”…””}”(hjúh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´Kthj‡h²hubjQ)”}”(hXâint flags, residue; flags = claim_dma_lock(); clear_dma_ff(); set_dma_mode(channel, DMA_MODE_WRITE); set_dma_addr(channel, phys_addr); set_dma_count(channel, num_bytes); dma_enable(channel); release_dma_lock(flags); while (!device_done()); flags = claim_dma_lock(); dma_disable(channel); residue = dma_get_residue(channel); if (residue != 0) printk(KERN_ERR "driver: Incomplete DMA transfer!" " %d bytes left!\n", residue); release_dma_lock(flags);”h]”hXâint flags, residue; flags = claim_dma_lock(); clear_dma_ff(); set_dma_mode(channel, DMA_MODE_WRITE); set_dma_addr(channel, phys_addr); set_dma_count(channel, num_bytes); dma_enable(channel); release_dma_lock(flags); while (!device_done()); flags = claim_dma_lock(); dma_disable(channel); residue = dma_get_residue(channel); if (residue != 0) printk(KERN_ERR "driver: Incomplete DMA transfer!" " %d bytes left!\n", residue); release_dma_lock(flags);”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”j`jauh1jPh³hÊh´Kvhj‡h²hubeh}”(h]”Œ transfer-data”ah ]”h"]”Œ transfer data”ah$]”h&]”uh1hµhh·h²hh³hÊh´KUubh¶)”}”(hhh]”(h»)”}”(hŒSuspend/resume”h]”hŒSuspend/resume”…””}”(hj!h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjh²hh³hÊh´K’ubhì)”}”(hX+It is the driver's responsibility to make sure that the machine isn't suspended while a DMA transfer is in progress. Also, all DMA settings are lost when the system suspends so if your driver relies on the DMA controller being in a certain state then you have to restore these registers upon resume.”h]”hX/It is the driver’s responsibility to make sure that the machine isn’t suspended while a DMA transfer is in progress. Also, all DMA settings are lost when the system suspends so if your driver relies on the DMA controller being in a certain state then you have to restore these registers upon resume.”…””}”(hj/h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÊh´K”hjh²hubeh}”(h]”Œsuspend-resume”ah ]”h"]”Œsuspend/resume”ah$]”h&]”uh1hµhh·h²hh³hÊh´K’ubeh}”(h]”Œdma-with-isa-and-lpc-devices”ah ]”h"]”Œdma with isa and lpc devices”ah$]”h&]”uh1hµhhh²hh³hÊh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÊuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(hºNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jpŒerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÊŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(jJjGjƒj€jðjíj%j"j„jjjjBj?uŒ nametypes”}”(jJ‰jƒ‰jð‰j%‰j„‰j‰jB‰uh}”(jGh·j€j1jíj†j"jójj(jj‡j?juŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.