video: tegra: host: Use dma_map_sg()
Terje Bergstrom [Thu, 25 Jul 2013 05:08:14 +0000 (08:08 +0300)]
Use dma_map_sg_attrs() for mapping in nvhost_memmgr.c. Also remove
touching sg fields. This causes dma_address to be set to only the first
chunk, so gk20a memory management code was adjusted to deal with that.

Also sets maximum dma chunk size to biggest possible number.

Bug 1325300

Change-Id: Icf76e01d6cc5464d98e5907cdefc40cc7ae59d14
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/253308
Reviewed-by: Mandar Padmawar <mpadmawar@nvidia.com>
Tested-by: Mandar Padmawar <mpadmawar@nvidia.com>

drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/gk20a/mm_gk20a.c
drivers/video/tegra/host/nvhost_memmgr.c
include/linux/nvhost.h

index 0e19db3..28e10c3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/hrtimer.h>
 #include <linux/export.h>
 #include <linux/firmware.h>
+#include <linux/dma-mapping.h>
 
 #include <trace/events/nvhost.h>
 
@@ -1460,6 +1461,10 @@ int nvhost_client_device_init(struct platform_device *dev)
        nvhost_syncpt_reset_client(dev);
        nvhost_module_idle(nvhost_master->dev);
 
+       /* Initialize dma parameters */
+       dev->dev.dma_parms = &pdata->dma_parms;
+       dma_set_max_seg_size(&dev->dev, UINT_MAX);
+
        dev_info(&dev->dev, "initialized\n");
 
        if (pdata->slave) {
index a044eda..8845441 100644 (file)
@@ -1193,9 +1193,12 @@ u64 gk20a_mm_iova_addr(struct scatterlist *sgl)
 {
        u64 result = sg_phys(sgl);
 #ifdef CONFIG_TEGRA_IOMMU_SMMU
-       if (sg_dma_address(sgl))
+       if (sg_dma_address(sgl) == DMA_ERROR_CODE)
+               result = 0;
+       else if (sg_dma_address(sgl)) {
                result = sg_dma_address(sgl) |
                        1ULL << NV_MC_SMMU_VADDR_TRANSLATION_BIT;
+       }
 #endif
        return result;
 }
@@ -1236,6 +1239,7 @@ static int update_gmmu_ptes(struct vm_gk20a *vm,
                u32 pte_cur;
                u32 pte_space_page_cur, pte_space_offset_cur;
                u32 pte_space_page_offset;
+               u64 addr = 0;
                void *pte_kv_cur;
 
                struct page_table_gk20a *pte = vm->pdes.ptes[pgsz_idx] + pde_i;
@@ -1275,16 +1279,20 @@ static int update_gmmu_ptes(struct vm_gk20a *vm,
                        }
 
                        if (likely(sgt)) {
-                               u64 addr = gk20a_mm_iova_addr(cur_chunk);
-                               addr += cur_offset;
+                               u64 new_addr = gk20a_mm_iova_addr(cur_chunk);
+                               if (new_addr) {
+                                       addr = new_addr;
+                                       addr += cur_offset;
+                               }
+
 
                                nvhost_dbg(dbg_pte,
                                   "pte_cur=%d addr=0x%08llx kind=%d ctag=%d",
                                   pte_cur, addr, kind_v, ctag);
 
-                               addr >>= gmmu_pte_address_shift_v();
                                pte_w[0] = gmmu_pte_valid_true_f() |
-                                       gmmu_pte_address_sys_f(addr);
+                                       gmmu_pte_address_sys_f(addr
+                                               >> gmmu_pte_address_shift_v());
                                pte_w[1] = gmmu_pte_aperture_video_memory_f() |
                                        gmmu_pte_kind_f(kind_v) |
                                        gmmu_pte_comptagline_f(ctag);
@@ -1296,6 +1304,7 @@ static int update_gmmu_ptes(struct vm_gk20a *vm,
                                        pte_w[1] |= gmmu_pte_vol_true_f();
 
                                cur_offset += 1 << page_shift;
+                               addr += 1 << page_shift;
                                while (cur_chunk &&
                                        cur_offset >= cur_chunk->length) {
                                        cur_offset -= cur_chunk->length;
index eb9b840..5c1f83b 100644 (file)
@@ -410,49 +410,23 @@ void nvhost_memmgr_free_sg_table(struct mem_mgr *mgr,
 int nvhost_memmgr_smmu_map(struct sg_table *sgt, size_t size,
                           struct device *dev)
 {
-       int i;
-       struct scatterlist *sg;
+       int ents;
        DEFINE_DMA_ATTRS(attrs);
-       dma_addr_t addr = dma_iova_alloc(dev, size);
-
-       if (unlikely(sg_dma_address(sgt->sgl) != 0))
-               return 0;
-
-       if (dma_mapping_error(dev, addr))
-               return -ENOMEM;
 
        dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               dma_addr_t da;
-               void *va;
-               sg_dma_address(sg) = addr;
-               sg_dma_len(sg) = sg->length;
-               for (va = phys_to_virt(sg_phys(sg));
-                    va < phys_to_virt(sg_phys(sg)) + sg->length;
-                    va += PAGE_SIZE, addr += PAGE_SIZE) {
-                       da = dma_map_single_at_attrs(dev, va, addr,
-                               PAGE_SIZE, 0, &attrs);
-                       if (dma_mapping_error(dev, da))
-                               /*  TODO: Clean up */
-                               return -EINVAL;
-               }
-       }
+       ents = dma_map_sg_attrs(dev, sgt->sgl, sgt->nents, 0, &attrs);
+       if (!ents)
+               return -EINVAL;
        return 0;
 }
 
 void nvhost_memmgr_smmu_unmap(struct sg_table *sgt, size_t size,
                struct device *dev)
 {
-       int i;
-       struct scatterlist *sg;
        DEFINE_DMA_ATTRS(attrs);
        dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
        /* dma_unmap_sg_attrs will also free the iova */
        dma_unmap_sg_attrs(dev, sgt->sgl, sgt->nents, 0, &attrs);
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               sg_dma_address(sg) = 0;
-               sg_dma_len(sg) = 0;
-       }
 }
 #endif
 
index 31e40a0..629c551 100644 (file)
@@ -154,6 +154,7 @@ struct nvhost_device_data {
        int             id;             /* Separates clients of same hw */
        int             index;          /* Hardware channel number */
        void __iomem    *aperture[NVHOST_MODULE_MAX_IORESOURCE_MEM];
+       struct device_dma_parameters dma_parms;
 
        u32             syncpts[NVHOST_MODULE_MAX_SYNCPTS];
        u32             syncpt_base;    /* Device sync point base */