diff options
-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) |