aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2013-08-02 12:24:42 -0400
committerChris Metcalf <cmetcalf@tilera.com>2013-08-06 12:52:33 -0400
commit803c874abe1358998ab65a8cca728684ebb50a13 (patch)
tree06f6ca14ed84458c0bd2b40e8b61a3cb4c0e8e1c
parent26cde05a2cb7d4c0f4cd1d4aeeadc2939c972786 (diff)
tile: support LSI MEGARAID SAS HBA hybrid dma_ops
The LSI MEGARAID SAS HBA suffers from the problem where it can do 64-bit DMA to streaming buffers but not to consistent buffers. In other words, 64-bit DMA is used for disk data transfers and 32-bit DMA must be used for control message transfers. According to LSI, the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this. Note that on most other platforms, the 64-bit DMA addressing space is the same as the 32-bit DMA space and they overlap the physical memory space. No special arrangement is needed to support this kind of mixed DMA capability. On TILE-Gx, the 64-bit DMA space is completely separate from the 32-bit DMA space. Due to the use of the IOMMU, the 64-bit DMA space doesn't overlap the physical memory space. On the other hand, the 32-bit DMA space overlaps the physical memory space under 4GB. The separate address spaces make it necessary to have separate dma_ops. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
-rw-r--r--arch/tile/include/asm/dma-mapping.h10
-rw-r--r--arch/tile/kernel/pci-dma.c40
2 files changed, 38 insertions, 12 deletions
diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h
index f2ff191376b4..4a60059876e6 100644
--- a/arch/tile/include/asm/dma-mapping.h
+++ b/arch/tile/include/asm/dma-mapping.h
@@ -23,6 +23,7 @@
23extern struct dma_map_ops *tile_dma_map_ops; 23extern struct dma_map_ops *tile_dma_map_ops;
24extern struct dma_map_ops *gx_pci_dma_map_ops; 24extern struct dma_map_ops *gx_pci_dma_map_ops;
25extern struct dma_map_ops *gx_legacy_pci_dma_map_ops; 25extern struct dma_map_ops *gx_legacy_pci_dma_map_ops;
26extern struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
26 27
27static inline struct dma_map_ops *get_dma_ops(struct device *dev) 28static inline struct dma_map_ops *get_dma_ops(struct device *dev)
28{ 29{
@@ -44,12 +45,12 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off)
44 45
45static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) 46static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
46{ 47{
47 return paddr + get_dma_offset(dev); 48 return paddr;
48} 49}
49 50
50static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) 51static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
51{ 52{
52 return daddr - get_dma_offset(dev); 53 return daddr;
53} 54}
54 55
55static inline void dma_mark_clean(void *addr, size_t size) {} 56static inline void dma_mark_clean(void *addr, size_t size) {}
@@ -88,7 +89,10 @@ dma_set_mask(struct device *dev, u64 mask)
88 struct dma_map_ops *dma_ops = get_dma_ops(dev); 89 struct dma_map_ops *dma_ops = get_dma_ops(dev);
89 90
90 /* Handle legacy PCI devices with limited memory addressability. */ 91 /* Handle legacy PCI devices with limited memory addressability. */
91 if ((dma_ops == gx_pci_dma_map_ops) && (mask <= DMA_BIT_MASK(32))) { 92 if ((dma_ops == gx_pci_dma_map_ops ||
93 dma_ops == gx_hybrid_pci_dma_map_ops ||
94 dma_ops == gx_legacy_pci_dma_map_ops) &&
95 (mask <= DMA_BIT_MASK(32))) {
92 set_dma_ops(dev, gx_legacy_pci_dma_map_ops); 96 set_dma_ops(dev, gx_legacy_pci_dma_map_ops);
93 set_dma_offset(dev, 0); 97 set_dma_offset(dev, 0);
94 if (mask > dev->archdata.max_direct_dma_addr) 98 if (mask > dev->archdata.max_direct_dma_addr)
diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c
index b9fe80ec1089..7e22e73264a9 100644
--- a/arch/tile/kernel/pci-dma.c
+++ b/arch/tile/kernel/pci-dma.c
@@ -357,7 +357,7 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
357 357
358 addr = page_to_phys(pg); 358 addr = page_to_phys(pg);
359 359
360 *dma_handle = phys_to_dma(dev, addr); 360 *dma_handle = addr + get_dma_offset(dev);
361 361
362 return page_address(pg); 362 return page_address(pg);
363} 363}
@@ -387,7 +387,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
387 sg->dma_address = sg_phys(sg); 387 sg->dma_address = sg_phys(sg);
388 __dma_prep_pa_range(sg->dma_address, sg->length, direction); 388 __dma_prep_pa_range(sg->dma_address, sg->length, direction);
389 389
390 sg->dma_address = phys_to_dma(dev, sg->dma_address); 390 sg->dma_address = sg->dma_address + get_dma_offset(dev);
391#ifdef CONFIG_NEED_SG_DMA_LENGTH 391#ifdef CONFIG_NEED_SG_DMA_LENGTH
392 sg->dma_length = sg->length; 392 sg->dma_length = sg->length;
393#endif 393#endif
@@ -422,7 +422,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
422 BUG_ON(offset + size > PAGE_SIZE); 422 BUG_ON(offset + size > PAGE_SIZE);
423 __dma_prep_page(page, offset, size, direction); 423 __dma_prep_page(page, offset, size, direction);
424 424
425 return phys_to_dma(dev, page_to_pa(page) + offset); 425 return page_to_pa(page) + offset + get_dma_offset(dev);
426} 426}
427 427
428static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address, 428static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
@@ -432,7 +432,7 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
432{ 432{
433 BUG_ON(!valid_dma_direction(direction)); 433 BUG_ON(!valid_dma_direction(direction));
434 434
435 dma_address = dma_to_phys(dev, dma_address); 435 dma_address -= get_dma_offset(dev);
436 436
437 __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)), 437 __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
438 dma_address & PAGE_OFFSET, size, direction); 438 dma_address & PAGE_OFFSET, size, direction);
@@ -445,7 +445,7 @@ static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
445{ 445{
446 BUG_ON(!valid_dma_direction(direction)); 446 BUG_ON(!valid_dma_direction(direction));
447 447
448 dma_handle = dma_to_phys(dev, dma_handle); 448 dma_handle -= get_dma_offset(dev);
449 449
450 __dma_complete_pa_range(dma_handle, size, direction); 450 __dma_complete_pa_range(dma_handle, size, direction);
451} 451}
@@ -456,7 +456,7 @@ static void tile_pci_dma_sync_single_for_device(struct device *dev,
456 enum dma_data_direction 456 enum dma_data_direction
457 direction) 457 direction)
458{ 458{
459 dma_handle = dma_to_phys(dev, dma_handle); 459 dma_handle -= get_dma_offset(dev);
460 460
461 __dma_prep_pa_range(dma_handle, size, direction); 461 __dma_prep_pa_range(dma_handle, size, direction);
462} 462}
@@ -558,21 +558,43 @@ static struct dma_map_ops pci_swiotlb_dma_ops = {
558 .mapping_error = swiotlb_dma_mapping_error, 558 .mapping_error = swiotlb_dma_mapping_error,
559}; 559};
560 560
561static struct dma_map_ops pci_hybrid_dma_ops = {
562 .alloc = tile_swiotlb_alloc_coherent,
563 .free = tile_swiotlb_free_coherent,
564 .map_page = tile_pci_dma_map_page,
565 .unmap_page = tile_pci_dma_unmap_page,
566 .map_sg = tile_pci_dma_map_sg,
567 .unmap_sg = tile_pci_dma_unmap_sg,
568 .sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu,
569 .sync_single_for_device = tile_pci_dma_sync_single_for_device,
570 .sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu,
571 .sync_sg_for_device = tile_pci_dma_sync_sg_for_device,
572 .mapping_error = tile_pci_dma_mapping_error,
573 .dma_supported = tile_pci_dma_supported
574};
575
561struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops; 576struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops;
577struct dma_map_ops *gx_hybrid_pci_dma_map_ops = &pci_hybrid_dma_ops;
562#else 578#else
563struct dma_map_ops *gx_legacy_pci_dma_map_ops; 579struct dma_map_ops *gx_legacy_pci_dma_map_ops;
580struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
564#endif 581#endif
565EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops); 582EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops);
583EXPORT_SYMBOL(gx_hybrid_pci_dma_map_ops);
566 584
567#ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK 585#ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK
568int dma_set_coherent_mask(struct device *dev, u64 mask) 586int dma_set_coherent_mask(struct device *dev, u64 mask)
569{ 587{
570 struct dma_map_ops *dma_ops = get_dma_ops(dev); 588 struct dma_map_ops *dma_ops = get_dma_ops(dev);
571 589
572 /* Handle legacy PCI devices with limited memory addressability. */ 590 /* Handle hybrid PCI devices with limited memory addressability. */
573 if (((dma_ops == gx_pci_dma_map_ops) || 591 if ((dma_ops == gx_pci_dma_map_ops ||
574 (dma_ops == gx_legacy_pci_dma_map_ops)) && 592 dma_ops == gx_hybrid_pci_dma_map_ops ||
593 dma_ops == gx_legacy_pci_dma_map_ops) &&
575 (mask <= DMA_BIT_MASK(32))) { 594 (mask <= DMA_BIT_MASK(32))) {
595 if (dma_ops == gx_pci_dma_map_ops)
596 set_dma_ops(dev, gx_hybrid_pci_dma_map_ops);
597
576 if (mask > dev->archdata.max_direct_dma_addr) 598 if (mask > dev->archdata.max_direct_dma_addr)
577 mask = dev->archdata.max_direct_dma_addr; 599 mask = dev->archdata.max_direct_dma_addr;
578 } 600 }