Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 347495
b: refs/heads/master
c: eb9c952
h: refs/heads/master
i:
  347493: 851cae0
  347491: 785a2e9
  347487: 46e1a55
v: v3
  • Loading branch information
Alex Williamson authored and Joerg Roedel committed Oct 24, 2012
1 parent 738cef8 commit 50375b5
Show file tree
Hide file tree
Showing 17 changed files with 53 additions and 234 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a0157573041403e7507a6f3f32279fc14ff5c02e
refs/heads/master: eb9c95271eafb62f7024547016ad00636c1425c1
126 changes: 0 additions & 126 deletions trunk/Documentation/DMA-API-HOWTO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -468,46 +468,11 @@ 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.

Expand All @@ -524,27 +489,13 @@ 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;
}

...

dma_unmap_page(dev, dma_handle, size, direction);

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);
Expand Down Expand Up @@ -627,14 +578,6 @@ 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;
Expand Down Expand Up @@ -715,75 +658,6 @@ 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
Expand Down
12 changes: 0 additions & 12 deletions trunk/Documentation/DMA-API.txt
Original file line number Diff line number Diff line change
Expand Up @@ -678,15 +678,3 @@ 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.

1 change: 0 additions & 1 deletion trunk/arch/arm/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ 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;
}

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/arm64/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
static inline int dma_mapping_error(struct device *dev, dma_addr_t dev_addr)
{
struct dma_map_ops *ops = get_dma_ops(dev);
debug_dma_mapping_error(dev, dev_addr);
return ops->mapping_error(dev, dev_addr);
}

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/c6x/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
*/
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
debug_dma_mapping_error(dev, dma_addr);
return dma_addr == ~0;
}

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/ia64/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ static inline void dma_free_attrs(struct device *dev, size_t size,
static inline int dma_mapping_error(struct device *dev, dma_addr_t daddr)
{
struct dma_map_ops *ops = platform_dma_get_ops(dev);
debug_dma_mapping_error(dev, daddr);
return ops->mapping_error(dev, daddr);
}

Expand Down
2 changes: 0 additions & 2 deletions trunk/arch/microblaze/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ static inline void __dma_sync(unsigned long paddr,
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
struct dma_map_ops *ops = get_dma_ops(dev);

debug_dma_mapping_error(dev, dma_addr);
if (ops->mapping_error)
return ops->mapping_error(dev, dma_addr);

Expand Down
2 changes: 0 additions & 2 deletions trunk/arch/mips/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ static inline int dma_supported(struct device *dev, u64 mask)
static inline int dma_mapping_error(struct device *dev, u64 mask)
{
struct dma_map_ops *ops = get_dma_ops(dev);

debug_dma_mapping_error(dev, mask);
return ops->mapping_error(dev, mask);
}

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/powerpc/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
struct dma_map_ops *dma_ops = get_dma_ops(dev);

debug_dma_mapping_error(dev, dma_addr);
if (dma_ops->mapping_error)
return dma_ops->mapping_error(dev, dma_addr);

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/sh/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
struct dma_map_ops *ops = get_dma_ops(dev);

debug_dma_mapping_error(dev, dma_addr);
if (ops->mapping_error)
return ops->mapping_error(dev, dma_addr);

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/sparc/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ static inline void dma_free_attrs(struct device *dev, size_t size,

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);
}

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/tile/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
static inline int
dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
debug_dma_mapping_error(dev, dma_addr);
return get_dma_ops(dev)->mapping_error(dev, dma_addr);
}

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/x86/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
struct dma_map_ops *ops = get_dma_ops(dev);
debug_dma_mapping_error(dev, dma_addr);
if (ops->mapping_error)
return ops->mapping_error(dev, dma_addr);

Expand Down
61 changes: 43 additions & 18 deletions trunk/drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,39 +276,32 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)

#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)

static int iommu_init_device(struct device *dev)
static int init_iommu_group(struct device *dev)
{
struct pci_dev *dma_pdev = NULL, *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
struct iommu_group *group;
u16 alias;
struct pci_dev *dma_pdev = NULL;
int ret;

if (dev->archdata.iommu)
group = iommu_group_get(dev);
if (group) {
iommu_group_put(group);
return 0;
}

dev_data = find_dev_data(get_device_id(dev));
if (!dev_data)
return -ENOMEM;

alias = amd_iommu_alias_table[dev_data->devid];
if (alias != dev_data->devid) {
struct iommu_dev_data *alias_data;

alias_data = find_dev_data(alias);
if (alias_data == NULL) {
pr_err("AMD-Vi: Warning: Unhandled device %s\n",
dev_name(dev));
free_dev_data(dev_data);
return -ENOTSUPP;
}
dev_data->alias_data = alias_data;
if (dev_data->alias_data) {
u16 alias;

alias = amd_iommu_alias_table[dev_data->devid];
dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
}

if (dma_pdev == NULL)
dma_pdev = pci_dev_get(pdev);
if (!dma_pdev)
dma_pdev = pci_dev_get(to_pci_dev(dev));

/* Account for quirked devices */
swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
Expand Down Expand Up @@ -358,6 +351,38 @@ static int iommu_init_device(struct device *dev)

iommu_group_put(group);

return ret;
}

static int iommu_init_device(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
u16 alias;
int ret;

if (dev->archdata.iommu)
return 0;

dev_data = find_dev_data(get_device_id(dev));
if (!dev_data)
return -ENOMEM;

alias = amd_iommu_alias_table[dev_data->devid];
if (alias != dev_data->devid) {
struct iommu_dev_data *alias_data;

alias_data = find_dev_data(alias);
if (alias_data == NULL) {
pr_err("AMD-Vi: Warning: Unhandled device %s\n",
dev_name(dev));
free_dev_data(dev_data);
return -ENOTSUPP;
}
dev_data->alias_data = alias_data;
}

ret = init_iommu_group(dev);
if (ret)
return ret;

Expand Down
7 changes: 0 additions & 7 deletions trunk/include/linux/dma-debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ extern void debug_dma_map_page(struct device *dev, struct page *page,
int direction, dma_addr_t dma_addr,
bool map_single);

extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);

extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
size_t size, int direction, bool map_single);

Expand Down Expand Up @@ -107,11 +105,6 @@ static inline void debug_dma_map_page(struct device *dev, struct page *page,
{
}

static inline void debug_dma_mapping_error(struct device *dev,
dma_addr_t dma_addr)
{
}

static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
size_t size, int direction,
bool map_single)
Expand Down
Loading

0 comments on commit 50375b5

Please sign in to comment.