Skip to content

Commit

Permalink
[POWERPC] Fix cell IOMMU code to cope with empty dma-ranges and non-P…
Browse files Browse the repository at this point in the history
…CI devices

The cell IOMMU code to parse the dma-ranges properties, used for the fixed
mapping, was broken in two ways for some devices.

Firstly it didn't cope with empty dma-ranges properties. An empty property
implies no translation so can be safely skipped.

The code also wrongly assumed it would be looking at PCI devices, and hard
coded the number of address and size cells.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Michael Ellerman authored and Paul Mackerras committed Mar 19, 2008
1 parent a72a6f5 commit 3a4295d
Showing 1 changed file with 25 additions and 16 deletions.
41 changes: 25 additions & 16 deletions arch/powerpc/platforms/cell/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -802,17 +802,24 @@ static int __init cell_iommu_init_disabled(void)

static u64 cell_iommu_get_fixed_address(struct device *dev)
{
u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR;
u64 cpu_addr, size, best_size, dev_addr = OF_BAD_ADDR;
struct device_node *np;
const u32 *ranges = NULL;
int i, len, best;
int i, len, best, naddr, nsize, pna, range_size;

np = of_node_get(dev->archdata.of_node);
while (np) {
while (1) {
naddr = of_n_addr_cells(np);
nsize = of_n_size_cells(np);
np = of_get_next_parent(np);
if (!np)
break;

ranges = of_get_property(np, "dma-ranges", &len);
if (ranges)

/* Ignore empty ranges, they imply no translation required */
if (ranges && len > 0)
break;
np = of_get_next_parent(np);
}

if (!ranges) {
Expand All @@ -822,31 +829,33 @@ static u64 cell_iommu_get_fixed_address(struct device *dev)

len /= sizeof(u32);

pna = of_n_addr_cells(np);
range_size = naddr + nsize + pna;

/* dma-ranges format:
* 1 cell: pci space
* 2 cells: pci address
* 2 cells: parent address
* 2 cells: size
* child addr : naddr cells
* parent addr : pna cells
* size : nsize cells
*/
for (i = 0, best = -1, best_size = 0; i < len; i += 7) {
cpu_addr = of_translate_dma_address(np, ranges +i + 3);
size = of_read_number(ranges + i + 5, 2);
for (i = 0, best = -1, best_size = 0; i < len; i += range_size) {
cpu_addr = of_translate_dma_address(np, ranges + i + naddr);
size = of_read_number(ranges + i + naddr + pna, nsize);

if (cpu_addr == 0 && size > best_size) {
best = i;
best_size = size;
}
}

if (best >= 0)
pci_addr = of_read_number(ranges + best + 1, 2);
else
if (best >= 0) {
dev_addr = of_read_number(ranges + best, naddr);
} else
dev_dbg(dev, "iommu: no suitable range found!\n");

out:
of_node_put(np);

return pci_addr;
return dev_addr;
}

static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask)
Expand Down

0 comments on commit 3a4295d

Please sign in to comment.