aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2008-03-14 01:47:39 -0400
committerPaul Mackerras <paulus@samba.org>2008-03-19 19:15:10 -0400
commit3a4295d101d9654ca909b64c786f9da6ca1bf37a (patch)
tree25bec42d4e6d98f8b5dd3fec0b431ec51958afbb
parenta72a6f53ddb95723960bb64c011457e9739941d7 (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>
-rw-r--r--arch/powerpc/platforms/cell/iommu.c41
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
803static u64 cell_iommu_get_fixed_address(struct device *dev) 803static 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
846out: 855out:
847 of_node_put(np); 856 of_node_put(np);
848 857
849 return pci_addr; 858 return dev_addr;
850} 859}
851 860
852static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask) 861static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask)