diff options
| -rw-r--r-- | Documentation/DMA-API-HOWTO.txt | 126 | 
1 files changed, 126 insertions, 0 deletions
diff --git a/Documentation/DMA-API-HOWTO.txt b/Documentation/DMA-API-HOWTO.txt index a0b6250add7..4a4fb295cee 100644 --- a/Documentation/DMA-API-HOWTO.txt +++ b/Documentation/DMA-API-HOWTO.txt @@ -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  |