€•BœŒ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/crypto/async-tx-api”Œ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/crypto/async-tx-api”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/it_IT/crypto/async-tx-api”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/ja_JP/crypto/async-tx-api”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/ko_KR/crypto/async-tx-api”Œ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/crypto/async-tx-api”Œ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/crypto/async-tx-api”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…””}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³ŒA/var/lib/git/docbuild/linux/Documentation/crypto/async-tx-api.rst”h´KubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒ%Asynchronous Transfers/Transforms API”h]”hŒ%Asynchronous Transfers/Transforms API”…””}”(hhÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhÊh²hh³hÇh´Kubh¶)”}”(hXnContents 1. INTRODUCTION 2 GENEALOGY 3 USAGE 3.1 General format of the API 3.2 Supported operations 3.3 Descriptor management 3.4 When does the operation execute? 3.5 When does the operation complete? 3.6 Constraints 3.7 Example 4 DMAENGINE DRIVER DEVELOPER NOTES 4.1 Conformance points 4.2 "My application needs exclusive control of hardware channels" 5 SOURCE”h]”hXnContents 1. INTRODUCTION 2 GENEALOGY 3 USAGE 3.1 General format of the API 3.2 Supported operations 3.3 Descriptor management 3.4 When does the operation execute? 3.5 When does the operation complete? 3.6 Constraints 3.7 Example 4 DMAENGINE DRIVER DEVELOPER NOTES 4.1 Conformance points 4.2 "My application needs exclusive control of hardware channels" 5 SOURCE”…””}”hhÝsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1hµhhÊh²hh³hÇh´KubhÉ)”}”(hhh]”(hÎ)”}”(hŒ1. Introduction”h]”hŒ1. Introduction”…””}”(hhîh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhëh²hh³hÇh´KubhŒ paragraph”“”)”}”(hX³The async_tx API provides methods for describing a chain of asynchronous bulk memory transfers/transforms with support for inter-transactional dependencies. It is implemented as a dmaengine client that smooths over the details of different hardware offload engine implementations. Code that is written to the API can optimize for asynchronous operation and the API will fit the chain of operations to the available offload resources.”h]”hX³The async_tx API provides methods for describing a chain of asynchronous bulk memory transfers/transforms with support for inter-transactional dependencies. It is implemented as a dmaengine client that smooths over the details of different hardware offload engine implementations. Code that is written to the API can optimize for asynchronous operation and the API will fit the chain of operations to the available offload resources.”…””}”(hhþh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khhëh²hubeh}”(h]”Œ introduction”ah ]”h"]”Œ1. introduction”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KubhÉ)”}”(hhh]”(hÎ)”}”(hŒ 2.Genealogy”h]”hŒ 2.Genealogy”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjh²hh³hÇh´K(ubhý)”}”(hXvThe API was initially designed to offload the memory copy and xor-parity-calculations of the md-raid5 driver using the offload engines present in the Intel(R) Xscale series of I/O processors. It also built on the 'dmaengine' layer developed for offloading memory copies in the network stack using Intel(R) I/OAT engines. The following design features surfaced as a result:”h]”hXzThe API was initially designed to offload the memory copy and xor-parity-calculations of the md-raid5 driver using the offload engines present in the Intel(R) Xscale series of I/O processors. It also built on the ‘dmaengine’ layer developed for offloading memory copies in the network stack using Intel(R) I/OAT engines. The following design features surfaced as a result:”…””}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K*hjh²hubhŒenumerated_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒáimplicit synchronous path: users of the API do not need to know if the platform they are running on has offload capabilities. The operation will be offloaded when an engine is available and carried out in software otherwise.”h]”hý)”}”(hŒáimplicit synchronous path: users of the API do not need to know if the platform they are running on has offload capabilities. The operation will be offloaded when an engine is available and carried out in software otherwise.”h]”hŒáimplicit synchronous path: users of the API do not need to know if the platform they are running on has offload capabilities. The operation will be offloaded when an engine is available and carried out in software otherwise.”…””}”(hj>h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K1hj:ubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj5h²hh³hÇh´Nubj9)”}”(hXcross channel dependency chains: the API allows a chain of dependent operations to be submitted, like xor->copy->xor in the raid5 case. The API automatically handles cases where the transition from one operation to another implies a hardware channel switch.”h]”hý)”}”(hXcross channel dependency chains: the API allows a chain of dependent operations to be submitted, like xor->copy->xor in the raid5 case. The API automatically handles cases where the transition from one operation to another implies a hardware channel switch.”h]”hXcross channel dependency chains: the API allows a chain of dependent operations to be submitted, like xor->copy->xor in the raid5 case. The API automatically handles cases where the transition from one operation to another implies a hardware channel switch.”…””}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K5hjRubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj5h²hh³hÇh´Nubj9)”}”(hŒUdmaengine extensions to support multiple clients and operation types beyond 'memcpy' ”h]”hý)”}”(hŒTdmaengine extensions to support multiple clients and operation types beyond 'memcpy'”h]”hŒXdmaengine extensions to support multiple clients and operation types beyond ‘memcpy’”…””}”(hjnh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K9hjjubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj5h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ.”uh1j3hjh²hh³hÇh´K1ubeh}”(h]”Œ genealogy”ah ]”h"]”Œ 2.genealogy”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K(ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ3. Usage”h]”hŒ3. Usage”…””}”(hj˜h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj•h²hh³hÇh´K=ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ3.1 General format of the API”h]”hŒ3.1 General format of the API”…””}”(hj©h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj¦h²hh³hÇh´K@ubhŒ literal_block”“”)”}”(hŒmstruct dma_async_tx_descriptor * async_(, struct async_submit_ctl *submit)”h]”hŒmstruct dma_async_tx_descriptor * async_(, struct async_submit_ctl *submit)”…””}”hj¹sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j·h³hÇh´KDhj¦h²hubeh}”(h]”Œgeneral-format-of-the-api”ah ]”h"]”Œ3.1 general format of the api”ah$]”h&]”uh1hÈhj•h²hh³hÇh´K@ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ3.2 Supported operations”h]”hŒ3.2 Supported operations”…””}”(hjÒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÏh²hh³hÇh´KHubhŒtable”“”)”}”(hhh]”hŒtgroup”“”)”}”(hhh]”(hŒcolspec”“”)”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jêhjçubjë)”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”KDuh1jêhjçubhŒtbody”“”)”}”(hhh]”(hŒrow”“”)”}”(hhh]”(hŒentry”“”)”}”(hhh]”hý)”}”(hŒmemcpy”h]”hŒmemcpy”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KKhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjubj )”}”(hhh]”hý)”}”(hŒ5memory copy between a source and a destination buffer”h]”hŒ5memory copy between a source and a destination buffer”…””}”(hj&h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KKhj#ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)”}”(hhh]”(j )”}”(hhh]”hý)”}”(hŒmemset”h]”hŒmemset”…””}”(hjFh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KLhjCubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj@ubj )”}”(hhh]”hý)”}”(hŒ+fill a destination buffer with a byte value”h]”hŒ+fill a destination buffer with a byte value”…””}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KLhjZubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj@ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)”}”(hhh]”(j )”}”(hhh]”hý)”}”(hŒxor”h]”hŒxor”…””}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KMhjzubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjwubj )”}”(hhh]”hý)”}”(hŒKxor a series of source buffers and write the result to a destination buffer”h]”hŒKxor a series of source buffers and write the result to a destination buffer”…””}”(hj”h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KMhj‘ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjwubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)”}”(hhh]”(j )”}”(hhh]”hý)”}”(hŒxor_val”h]”hŒxor_val”…””}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KOhj±ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj®ubj )”}”(hhh]”hý)”}”(hŒ}xor a series of source buffers and set a flag if the result is zero. The implementation attempts to prevent writes to memory”h]”hŒ}xor a series of source buffers and set a flag if the result is zero. The implementation attempts to prevent writes to memory”…””}”(hjËh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KOhjÈubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj®ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)”}”(hhh]”(j )”}”(hhh]”hý)”}”(hŒpq”h]”hŒpq”…””}”(hjëh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KRhjèubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjåubj )”}”(hhh]”hý)”}”(hŒAgenerate the p+q (raid6 syndrome) from a series of source buffers”h]”hŒAgenerate the p+q (raid6 syndrome) from a series of source buffers”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KRhjÿubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjåubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)”}”(hhh]”(j )”}”(hhh]”hý)”}”(hŒpq_val”h]”hŒpq_val”…””}”(hj"h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KShjubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjubj )”}”(hhh]”hý)”}”(hŒLvalidate that a p and or q buffer are in sync with a given series of sources”h]”hŒLvalidate that a p and or q buffer are in sync with a given series of sources”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KShj6ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)”}”(hhh]”(j )”}”(hhh]”hý)”}”(hŒdatap”h]”hŒdatap”…””}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KUhjVubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjSubj )”}”(hhh]”hý)”}”(hŒU(raid6_datap_recov) recover a raid6 data block and the p block from the given sources”h]”hŒU(raid6_datap_recov) recover a raid6 data block and the p block from the given sources”…””}”(hjph²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KUhjmubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjSubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)”}”(hhh]”(j )”}”(hhh]”hý)”}”(hŒ2data”h]”hŒ2data”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KWhjubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjŠubj )”}”(hhh]”hý)”}”(hŒF(raid6_2data_recov) recover 2 raid6 data blocks from the given sources”h]”hŒF(raid6_2data_recov) recover 2 raid6 data blocks from the given sources”…””}”(hj§h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KWhj¤ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjŠubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjçubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1jåhjâubah}”(h]”h ]”h"]”h$]”h&]”uh1jàhjÏh²hh³hÇh´Nubeh}”(h]”Œsupported-operations”ah ]”h"]”Œ3.2 supported operations”ah$]”h&]”uh1hÈhj•h²hh³hÇh´KHubhÉ)”}”(hhh]”(hÎ)”}”(hŒ3.3 Descriptor management”h]”hŒ3.3 Descriptor management”…””}”(hjßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÜh²hh³hÇh´K\ubhý)”}”(hXdThe return value is non-NULL and points to a 'descriptor' when the operation has been queued to execute asynchronously. Descriptors are recycled resources, under control of the offload engine driver, to be reused as operations complete. When an application needs to submit a chain of operations it must guarantee that the descriptor is not automatically recycled before the dependency is submitted. This requires that all descriptors be acknowledged by the application before the offload engine driver is allowed to recycle (or free) the descriptor. A descriptor can be acked by one of the following methods:”h]”hXhThe return value is non-NULL and points to a ‘descriptor’ when the operation has been queued to execute asynchronously. Descriptors are recycled resources, under control of the offload engine driver, to be reused as operations complete. When an application needs to submit a chain of operations it must guarantee that the descriptor is not automatically recycled before the dependency is submitted. This requires that all descriptors be acknowledged by the application before the offload engine driver is allowed to recycle (or free) the descriptor. A descriptor can be acked by one of the following methods:”…””}”(hjíh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K^hjÜh²hubj4)”}”(hhh]”(j9)”}”(hŒHsetting the ASYNC_TX_ACK flag if no child operations are to be submitted”h]”hý)”}”(hjh]”hŒHsetting the ASYNC_TX_ACK flag if no child operations are to be submitted”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khhjþubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hjûh²hh³hÇh´Nubj9)”}”(hŒ|submitting an unacknowledged descriptor as a dependency to another async_tx call will implicitly set the acknowledged state.”h]”hý)”}”(hŒ|submitting an unacknowledged descriptor as a dependency to another async_tx call will implicitly set the acknowledged state.”h]”hŒ|submitting an unacknowledged descriptor as a dependency to another async_tx call will implicitly set the acknowledged state.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kihjubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hjûh²hh³hÇh´Nubj9)”}”(hŒ*calling async_tx_ack() on the descriptor. ”h]”hý)”}”(hŒ)calling async_tx_ack() on the descriptor.”h]”hŒ)calling async_tx_ack() on the descriptor.”…””}”(hj1h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kkhj-ubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hjûh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jˆj‰jŠhj‹jŒuh1j3hjÜh²hh³hÇh´Khubeh}”(h]”Œdescriptor-management”ah ]”h"]”Œ3.3 descriptor management”ah$]”h&]”uh1hÈhj•h²hh³hÇh´K\ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ$3.4 When does the operation execute?”h]”hŒ$3.4 When does the operation execute?”…””}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjSh²hh³hÇh´Knubhý)”}”(hXçOperations do not immediately issue after return from the async_ call. Offload engine drivers batch operations to improve performance by reducing the number of mmio cycles needed to manage the channel. Once a driver-specific threshold is met the driver automatically issues pending operations. An application can force this event by calling async_tx_issue_pending_all(). This operates on all channels since the application has no knowledge of channel to operation mapping.”h]”hXçOperations do not immediately issue after return from the async_ call. Offload engine drivers batch operations to improve performance by reducing the number of mmio cycles needed to manage the channel. Once a driver-specific threshold is met the driver automatically issues pending operations. An application can force this event by calling async_tx_issue_pending_all(). This operates on all channels since the application has no knowledge of channel to operation mapping.”…””}”(hjdh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KphjSh²hubeh}”(h]”Œwhen-does-the-operation-execute”ah ]”h"]”Œ$3.4 when does the operation execute?”ah$]”h&]”uh1hÈhj•h²hh³hÇh´KnubhÉ)”}”(hhh]”(hÎ)”}”(hŒ%3.5 When does the operation complete?”h]”hŒ%3.5 When does the operation complete?”…””}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjzh²hh³hÇh´Kzubhý)”}”(hŒWThere are two methods for an application to learn about the completion of an operation.”h]”hŒWThere are two methods for an application to learn about the completion of an operation.”…””}”(hj‹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K|hjzh²hubj4)”}”(hhh]”(j9)”}”(hŒ±Call dma_wait_for_async_tx(). This call causes the CPU to spin while it polls for the completion of the operation. It handles dependency chains and issuing pending operations.”h]”hý)”}”(hŒ±Call dma_wait_for_async_tx(). This call causes the CPU to spin while it polls for the completion of the operation. It handles dependency chains and issuing pending operations.”h]”hŒ±Call dma_wait_for_async_tx(). This call causes the CPU to spin while it polls for the completion of the operation. It handles dependency chains and issuing pending operations.”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khjœubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj™h²hh³hÇh´Nubj9)”}”(hXÎSpecify a completion callback. The callback routine runs in tasklet context if the offload engine driver supports interrupts, or it is called in application context if the operation is carried out synchronously in software. The callback can be set in the call to async_, or when the application needs to submit a chain of unknown length it can use the async_trigger_callback() routine to set a completion interrupt/callback at the end of the chain. ”h]”hý)”}”(hXÍSpecify a completion callback. The callback routine runs in tasklet context if the offload engine driver supports interrupts, or it is called in application context if the operation is carried out synchronously in software. The callback can be set in the call to async_, or when the application needs to submit a chain of unknown length it can use the async_trigger_callback() routine to set a completion interrupt/callback at the end of the chain.”h]”hXÍSpecify a completion callback. The callback routine runs in tasklet context if the offload engine driver supports interrupts, or it is called in application context if the operation is carried out synchronously in software. The callback can be set in the call to async_, or when the application needs to submit a chain of unknown length it can use the async_trigger_callback() routine to set a completion interrupt/callback at the end of the chain.”…””}”(hj¸h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K‚hj´ubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj™h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jˆj‰jŠhj‹jŒuh1j3hjzh²hh³hÇh´Kubeh}”(h]”Œ when-does-the-operation-complete”ah ]”h"]”Œ%3.5 when does the operation complete?”ah$]”h&]”uh1hÈhj•h²hh³hÇh´KzubhÉ)”}”(hhh]”(hÎ)”}”(hŒ3.6 Constraints”h]”hŒ3.6 Constraints”…””}”(hjÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÚh²hh³hÇh´K‹ubj4)”}”(hhh]”(j9)”}”(hŒ‚Calls to async_ are not permitted in IRQ context. Other contexts are permitted provided constraint #2 is not violated.”h]”hý)”}”(hŒ‚Calls to async_ are not permitted in IRQ context. Other contexts are permitted provided constraint #2 is not violated.”h]”hŒ‚Calls to async_ are not permitted in IRQ context. Other contexts are permitted provided constraint #2 is not violated.”…””}”(hjòh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khjîubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hjëh²hh³hÇh´Nubj9)”}”(hŒ¬Completion callback routines cannot submit new operations. This results in recursion in the synchronous case and spin_locks being acquired twice in the asynchronous case. ”h]”hý)”}”(hŒ«Completion callback routines cannot submit new operations. This results in recursion in the synchronous case and spin_locks being acquired twice in the asynchronous case.”h]”hŒ«Completion callback routines cannot submit new operations. This results in recursion in the synchronous case and spin_locks being acquired twice in the asynchronous case.”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hjëh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jˆj‰jŠhj‹jŒuh1j3hjÚh²hh³hÇh´Kubeh}”(h]”Œ constraints”ah ]”h"]”Œ3.6 constraints”ah$]”h&]”uh1hÈhj•h²hh³hÇh´K‹ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ 3.7 Example”h]”hŒ 3.7 Example”…””}”(hj/h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj,h²hh³hÇh´K”ubhý)”}”(hŒkPerform a xor->copy->xor operation where each operation depends on the result from the previous operation::”h]”hŒjPerform a xor->copy->xor operation where each operation depends on the result from the previous operation:”…””}”(hj=h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K–hj,h²hubj¸)”}”(hX’#include static void callback(void *param) { complete(param); } #define NDISKS 2 static void run_xor_copy_xor(struct page **xor_srcs, struct page *xor_dest, size_t xor_len, struct page *copy_src, struct page *copy_dest, size_t copy_len) { struct dma_async_tx_descriptor *tx; struct async_submit_ctl submit; addr_conv_t addr_conv[NDISKS]; struct completion cmp; init_async_submit(&submit, ASYNC_TX_XOR_DROP_DST, NULL, NULL, NULL, addr_conv); tx = async_xor(xor_dest, xor_srcs, 0, NDISKS, xor_len, &submit); submit.depend_tx = tx; tx = async_memcpy(copy_dest, copy_src, 0, 0, copy_len, &submit); init_completion(&cmp); init_async_submit(&submit, ASYNC_TX_XOR_DROP_DST | ASYNC_TX_ACK, tx, callback, &cmp, addr_conv); tx = async_xor(xor_dest, xor_srcs, 0, NDISKS, xor_len, &submit); async_tx_issue_pending_all(); wait_for_completion(&cmp); }”h]”hX’#include static void callback(void *param) { complete(param); } #define NDISKS 2 static void run_xor_copy_xor(struct page **xor_srcs, struct page *xor_dest, size_t xor_len, struct page *copy_src, struct page *copy_dest, size_t copy_len) { struct dma_async_tx_descriptor *tx; struct async_submit_ctl submit; addr_conv_t addr_conv[NDISKS]; struct completion cmp; init_async_submit(&submit, ASYNC_TX_XOR_DROP_DST, NULL, NULL, NULL, addr_conv); tx = async_xor(xor_dest, xor_srcs, 0, NDISKS, xor_len, &submit); submit.depend_tx = tx; tx = async_memcpy(copy_dest, copy_src, 0, 0, copy_len, &submit); init_completion(&cmp); init_async_submit(&submit, ASYNC_TX_XOR_DROP_DST | ASYNC_TX_ACK, tx, callback, &cmp, addr_conv); tx = async_xor(xor_dest, xor_srcs, 0, NDISKS, xor_len, &submit); async_tx_issue_pending_all(); wait_for_completion(&cmp); }”…””}”hjKsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j·h³hÇh´K™hj,h²hubhý)”}”(hŒ¦See include/linux/async_tx.h for more information on the flags. See the ops_run_* and ops_complete_* routines in drivers/md/raid5.c for more implementation examples.”h]”hŒ¦See include/linux/async_tx.h for more information on the flags. See the ops_run_* and ops_complete_* routines in drivers/md/raid5.c for more implementation examples.”…””}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K¿hj,h²hubeh}”(h]”Œexample”ah ]”h"]”Œ 3.7 example”ah$]”h&]”uh1hÈhj•h²hh³hÇh´K”ubeh}”(h]”Œusage”ah ]”h"]”Œ3. usage”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K=ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ4. Driver Development Notes”h]”hŒ4. Driver Development Notes”…””}”(hjzh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjwh²hh³hÇh´KÄubhÉ)”}”(hhh]”(hÎ)”}”(hŒ4.1 Conformance points”h]”hŒ4.1 Conformance points”…””}”(hj‹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjˆh²hh³hÇh´KÇubhý)”}”(hŒˆThere are a few conformance points required in dmaengine drivers to accommodate assumptions made by applications using the async_tx API:”h]”hŒˆThere are a few conformance points required in dmaengine drivers to accommodate assumptions made by applications using the async_tx API:”…””}”(hj™h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÉhjˆh²hubj4)”}”(hhh]”(j9)”}”(hŒ>Completion callbacks are expected to happen in tasklet context”h]”hý)”}”(hj¬h]”hŒ>Completion callbacks are expected to happen in tasklet context”…””}”(hj®h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÌhjªubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj§h²hh³hÇh´Nubj9)”}”(hŒCdma_async_tx_descriptor fields are never manipulated in IRQ context”h]”hý)”}”(hjÃh]”hŒCdma_async_tx_descriptor fields are never manipulated in IRQ context”…””}”(hjÅh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÍhjÁubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj§h²hh³hÇh´Nubj9)”}”(hŒmUse async_tx_run_dependencies() in the descriptor clean up path to handle submission of dependent operations ”h]”hý)”}”(hŒlUse async_tx_run_dependencies() in the descriptor clean up path to handle submission of dependent operations”h]”hŒlUse async_tx_run_dependencies() in the descriptor clean up path to handle submission of dependent operations”…””}”(hjÜh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÎhjØubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hj§h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jˆj‰jŠhj‹jŒuh1j3hjˆh²hh³hÇh´KÌubeh}”(h]”Œconformance-points”ah ]”h"]”Œ4.1 conformance points”ah$]”h&]”uh1hÈhjwh²hh³hÇh´KÇubhÉ)”}”(hhh]”(hÎ)”}”(hŒA4.2 "My application needs exclusive control of hardware channels"”h]”hŒE4.2 “My application needs exclusive control of hardware channels—…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjþh²hh³hÇh´KÒubhý)”}”(hX$Primarily this requirement arises from cases where a DMA engine driver is being used to support device-to-memory operations. A channel that is performing these operations cannot, for many platform specific reasons, be shared. For these cases the dma_request_channel() interface is provided.”h]”hX$Primarily this requirement arises from cases where a DMA engine driver is being used to support device-to-memory operations. A channel that is performing these operations cannot, for many platform specific reasons, be shared. For these cases the dma_request_channel() interface is provided.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÔhjþh²hubhý)”}”(hŒThe interface is::”h]”hŒThe interface is:”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÚhjþh²hubj¸)”}”(hŒ±struct dma_chan *dma_request_channel(dma_cap_mask_t mask, dma_filter_fn filter_fn, void *filter_param);”h]”hŒ±struct dma_chan *dma_request_channel(dma_cap_mask_t mask, dma_filter_fn filter_fn, void *filter_param);”…””}”hj+sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j·h³hÇh´KÜhjþh²hubhý)”}”(hŒ#Where dma_filter_fn is defined as::”h]”hŒ"Where dma_filter_fn is defined as:”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kàhjþh²hubj¸)”}”(hŒItypedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);”h]”hŒItypedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);”…””}”hjGsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j·h³hÇh´Kâhjþh²hubhý)”}”(hXyWhen the optional 'filter_fn' parameter is set to NULL dma_request_channel simply returns the first channel that satisfies the capability mask. Otherwise, when the mask parameter is insufficient for specifying the necessary channel, the filter_fn routine can be used to disposition the available channels in the system. The filter_fn routine is called once for each free channel in the system. Upon seeing a suitable channel filter_fn returns DMA_ACK which flags that channel to be the return value from dma_request_channel. A channel allocated via this interface is exclusive to the caller, until dma_release_channel() is called.”h]”hX}When the optional ‘filter_fn’ parameter is set to NULL dma_request_channel simply returns the first channel that satisfies the capability mask. Otherwise, when the mask parameter is insufficient for specifying the necessary channel, the filter_fn routine can be used to disposition the available channels in the system. The filter_fn routine is called once for each free channel in the system. Upon seeing a suitable channel filter_fn returns DMA_ACK which flags that channel to be the return value from dma_request_channel. A channel allocated via this interface is exclusive to the caller, until dma_release_channel() is called.”…””}”(hjUh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kähjþh²hubhý)”}”(hX'The DMA_PRIVATE capability flag is used to tag dma devices that should not be used by the general-purpose allocator. It can be set at initialization time if it is known that a channel will always be private. Alternatively, it is set when dma_request_channel() finds an unused "public" channel.”h]”hX+The DMA_PRIVATE capability flag is used to tag dma devices that should not be used by the general-purpose allocator. It can be set at initialization time if it is known that a channel will always be private. Alternatively, it is set when dma_request_channel() finds an unused “public†channel.”…””}”(hjch²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kïhjþh²hubhý)”}”(hŒAA couple caveats to note when implementing a driver and consumer:”h]”hŒAA couple caveats to note when implementing a driver and consumer:”…””}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kõhjþh²hubj4)”}”(hhh]”(j9)”}”(hŒ˜Once a channel has been privately allocated it will no longer be considered by the general-purpose allocator even after a call to dma_release_channel().”h]”hý)”}”(hŒ˜Once a channel has been privately allocated it will no longer be considered by the general-purpose allocator even after a call to dma_release_channel().”h]”hŒ˜Once a channel has been privately allocated it will no longer be considered by the general-purpose allocator even after a call to dma_release_channel().”…””}”(hj†h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K÷hj‚ubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hjh²hh³hÇh´Nubj9)”}”(hŒ˜Since capabilities are specified at the device level a dma_device with multiple channels will either have all channels public, or all channels private. ”h]”hý)”}”(hŒ—Since capabilities are specified at the device level a dma_device with multiple channels will either have all channels public, or all channels private.”h]”hŒ—Since capabilities are specified at the device level a dma_device with multiple channels will either have all channels public, or all channels private.”…””}”(hjžh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kúhjšubah}”(h]”h ]”h"]”h$]”h&]”uh1j8hjh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jˆj‰jŠhj‹jŒuh1j3hjþh²hh³hÇh´K÷ubeh}”(h]”Œ;my-application-needs-exclusive-control-of-hardware-channels”ah ]”h"]”ŒA4.2 "my application needs exclusive control of hardware channels"”ah$]”h&]”uh1hÈhjwh²hh³hÇh´KÒubhÉ)”}”(hhh]”(hÎ)”}”(hŒ 5. Source”h]”hŒ 5. Source”…””}”(hjÃh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjÀh²hh³hÇh´KÿubhŒdefinition_list”“”)”}”(hhh]”(hŒdefinition_list_item”“”)”}”(hŒIinclude/linux/dmaengine.h: core header file for DMA drivers and api users”h]”(hŒterm”“”)”}”(hŒinclude/linux/dmaengine.h:”h]”hŒinclude/linux/dmaengine.h:”…””}”(hjÞh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jÜh³hÇh´MhjØubhŒ definition”“”)”}”(hhh]”hý)”}”(hŒ.core header file for DMA drivers and api users”h]”hŒ.core header file for DMA drivers and api users”…””}”(hjñh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjîubah}”(h]”h ]”h"]”h$]”h&]”uh1jìhjØubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÖh³hÇh´MhjÓubj×)”}”(hŒCdrivers/dma/dmaengine.c: offload engine channel management routines”h]”(jÝ)”}”(hŒdrivers/dma/dmaengine.c:”h]”hŒdrivers/dma/dmaengine.c:”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jÜh³hÇh´Mhj ubjí)”}”(hhh]”hý)”}”(hŒ*offload engine channel management routines”h]”hŒ*offload engine channel management routines”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jìhj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÖh³hÇh´MhjÓh²hubj×)”}”(hŒ1drivers/dma/: location for offload engine drivers”h]”(jÝ)”}”(hŒ drivers/dma/:”h]”hŒ drivers/dma/:”…””}”(hj>h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jÜh³hÇh´Mhj:ubjí)”}”(hhh]”hý)”}”(hŒ#location for offload engine drivers”h]”hŒ#location for offload engine drivers”…””}”(hjOh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MhjLubah}”(h]”h ]”h"]”h$]”h&]”uh1jìhj:ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÖh³hÇh´MhjÓh²hubj×)”}”(hŒ?include/linux/async_tx.h: core header file for the async_tx api”h]”(jÝ)”}”(hŒinclude/linux/async_tx.h:”h]”hŒinclude/linux/async_tx.h:”…””}”(hjmh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jÜh³hÇh´Mhjiubjí)”}”(hhh]”hý)”}”(hŒ%core header file for the async_tx api”h]”hŒ%core header file for the async_tx api”…””}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhj{ubah}”(h]”h ]”h"]”h$]”h&]”uh1jìhjiubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÖh³hÇh´MhjÓh²hubj×)”}”(hŒKcrypto/async_tx/async_tx.c: async_tx interface to dmaengine and common code”h]”(jÝ)”}”(hŒcrypto/async_tx/async_tx.c:”h]”hŒcrypto/async_tx/async_tx.c:”…””}”(hjœh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jÜh³hÇh´M hj˜ubjí)”}”(hhh]”hý)”}”(hŒ/async_tx interface to dmaengine and common code”h]”hŒ/async_tx interface to dmaengine and common code”…””}”(hj­h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M hjªubah}”(h]”h ]”h"]”h$]”h&]”uh1jìhj˜ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÖh³hÇh´M hjÓh²hubj×)”}”(hŒ,crypto/async_tx/async_memcpy.c: copy offload”h]”(jÝ)”}”(hŒcrypto/async_tx/async_memcpy.c:”h]”hŒcrypto/async_tx/async_memcpy.c:”…””}”(hjËh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jÜh³hÇh´M hjÇubjí)”}”(hhh]”hý)”}”(hŒ copy offload”h]”hŒ copy offload”…””}”(hjÜh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M hjÙubah}”(h]”h ]”h"]”h$]”h&]”uh1jìhjÇubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÖh³hÇh´M hjÓh²hubj×)”}”(hŒ9crypto/async_tx/async_xor.c: xor and xor zero sum offload”h]”(jÝ)”}”(hŒcrypto/async_tx/async_xor.c:”h]”hŒcrypto/async_tx/async_xor.c:”…””}”(hjúh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jÜh³hÇh´M hjöubjí)”}”(hhh]”hý)”}”(hŒxor and xor zero sum offload”h]”hŒxor and xor zero sum offload”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jìhjöubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÖh³hÇh´M hjÓh²hubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÑhjÀh²hh³hÇh´Nubeh}”(h]”Œsource”ah ]”h"]”Œ 5. source”ah$]”h&]”uh1hÈhjwh²hh³hÇh´Kÿubeh}”(h]”Œdriver-development-notes”ah ]”h"]”Œ4. driver development notes”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KÄubeh}”(h]”Œ%asynchronous-transfers-transforms-api”ah ]”h"]”Œ%asynchronous transfers/transforms api”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”j Œ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”jeŒ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”}”(j@j=jjj’jjtjqjÌjÉjÙjÖjPjMjwjtj×jÔj)j&jljij8j5jûjøj½jºj0j-uŒ nametypes”}”(j@‰j‰j’‰jt‰j̉jÙ‰jP‰jw‰j׉j)‰jl‰j8‰jû‰j½‰j0‰uh}”(j=hÊjhëjjjqj•jÉj¦jÖjÏjMjÜjtjSjÔjzj&jÚjij,j5jwjøjˆjºjþj-jÀuŒ 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.