Loading Documentation/DMA-API-HOWTO.txt +126 −0 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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; } ... Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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 Loading Documentation/DMA-API.txt +12 −0 Original line number Diff line number Diff line Loading @@ -678,3 +678,15 @@ out of dma_debug_entries. These entries are preallocated at boot. The number of preallocated entries is defined per architecture. If it is too low for you boot with 'dma_debug_entries=<your_desired_number>' to overwrite the architectural default. void debug_dmap_mapping_error(struct device *dev, dma_addr_t dma_addr); dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. This interface clears a flag set by debug_dma_map_page() to indicate that dma_mapping_error() has been called by the driver. When driver does unmap, debug_dma_unmap() checks the flag and if this flag is still set, prints warning message that includes call trace that leads up to the unmap. This interface can be called from dma_mapping_error() routines to enable dma mapping error check debugging. arch/arm/include/asm/dma-mapping.h +1 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { debug_dma_mapping_error(dev, dma_addr); return dma_addr == DMA_ERROR_CODE; } Loading arch/arm/mach-omap2/Makefile +0 −2 Original line number Diff line number Diff line Loading @@ -184,8 +184,6 @@ obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o mailbox_mach-objs := mailbox.o obj-$(CONFIG_OMAP_IOMMU) += iommu2.o iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o obj-y += $(iommu-m) $(iommu-y) Loading arch/arm/mach-omap2/clock44xx_data.c +0 −22 Original line number Diff line number Diff line Loading @@ -1316,16 +1316,6 @@ static struct clk dmic_fck = { .clkdm_name = "abe_clkdm", }; static struct clk dsp_fck = { .name = "dsp_fck", .ops = &clkops_omap2_dflt, .enable_reg = OMAP4430_CM_TESLA_TESLA_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "tesla_clkdm", .parent = &dpll_iva_m4x2_ck, .recalc = &followparent_recalc, }; static struct clk dss_sys_clk = { .name = "dss_sys_clk", .ops = &clkops_omap2_dflt, Loading Loading @@ -1696,16 +1686,6 @@ static struct clk i2c4_fck = { .recalc = &followparent_recalc, }; static struct clk ipu_fck = { .name = "ipu_fck", .ops = &clkops_omap2_dflt, .enable_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "ducati_clkdm", .parent = &ducati_clk_mux_ck, .recalc = &followparent_recalc, }; static struct clk iss_ctrlclk = { .name = "iss_ctrlclk", .ops = &clkops_omap2_dflt, Loading Loading @@ -3151,7 +3131,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X), CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X), CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk, CK_443X), Loading Loading @@ -3183,7 +3162,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "i2c2_fck", &i2c2_fck, CK_443X), CLK(NULL, "i2c3_fck", &i2c3_fck, CK_443X), CLK(NULL, "i2c4_fck", &i2c4_fck, CK_443X), CLK(NULL, "ipu_fck", &ipu_fck, CK_443X), CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X), CLK(NULL, "iss_fck", &iss_fck, CK_443X), CLK(NULL, "iva_fck", &iva_fck, CK_443X), Loading Loading
Documentation/DMA-API-HOWTO.txt +126 −0 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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; } ... Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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 Loading
Documentation/DMA-API.txt +12 −0 Original line number Diff line number Diff line Loading @@ -678,3 +678,15 @@ out of dma_debug_entries. These entries are preallocated at boot. The number of preallocated entries is defined per architecture. If it is too low for you boot with 'dma_debug_entries=<your_desired_number>' to overwrite the architectural default. void debug_dmap_mapping_error(struct device *dev, dma_addr_t dma_addr); dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. This interface clears a flag set by debug_dma_map_page() to indicate that dma_mapping_error() has been called by the driver. When driver does unmap, debug_dma_unmap() checks the flag and if this flag is still set, prints warning message that includes call trace that leads up to the unmap. This interface can be called from dma_mapping_error() routines to enable dma mapping error check debugging.
arch/arm/include/asm/dma-mapping.h +1 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { debug_dma_mapping_error(dev, dma_addr); return dma_addr == DMA_ERROR_CODE; } Loading
arch/arm/mach-omap2/Makefile +0 −2 Original line number Diff line number Diff line Loading @@ -184,8 +184,6 @@ obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o mailbox_mach-objs := mailbox.o obj-$(CONFIG_OMAP_IOMMU) += iommu2.o iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o obj-y += $(iommu-m) $(iommu-y) Loading
arch/arm/mach-omap2/clock44xx_data.c +0 −22 Original line number Diff line number Diff line Loading @@ -1316,16 +1316,6 @@ static struct clk dmic_fck = { .clkdm_name = "abe_clkdm", }; static struct clk dsp_fck = { .name = "dsp_fck", .ops = &clkops_omap2_dflt, .enable_reg = OMAP4430_CM_TESLA_TESLA_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "tesla_clkdm", .parent = &dpll_iva_m4x2_ck, .recalc = &followparent_recalc, }; static struct clk dss_sys_clk = { .name = "dss_sys_clk", .ops = &clkops_omap2_dflt, Loading Loading @@ -1696,16 +1686,6 @@ static struct clk i2c4_fck = { .recalc = &followparent_recalc, }; static struct clk ipu_fck = { .name = "ipu_fck", .ops = &clkops_omap2_dflt, .enable_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "ducati_clkdm", .parent = &ducati_clk_mux_ck, .recalc = &followparent_recalc, }; static struct clk iss_ctrlclk = { .name = "iss_ctrlclk", .ops = &clkops_omap2_dflt, Loading Loading @@ -3151,7 +3131,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X), CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X), CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk, CK_443X), Loading Loading @@ -3183,7 +3162,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "i2c2_fck", &i2c2_fck, CK_443X), CLK(NULL, "i2c3_fck", &i2c3_fck, CK_443X), CLK(NULL, "i2c4_fck", &i2c4_fck, CK_443X), CLK(NULL, "ipu_fck", &ipu_fck, CK_443X), CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X), CLK(NULL, "iss_fck", &iss_fck, CK_443X), CLK(NULL, "iva_fck", &iva_fck, CK_443X), Loading