aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorMark Nelson <markn@au1.ibm.com>2008-10-27 16:38:08 -0400
committerPaul Mackerras <paulus@samba.org>2008-10-31 01:13:48 -0400
commitf9226d572d2f8b5f564596db8c6a13e458c46191 (patch)
treebff17e54e92bfeea78f8a86181963db7de9a5549 /arch/powerpc/platforms
parentb30115ea8f685bcd1769553fe8511745f985053c (diff)
powerpc: Update remaining dma_mapping_ops to use map/unmap_page
After the merge of the 32 and 64bit DMA code, dma_direct_ops lost their map/unmap_single() functions but gained map/unmap_page(). This caused a problem for Cell because Cell's dma_iommu_fixed_ops called the dma_direct_ops if the fixed linear mapping was to be used or the iommu ops if the dynamic window was to be used. So in order to fix this problem we need to update the 64bit DMA code to use map/unmap_page. First, we update the generic IOMMU code so that iommu_map_single() becomes iommu_map_page() and iommu_unmap_single() becomes iommu_unmap_page(). Then we propagate these changes up through all the callers of these two functions and in the process update all the dma_mapping_ops so that they have map/unmap_page rahter than map/unmap_single. We can do this because on 64bit there is no HIGHMEM memory so map/unmap_page ends up performing exactly the same function as map/unmap_single, just taking different arguments. This has no affect on drivers because the dma_map_single_attrs() just ends up calling the map_page() function of the appropriate dma_mapping_ops and similarly the dma_unmap_single_attrs() calls unmap_page(). This fixes an oops on Cell blades, which oops on boot without this because they call dma_direct_ops.map_single, which is NULL. Signed-off-by: Mark Nelson <markn@au1.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/cell/iommu.c37
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c7
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c36
3 files changed, 41 insertions, 39 deletions
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index ef92e7146215..3168272ab0d7 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -593,31 +593,30 @@ static void dma_fixed_free_coherent(struct device *dev, size_t size,
593 dma_direct_ops.free_coherent(dev, size, vaddr, dma_handle); 593 dma_direct_ops.free_coherent(dev, size, vaddr, dma_handle);
594} 594}
595 595
596static dma_addr_t dma_fixed_map_single(struct device *dev, void *ptr, 596static dma_addr_t dma_fixed_map_page(struct device *dev, struct page *page,
597 size_t size, 597 unsigned long offset, size_t size,
598 enum dma_data_direction direction, 598 enum dma_data_direction direction,
599 struct dma_attrs *attrs) 599 struct dma_attrs *attrs)
600{ 600{
601 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) 601 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
602 return dma_direct_ops.map_single(dev, ptr, size, direction, 602 return dma_direct_ops.map_page(dev, page, offset, size,
603 attrs); 603 direction, attrs);
604 else 604 else
605 return iommu_map_single(dev, cell_get_iommu_table(dev), ptr, 605 return iommu_map_page(dev, cell_get_iommu_table(dev), page,
606 size, device_to_mask(dev), direction, 606 offset, size, device_to_mask(dev),
607 attrs); 607 direction, attrs);
608} 608}
609 609
610static void dma_fixed_unmap_single(struct device *dev, dma_addr_t dma_addr, 610static void dma_fixed_unmap_page(struct device *dev, dma_addr_t dma_addr,
611 size_t size, 611 size_t size, enum dma_data_direction direction,
612 enum dma_data_direction direction, 612 struct dma_attrs *attrs)
613 struct dma_attrs *attrs)
614{ 613{
615 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) 614 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
616 dma_direct_ops.unmap_single(dev, dma_addr, size, direction, 615 dma_direct_ops.unmap_page(dev, dma_addr, size, direction,
617 attrs); 616 attrs);
618 else 617 else
619 iommu_unmap_single(cell_get_iommu_table(dev), dma_addr, size, 618 iommu_unmap_page(cell_get_iommu_table(dev), dma_addr, size,
620 direction, attrs); 619 direction, attrs);
621} 620}
622 621
623static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg, 622static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg,
@@ -652,12 +651,12 @@ static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask);
652struct dma_mapping_ops dma_iommu_fixed_ops = { 651struct dma_mapping_ops dma_iommu_fixed_ops = {
653 .alloc_coherent = dma_fixed_alloc_coherent, 652 .alloc_coherent = dma_fixed_alloc_coherent,
654 .free_coherent = dma_fixed_free_coherent, 653 .free_coherent = dma_fixed_free_coherent,
655 .map_single = dma_fixed_map_single,
656 .unmap_single = dma_fixed_unmap_single,
657 .map_sg = dma_fixed_map_sg, 654 .map_sg = dma_fixed_map_sg,
658 .unmap_sg = dma_fixed_unmap_sg, 655 .unmap_sg = dma_fixed_unmap_sg,
659 .dma_supported = dma_fixed_dma_supported, 656 .dma_supported = dma_fixed_dma_supported,
660 .set_dma_mask = dma_set_mask_and_switch, 657 .set_dma_mask = dma_set_mask_and_switch,
658 .map_page = dma_fixed_map_page,
659 .unmap_page = dma_fixed_unmap_page,
661}; 660};
662 661
663static void cell_dma_dev_setup_fixed(struct device *dev); 662static void cell_dma_dev_setup_fixed(struct device *dev);
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index bb464d1211b2..bbe828f1b885 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -215,14 +215,15 @@ EXPORT_SYMBOL_GPL(iseries_hv_free);
215dma_addr_t iseries_hv_map(void *vaddr, size_t size, 215dma_addr_t iseries_hv_map(void *vaddr, size_t size,
216 enum dma_data_direction direction) 216 enum dma_data_direction direction)
217{ 217{
218 return iommu_map_single(NULL, &vio_iommu_table, vaddr, size, 218 return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr),
219 DMA_32BIT_MASK, direction, NULL); 219 (unsigned long)vaddr % PAGE_SIZE, size,
220 DMA_32BIT_MASK, direction, NULL);
220} 221}
221 222
222void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, 223void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
223 enum dma_data_direction direction) 224 enum dma_data_direction direction)
224{ 225{
225 iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction, NULL); 226 iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL);
226} 227}
227 228
228void __init iommu_vio_init(void) 229void __init iommu_vio_init(void)
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index a789bf58ca8b..661e9f77ebf6 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -555,18 +555,19 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
555} 555}
556 556
557/* Creates TCEs for a user provided buffer. The user buffer must be 557/* Creates TCEs for a user provided buffer. The user buffer must be
558 * contiguous real kernel storage (not vmalloc). The address of the buffer 558 * contiguous real kernel storage (not vmalloc). The address passed here
559 * passed here is the kernel (virtual) address of the buffer. The buffer 559 * comprises a page address and offset into that page. The dma_addr_t
560 * need not be page aligned, the dma_addr_t returned will point to the same 560 * returned will point to the same byte within the page as was passed in.
561 * byte within the page as vaddr.
562 */ 561 */
563 562
564static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, 563static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
565 enum dma_data_direction direction, struct dma_attrs *attrs) 564 unsigned long offset, size_t size, enum dma_data_direction direction,
565 struct dma_attrs *attrs)
566{ 566{
567 struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 567 struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
568 int result; 568 int result;
569 unsigned long bus_addr; 569 unsigned long bus_addr;
570 void *ptr = page_address(page) + offset;
570 571
571 result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, 572 result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
572 &bus_addr, 573 &bus_addr,
@@ -580,15 +581,16 @@ static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size,
580 return bus_addr; 581 return bus_addr;
581} 582}
582 583
583static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, 584static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
584 size_t size, 585 unsigned long offset, size_t size,
585 enum dma_data_direction direction, 586 enum dma_data_direction direction,
586 struct dma_attrs *attrs) 587 struct dma_attrs *attrs)
587{ 588{
588 struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 589 struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
589 int result; 590 int result;
590 unsigned long bus_addr; 591 unsigned long bus_addr;
591 u64 iopte_flag; 592 u64 iopte_flag;
593 void *ptr = page_address(page) + offset;
592 594
593 iopte_flag = IOPTE_M; 595 iopte_flag = IOPTE_M;
594 switch (direction) { 596 switch (direction) {
@@ -615,7 +617,7 @@ static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr,
615 return bus_addr; 617 return bus_addr;
616} 618}
617 619
618static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, 620static void ps3_unmap_page(struct device *_dev, dma_addr_t dma_addr,
619 size_t size, enum dma_data_direction direction, struct dma_attrs *attrs) 621 size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
620{ 622{
621 struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 623 struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
@@ -689,21 +691,21 @@ static int ps3_dma_supported(struct device *_dev, u64 mask)
689static struct dma_mapping_ops ps3_sb_dma_ops = { 691static struct dma_mapping_ops ps3_sb_dma_ops = {
690 .alloc_coherent = ps3_alloc_coherent, 692 .alloc_coherent = ps3_alloc_coherent,
691 .free_coherent = ps3_free_coherent, 693 .free_coherent = ps3_free_coherent,
692 .map_single = ps3_sb_map_single,
693 .unmap_single = ps3_unmap_single,
694 .map_sg = ps3_sb_map_sg, 694 .map_sg = ps3_sb_map_sg,
695 .unmap_sg = ps3_sb_unmap_sg, 695 .unmap_sg = ps3_sb_unmap_sg,
696 .dma_supported = ps3_dma_supported 696 .dma_supported = ps3_dma_supported,
697 .map_page = ps3_sb_map_page,
698 .unmap_page = ps3_unmap_page,
697}; 699};
698 700
699static struct dma_mapping_ops ps3_ioc0_dma_ops = { 701static struct dma_mapping_ops ps3_ioc0_dma_ops = {
700 .alloc_coherent = ps3_alloc_coherent, 702 .alloc_coherent = ps3_alloc_coherent,
701 .free_coherent = ps3_free_coherent, 703 .free_coherent = ps3_free_coherent,
702 .map_single = ps3_ioc0_map_single,
703 .unmap_single = ps3_unmap_single,
704 .map_sg = ps3_ioc0_map_sg, 704 .map_sg = ps3_ioc0_map_sg,
705 .unmap_sg = ps3_ioc0_unmap_sg, 705 .unmap_sg = ps3_ioc0_unmap_sg,
706 .dma_supported = ps3_dma_supported 706 .dma_supported = ps3_dma_supported,
707 .map_page = ps3_ioc0_map_page,
708 .unmap_page = ps3_unmap_page,
707}; 709};
708 710
709/** 711/**