aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Nelson <markn@au1.ibm.com>2008-07-18 09:03:34 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-07-21 20:39:36 -0400
commit1ed6af73440c5ec920884bb800685a8cab4ce847 (patch)
tree68a452bd8e9d07e9a28cef63ee3b72e0319635da
parent79e25bac124a7d1d7bf966f06dd9398a1b5f3d20 (diff)
powerpc/cell: Add DMA_ATTR_WEAK_ORDERING dma attribute and use in Cell IOMMU code
Introduce a new dma attriblue DMA_ATTR_WEAK_ORDERING to use weak ordering on DMA mappings in the Cell processor. Add the code to the Cell's IOMMU implementation to use this code. Dynamic mappings can be weakly or strongly ordered on an individual basis but the fixed mapping has to be either completely strong or completely weak. This is currently decided by a kernel boot option (pass iommu_fixed=weak for a weakly ordered fixed linear mapping, strongly ordered is the default). Signed-off-by: Mark Nelson <markn@au1.ibm.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--Documentation/DMA-attributes.txt9
-rw-r--r--arch/powerpc/platforms/cell/iommu.c113
-rw-r--r--include/linux/dma-attrs.h1
3 files changed, 118 insertions, 5 deletions
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt
index 6d772f84b477..b768cc0e402b 100644
--- a/Documentation/DMA-attributes.txt
+++ b/Documentation/DMA-attributes.txt
@@ -22,3 +22,12 @@ ready and available in memory. The DMA of the "completion indication"
22could race with data DMA. Mapping the memory used for completion 22could race with data DMA. Mapping the memory used for completion
23indications with DMA_ATTR_WRITE_BARRIER would prevent the race. 23indications with DMA_ATTR_WRITE_BARRIER would prevent the race.
24 24
25DMA_ATTR_WEAK_ORDERING
26----------------------
27
28DMA_ATTR_WEAK_ORDERING specifies that reads and writes to the mapping
29may be weakly ordered, that is that reads and writes may pass each other.
30
31Since it is optional for platforms to implement DMA_ATTR_WEAK_ORDERING,
32those that do not will simply ignore the attribute and exhibit default
33behavior.
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 3b7078453e7f..208005ca262c 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -199,6 +199,8 @@ static void tce_build_cell(struct iommu_table *tbl, long index, long npages,
199 base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | 199 base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW |
200 (window->ioid & IOPTE_IOID_Mask); 200 (window->ioid & IOPTE_IOID_Mask);
201#endif 201#endif
202 if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)))
203 base_pte &= ~IOPTE_SO_RW;
202 204
203 io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); 205 io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
204 206
@@ -539,7 +541,9 @@ static struct cbe_iommu *cell_iommu_for_node(int nid)
539static unsigned long cell_dma_direct_offset; 541static unsigned long cell_dma_direct_offset;
540 542
541static unsigned long dma_iommu_fixed_base; 543static unsigned long dma_iommu_fixed_base;
542struct dma_mapping_ops dma_iommu_fixed_ops; 544
545/* iommu_fixed_is_weak is set if booted with iommu_fixed=weak */
546static int iommu_fixed_is_weak;
543 547
544static struct iommu_table *cell_get_iommu_table(struct device *dev) 548static struct iommu_table *cell_get_iommu_table(struct device *dev)
545{ 549{
@@ -563,6 +567,98 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
563 return &window->table; 567 return &window->table;
564} 568}
565 569
570/* A coherent allocation implies strong ordering */
571
572static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
573 dma_addr_t *dma_handle, gfp_t flag)
574{
575 if (iommu_fixed_is_weak)
576 return iommu_alloc_coherent(dev, cell_get_iommu_table(dev),
577 size, dma_handle,
578 device_to_mask(dev), flag,
579 dev->archdata.numa_node);
580 else
581 return dma_direct_ops.alloc_coherent(dev, size, dma_handle,
582 flag);
583}
584
585static void dma_fixed_free_coherent(struct device *dev, size_t size,
586 void *vaddr, dma_addr_t dma_handle)
587{
588 if (iommu_fixed_is_weak)
589 iommu_free_coherent(cell_get_iommu_table(dev), size, vaddr,
590 dma_handle);
591 else
592 dma_direct_ops.free_coherent(dev, size, vaddr, dma_handle);
593}
594
595static dma_addr_t dma_fixed_map_single(struct device *dev, void *ptr,
596 size_t size,
597 enum dma_data_direction direction,
598 struct dma_attrs *attrs)
599{
600 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
601 return dma_direct_ops.map_single(dev, ptr, size, direction,
602 attrs);
603 else
604 return iommu_map_single(dev, cell_get_iommu_table(dev), ptr,
605 size, device_to_mask(dev), direction,
606 attrs);
607}
608
609static void dma_fixed_unmap_single(struct device *dev, dma_addr_t dma_addr,
610 size_t size,
611 enum dma_data_direction direction,
612 struct dma_attrs *attrs)
613{
614 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
615 dma_direct_ops.unmap_single(dev, dma_addr, size, direction,
616 attrs);
617 else
618 iommu_unmap_single(cell_get_iommu_table(dev), dma_addr, size,
619 direction, attrs);
620}
621
622static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg,
623 int nents, enum dma_data_direction direction,
624 struct dma_attrs *attrs)
625{
626 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
627 return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs);
628 else
629 return iommu_map_sg(dev, cell_get_iommu_table(dev), sg, nents,
630 device_to_mask(dev), direction, attrs);
631}
632
633static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg,
634 int nents, enum dma_data_direction direction,
635 struct dma_attrs *attrs)
636{
637 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
638 dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs);
639 else
640 iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents, direction,
641 attrs);
642}
643
644static int dma_fixed_dma_supported(struct device *dev, u64 mask)
645{
646 return mask == DMA_64BIT_MASK;
647}
648
649static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask);
650
651struct dma_mapping_ops dma_iommu_fixed_ops = {
652 .alloc_coherent = dma_fixed_alloc_coherent,
653 .free_coherent = dma_fixed_free_coherent,
654 .map_single = dma_fixed_map_single,
655 .unmap_single = dma_fixed_unmap_single,
656 .map_sg = dma_fixed_map_sg,
657 .unmap_sg = dma_fixed_unmap_sg,
658 .dma_supported = dma_fixed_dma_supported,
659 .set_dma_mask = dma_set_mask_and_switch,
660};
661
566static void cell_dma_dev_setup_fixed(struct device *dev); 662static void cell_dma_dev_setup_fixed(struct device *dev);
567 663
568static void cell_dma_dev_setup(struct device *dev) 664static void cell_dma_dev_setup(struct device *dev)
@@ -919,9 +1015,16 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
919 1015
920 pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase); 1016 pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
921 1017
922 base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW 1018 base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M
923 | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask); 1019 | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
924 1020
1021 if (iommu_fixed_is_weak)
1022 pr_info("IOMMU: Using weak ordering for fixed mapping\n");
1023 else {
1024 pr_info("IOMMU: Using strong ordering for fixed mapping\n");
1025 base_pte |= IOPTE_SO_RW;
1026 }
1027
925 for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) { 1028 for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) {
926 /* Don't touch the dynamic region */ 1029 /* Don't touch the dynamic region */
927 ioaddr = uaddr + fbase; 1030 ioaddr = uaddr + fbase;
@@ -1037,9 +1140,6 @@ static int __init cell_iommu_fixed_mapping_init(void)
1037 cell_iommu_setup_window(iommu, np, dbase, dsize, 0); 1140 cell_iommu_setup_window(iommu, np, dbase, dsize, 0);
1038 } 1141 }
1039 1142
1040 dma_iommu_fixed_ops = dma_direct_ops;
1041 dma_iommu_fixed_ops.set_dma_mask = dma_set_mask_and_switch;
1042
1043 dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch; 1143 dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch;
1044 set_pci_dma_ops(&dma_iommu_ops); 1144 set_pci_dma_ops(&dma_iommu_ops);
1045 1145
@@ -1053,6 +1153,9 @@ static int __init setup_iommu_fixed(char *str)
1053 if (strcmp(str, "off") == 0) 1153 if (strcmp(str, "off") == 0)
1054 iommu_fixed_disabled = 1; 1154 iommu_fixed_disabled = 1;
1055 1155
1156 else if (strcmp(str, "weak") == 0)
1157 iommu_fixed_is_weak = 1;
1158
1056 return 1; 1159 return 1;
1057} 1160}
1058__setup("iommu_fixed=", setup_iommu_fixed); 1161__setup("iommu_fixed=", setup_iommu_fixed);
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
index 1677e2bfa00c..71ad34eca6e3 100644
--- a/include/linux/dma-attrs.h
+++ b/include/linux/dma-attrs.h
@@ -12,6 +12,7 @@
12 */ 12 */
13enum dma_attr { 13enum dma_attr {
14 DMA_ATTR_WRITE_BARRIER, 14 DMA_ATTR_WRITE_BARRIER,
15 DMA_ATTR_WEAK_ORDERING,
15 DMA_ATTR_MAX, 16 DMA_ATTR_MAX,
16}; 17};
17 18