Documentation DMA-API-HOWTO.txt Add dma mapping error check usage examples
PATCH 1/1 Documentation DMA-API-HOWTO.txt Add dma mapping error check usage examples
Enhance the document to discuss the importance of dma mapping error checks after dma_map_single() and dma_map_page() calls. Also added usage examples that include unmap examples in error paths when dma mapping error is returned. Includes correct and incorrect usages to high light some common mistakes in error paths especially when dma mapping fails when more than one dma mapping call is made.
--- Documentation/DMA-API-HOWTO.txt | 128 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-)
Documentation/DMA-API-HOWTO.txt +127 -1
@@ -468,11 +468,46 @@ To map a single region, you do: size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); + if (unlikely(dma_mapping_error(dma_handle))) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } and to unmap it: dma_unmap_single(dev, dma_handle, size, direction); +You should call dma_mapping_error() as dma_map_single() could fail and return +error. Not all dma implementations support dma_mapping_error() interface. +However, it is a good practice to call dma_mapping_error() interface, which +will invoke the generic mapping error check interface. Doing so will ensure +that the mapping code will work correctly on all dma implementations without +any dependency on the specifics of the underlying implementation. Using the +returned address without checking for errors could result in failures ranging +from panics to silent data corruption. Couple of example of incorrect ways to +check for errors that make assumptions about the underlying dma implementation +are as follows and these are applicable to dma_map_page() as well. + +Incorrect example 1: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if ((dma_handle & 0xffff != 0) || (dma_handle >= 0x1000000)) { + goto map_error; + } + +Incorrect example 2: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if (dma_handle == DMA_ERROR_CODE) { + goto map_error; + } + You should call dma_unmap_single when the DMA activity is finished, e.g. from the interrupt which told you that the DMA transfer is done.
@@ -489,6 +524,14 @@ Specifically: size_t size = buffer->len; dma_handle = dma_map_page(dev, page, offset, size, direction); + if (unlikely(dma_mapping_error(dma_handle))) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } ...
@@ -496,6 +539,12 @@ Specifically: Here, "offset" means byte offset within the given page. +You should call dma_mapping_error() as dma_map_page() could fail and return +error as outlined under the dma_map_single() discussion. + +You should call dma_unmap_page when the DMA activity is finished, e.g. +from the interrupt which told you that the DMA transfer is done. + With scatterlists, you map a region gathered from several regions by: int i, count = dma_map_sg(dev, sglist, nents, direction);
@@ -578,6 +627,14 @@ to use the dma_sync_*() interfaces. dma_addr_t mapping; mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dma_handle))) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } cp->rx_buf = buffer; cp->rx_len = len;
@@ -652,12 +709,81 @@ failure can be determined by: dma_addr_t dma_handle; dma_handle = dma_map_single(dev, addr, size, direction); - if (dma_mapping_error(dev, dma_handle)) { + if (unlikely(dma_mapping_error(dev, dma_handle))) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } + +- unmap pages that are already mapped, when mapping error occurs in the middle + of a multiple page mapping attempt. These example are applicable to + dma_map_page() as well. + +Example 1: + dma_addr_t dma_handle1; + dma_addr_t dma_handle2; + + dma_handle1 = dma_map_single(dev, addr, size, direction); + if (unlikely(dma_mapping_error(dev, dma_handle1))) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling1; + } + dma_handle2 = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_handle2)) { /* * reduce current DMA mapping usage, * delay and try again later or * reset driver. */ + goto map_error_handling2; + } + + ... + + map_error_handling2: + dma_unmap_single(dma_handle1); + map_error_handling1: + +Example 2: (if buffers are allocated a loop, unmap all mapped buffers when + mapping error is detected in the middle) + + dma_addr_t dma_addr; + dma_addr_t array[DMA_BUFFERS]; + int save_index = 0; + + for (i = 0; i < DMA_BUFFERS; i++) { + + ... + + dma_addr = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_addr)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } + array[i].dma_addr = dma_addr; + save_index++; + } + + ... + + map_error_handling: + + for (i = 0; i < save_index; i++) { + + ... + + dma_unmap_single(array[i].dma_addr); } Networking drivers must call dev_kfree_skb to free the socket buffer
Signature · 1 line
1.7.9.5
Documentation/DMA-API-HOWTO.txt To map a single region, you do: · line 471
Quoted 9 lines · Shuah Khan
Documentation/DMA-API-HOWTO.txt +1
-0@@ -468,11 +468,46 @@ To map a single region, you do: size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); + if (unlikely(dma_mapping_error(dma_handle))) {
Don't encourage people to put unlikely() and likely() into their driver code. It should only be used after benchmarking both with and without. I can't imagine how it would make a measurable difference here.
regards,
dan carpenter
Quoted 8 lines · Dan Carpenter
Quoted 7 lines · Shuah Khan
Documentation/DMA-API-HOWTO.txt +0
-0@@ -468,11 +468,46 @@ To map a single region, you do: size_t size = buffer->len;
Quoted 7 lines
Documentation/DMA-API-HOWTO.txt To map a single region, you do: · line 471
Quoted 2 lines
Documentation/DMA-API-HOWTO.txt +1
-0dma_handle = dma_map_single(dev, addr, size, direction); + if (unlikely(dma_mapping_error(dma_handle))) {Don't encourage people to put
unlikely()andlikely()into their driver code. It should only be used after benchmarking both with and without. I can't imagine how it would make a measurable difference here.
(Hi Dan)
Quite. See http://blog.man7.org/2012/10/how-much-do-builtinexpect-likely-and.html
I wonder how many blind uses of likely() and unlikely() in the kernel are actually degrading performance.
Cheers,
Michael
Signature · 3 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Author of "The Linux Programming Interface"; http://man7.org/tlpi/
Quoted 20 lines · Michael Kerrisk (man-pages)
Quoted 8 lines · Dan Carpenter
Quoted 7 lines · Shuah Khan
Documentation/DMA-API-HOWTO.txt +0
-0@@ -468,11 +468,46 @@ To map a single region, you do: size_t size = buffer->len;Quoted 7 lines
Documentation/DMA-API-HOWTO.txt To map a single region, you do: · line 471
Quoted 2 lines
Documentation/DMA-API-HOWTO.txt +1
-0dma_handle = dma_map_single(dev, addr, size, direction); + if (unlikely(dma_mapping_error(dma_handle))) {Don't encourage people to put
unlikely()andlikely()into their driver code. It should only be used after benchmarking both with and without. I can't imagine how it would make a measurable difference here.(Hi Dan)
Quoted 8 lines
Quite. See http://blog.man7.org/2012/10/how-much-do-builtinexpect-likely-and.html
I wonder how many blind uses of
likely()andunlikely()in the kernel are actually degrading performance.Cheers,
Michael
Dan, Michael,
Thanks. I see unlikely() and likely() used widely and didn't realize the negatives of it. Will fix the examples without the use of unlikely() and send v2 patch.
Thanks,
-- Shuah
PATCH v2 1/1 Documentation DMA-API-HOWTO.txt Add dma mapping error check usage examples
In reply to Michael Kerrisk (man-pages)Enhance the document to discuss the importance of dma mapping error checks after dma_map_single() and dma_map_page() calls. Also added usage examples that include unmap examples in error paths when dma mapping error is returned. Includes correct and incorrect usages to high light some common mistakes in error paths especially when dma mapping fails when more than one dma mapping call is made.
--- Documentation/DMA-API-HOWTO.txt | 126 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+)
Documentation/DMA-API-HOWTO.txt +126 -0
@@ -468,11 +468,46 @@ To map a single region, you do: size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } and to unmap it: dma_unmap_single(dev, dma_handle, size, direction); +You should call dma_mapping_error() as dma_map_single() could fail and return +error. Not all dma implementations support dma_mapping_error() interface. +However, it is a good practice to call dma_mapping_error() interface, which +will invoke the generic mapping error check interface. Doing so will ensure +that the mapping code will work correctly on all dma implementations without +any dependency on the specifics of the underlying implementation. Using the +returned address without checking for errors could result in failures ranging +from panics to silent data corruption. Couple of example of incorrect ways to +check for errors that make assumptions about the underlying dma implementation +are as follows and these are applicable to dma_map_page() as well. + +Incorrect example 1: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if ((dma_handle & 0xffff != 0) || (dma_handle >= 0x1000000)) { + goto map_error; + } + +Incorrect example 2: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if (dma_handle == DMA_ERROR_CODE) { + goto map_error; + } + You should call dma_unmap_single when the DMA activity is finished, e.g. from the interrupt which told you that the DMA transfer is done.
@@ -489,6 +524,14 @@ Specifically: size_t size = buffer->len; dma_handle = dma_map_page(dev, page, offset, size, direction); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } ...
@@ -496,6 +539,12 @@ Specifically: Here, "offset" means byte offset within the given page. +You should call dma_mapping_error() as dma_map_page() could fail and return +error as outlined under the dma_map_single() discussion. + +You should call dma_unmap_page when the DMA activity is finished, e.g. +from the interrupt which told you that the DMA transfer is done. + With scatterlists, you map a region gathered from several regions by: int i, count = dma_map_sg(dev, sglist, nents, direction);
@@ -578,6 +627,14 @@ to use the dma_sync_*() interfaces. dma_addr_t mapping; mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } cp->rx_buf = buffer; cp->rx_len = len;
@@ -658,6 +715,75 @@ failure can be determined by: * delay and try again later or * reset driver. */ + goto map_error_handling; + } + +- unmap pages that are already mapped, when mapping error occurs in the middle + of a multiple page mapping attempt. These example are applicable to + dma_map_page() as well. + +Example 1: + dma_addr_t dma_handle1; + dma_addr_t dma_handle2; + + dma_handle1 = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_handle1)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling1; + } + dma_handle2 = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_handle2)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling2; + } + + ... + + map_error_handling2: + dma_unmap_single(dma_handle1); + map_error_handling1: + +Example 2: (if buffers are allocated a loop, unmap all mapped buffers when + mapping error is detected in the middle) + + dma_addr_t dma_addr; + dma_addr_t array[DMA_BUFFERS]; + int save_index = 0; + + for (i = 0; i < DMA_BUFFERS; i++) { + + ... + + dma_addr = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_addr)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } + array[i].dma_addr = dma_addr; + save_index++; + } + + ... + + map_error_handling: + + for (i = 0; i < save_index; i++) { + + ... + + dma_unmap_single(array[i].dma_addr); } Networking drivers must call dev_kfree_skb to free the socket buffer
Signature · 1 line
1.7.9.5
Quoted 8 lines · Shuah Khan
Enhance the document to discuss the importance of dma mapping error checks after
dma_map_single()anddma_map_page()calls. Also added usage examples that include unmap examples in error paths when dma mapping error is returned. Includes correct and incorrect usages to high light some common mistakes in error paths especially when dma mapping fails when more than one dma mapping call is made.Signed-off-by Shuah Khan <[email protected]>
[...]
Nit picking :
Documentation/DMA-API-HOWTO.txt failure can be determined by: · line 756
Quoted 3 lines
Documentation/DMA-API-HOWTO.txt +3
-0+Example 2: (if buffers are allocated a loop, unmap all mapped buffers when + mapping error is detected in the middle) +
"... if buffers are allocated in a loop..."
Signature · 3 lines
Jesper Juhl <[email protected]> http://www.chaosbits.net/ Don't top-post http://www.catb.org/jargon/html/T/top-post.html Plain text mails only, please.
Quoted 8 lines · Shuah Khan
Enhance the document to discuss the importance of dma mapping error checks after
dma_map_single()anddma_map_page()calls. Also added usage examples that include unmap examples in error paths when dma mapping error is returned. Includes correct and incorrect usages to high light some common mistakes in error paths especially when dma mapping fails when more than one dma mapping call is made.Signed-off-by Shuah Khan <[email protected]>
Quoted 178 lines
--- Documentation/DMA-API-HOWTO.txt | 126 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+)Documentation/DMA-API-HOWTO.txt +126
-0@@ -468,11 +468,46 @@ To map a single region, you do: size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } and to unmap it: dma_unmap_single(dev, dma_handle, size, direction); +You should call dma_mapping_error() as dma_map_single() could fail and return +error. Not all dma implementations support dma_mapping_error() interface. +However, it is a good practice to call dma_mapping_error() interface, which +will invoke the generic mapping error check interface. Doing so will ensure +that the mapping code will work correctly on all dma implementations without +any dependency on the specifics of the underlying implementation. Using the +returned address without checking for errors could result in failures ranging +from panics to silent data corruption. Couple of example of incorrect ways to +check for errors that make assumptions about the underlying dma implementation +are as follows and these are applicable to dma_map_page() as well. + +Incorrect example 1: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if ((dma_handle & 0xffff != 0) || (dma_handle >= 0x1000000)) { + goto map_error; + } + +Incorrect example 2: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if (dma_handle == DMA_ERROR_CODE) { + goto map_error; + } + You should call dma_unmap_single when the DMA activity is finished, e.g. from the interrupt which told you that the DMA transfer is done.@@ -489,6 +524,14 @@ Specifically: size_t size = buffer->len; dma_handle = dma_map_page(dev, page, offset, size, direction); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + }@@ -496,6 +539,12 @@ Specifically: Here, "offset" means byte offset within the given page. +You should call dma_mapping_error() as dma_map_page() could fail and return +error as outlined under the dma_map_single() discussion. + +You should call dma_unmap_page when the DMA activity is finished, e.g. +from the interrupt which told you that the DMA transfer is done. + With scatterlists, you map a region gathered from several regions by: int i, count = dma_map_sg(dev, sglist, nents, direction);@@ -578,6 +627,14 @@ to use the dma_sync_*() interfaces. dma_addr_t mapping; mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } cp->rx_buf = buffer; cp->rx_len = len;@@ -658,6 +715,75 @@ failure can be determined by: * delay and try again later or * reset driver. */ + goto map_error_handling; + } + +- unmap pages that are already mapped, when mapping error occurs in the middle + of a multiple page mapping attempt. These example are applicable to + dma_map_page() as well. + +Example 1: + dma_addr_t dma_handle1; + dma_addr_t dma_handle2; + + dma_handle1 = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_handle1)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling1; + } + dma_handle2 = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_handle2)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling2; + } + + ... + + map_error_handling2: + dma_unmap_single(dma_handle1); + map_error_handling1: + +Example 2: (if buffers are allocated a loop, unmap all mapped buffers when + mapping error is detected in the middle) + + dma_addr_t dma_addr; + dma_addr_t array[DMA_BUFFERS]; + int save_index = 0; + + for (i = 0; i < DMA_BUFFERS; i++) { + + ... + + dma_addr = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_addr)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } + array[i].dma_addr = dma_addr; + save_index++; + } + + ... + + map_error_handling: + + for (i = 0; i < save_index; i++) { + + ... + + dma_unmap_single(array[i].dma_addr); } Networking drivers must call dev_kfree_skb to free the socket bufferSignature · 1 line
1.7.9.5
Joerg Roedel
AppliedQuoted 8 lines · Shuah Khan
Enhance the document to discuss the importance of dma mapping error checks after
dma_map_single()anddma_map_page()calls. Also added usage examples that include unmap examples in error paths when dma mapping error is returned. Includes correct and incorrect usages to high light some common mistakes in error paths especially when dma mapping fails when more than one dma mapping call is made.Signed-off-by Shuah Khan <[email protected]>
Applied, thanks.
Signature · 5 lines
AMD Operating System Research Center Advanced Micro Devices GmbH Einsteinring 24 85609 Dornach General Managers: Alberto Bozzo Registration: Dornach, Landkr. Muenchen; Registerger. Muenchen, HRB Nr. 43632