diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2008-03-14 01:47:39 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-03-19 19:15:10 -0400 |
commit | 3a4295d101d9654ca909b64c786f9da6ca1bf37a (patch) | |
tree | 25bec42d4e6d98f8b5dd3fec0b431ec51958afbb /arch/powerpc/platforms/cell/iommu.c | |
parent | a72a6f53ddb95723960bb64c011457e9739941d7 (diff) |
[POWERPC] Fix cell IOMMU code to cope with empty dma-ranges and non-PCI 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>
Diffstat (limited to 'arch/powerpc/platforms/cell/iommu.c')
-rw-r--r-- | arch/powerpc/platforms/cell/iommu.c | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 20ea0e118f24..d75ccded7f10 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c | |||
@@ -802,17 +802,24 @@ static int __init cell_iommu_init_disabled(void) | |||
802 | 802 | ||
803 | static u64 cell_iommu_get_fixed_address(struct device *dev) | 803 | static u64 cell_iommu_get_fixed_address(struct device *dev) |
804 | { | 804 | { |
805 | u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR; | 805 | u64 cpu_addr, size, best_size, dev_addr = OF_BAD_ADDR; |
806 | struct device_node *np; | 806 | struct device_node *np; |
807 | const u32 *ranges = NULL; | 807 | const u32 *ranges = NULL; |
808 | int i, len, best; | 808 | int i, len, best, naddr, nsize, pna, range_size; |
809 | 809 | ||
810 | np = of_node_get(dev->archdata.of_node); | 810 | np = of_node_get(dev->archdata.of_node); |
811 | while (np) { | 811 | while (1) { |
812 | naddr = of_n_addr_cells(np); | ||
813 | nsize = of_n_size_cells(np); | ||
814 | np = of_get_next_parent(np); | ||
815 | if (!np) | ||
816 | break; | ||
817 | |||
812 | ranges = of_get_property(np, "dma-ranges", &len); | 818 | ranges = of_get_property(np, "dma-ranges", &len); |
813 | if (ranges) | 819 | |
820 | /* Ignore empty ranges, they imply no translation required */ | ||
821 | if (ranges && len > 0) | ||
814 | break; | 822 | break; |
815 | np = of_get_next_parent(np); | ||
816 | } | 823 | } |
817 | 824 | ||
818 | if (!ranges) { | 825 | if (!ranges) { |
@@ -822,15 +829,17 @@ static u64 cell_iommu_get_fixed_address(struct device *dev) | |||
822 | 829 | ||
823 | len /= sizeof(u32); | 830 | len /= sizeof(u32); |
824 | 831 | ||
832 | pna = of_n_addr_cells(np); | ||
833 | range_size = naddr + nsize + pna; | ||
834 | |||
825 | /* dma-ranges format: | 835 | /* dma-ranges format: |
826 | * 1 cell: pci space | 836 | * child addr : naddr cells |
827 | * 2 cells: pci address | 837 | * parent addr : pna cells |
828 | * 2 cells: parent address | 838 | * size : nsize cells |
829 | * 2 cells: size | ||
830 | */ | 839 | */ |
831 | for (i = 0, best = -1, best_size = 0; i < len; i += 7) { | 840 | for (i = 0, best = -1, best_size = 0; i < len; i += range_size) { |
832 | cpu_addr = of_translate_dma_address(np, ranges +i + 3); | 841 | cpu_addr = of_translate_dma_address(np, ranges + i + naddr); |
833 | size = of_read_number(ranges + i + 5, 2); | 842 | size = of_read_number(ranges + i + naddr + pna, nsize); |
834 | 843 | ||
835 | if (cpu_addr == 0 && size > best_size) { | 844 | if (cpu_addr == 0 && size > best_size) { |
836 | best = i; | 845 | best = i; |
@@ -838,15 +847,15 @@ static u64 cell_iommu_get_fixed_address(struct device *dev) | |||
838 | } | 847 | } |
839 | } | 848 | } |
840 | 849 | ||
841 | if (best >= 0) | 850 | if (best >= 0) { |
842 | pci_addr = of_read_number(ranges + best + 1, 2); | 851 | dev_addr = of_read_number(ranges + best, naddr); |
843 | else | 852 | } else |
844 | dev_dbg(dev, "iommu: no suitable range found!\n"); | 853 | dev_dbg(dev, "iommu: no suitable range found!\n"); |
845 | 854 | ||
846 | out: | 855 | out: |
847 | of_node_put(np); | 856 | of_node_put(np); |
848 | 857 | ||
849 | return pci_addr; | 858 | return dev_addr; |
850 | } | 859 | } |
851 | 860 | ||
852 | static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask) | 861 | static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask) |