[PATCH v4 3/6] staging: tidspbridge: mapping support when SG_CHAIN is not defined

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If ARCH_HAS_SG_CHAIN is not defined a scatter-gather table can hold a
fixed number of entries, otherwise it results in a panic when
allocating bigger tables.

Use generic allocator to manage the mapped memory in such cases and
ignore iovmm functions.

Signed-off-by: Fernando Guzman Lugo <x0095840@xxxxxx>
Signed-off-by: Omar Ramirez Luna <omar.ramirez@xxxxxx>
---
 drivers/staging/tidspbridge/Kconfig                |    1 +
 drivers/staging/tidspbridge/core/tiomap3430.c      |   94 +++++++++++++++++++-
 .../tidspbridge/include/dspbridge/dspdefs.h        |    3 +-
 drivers/staging/tidspbridge/rmgr/proc.c            |    3 +-
 4 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig
index 19b1b76..7a9d539 100644
--- a/drivers/staging/tidspbridge/Kconfig
+++ b/drivers/staging/tidspbridge/Kconfig
@@ -8,6 +8,7 @@ menuconfig TIDSPBRIDGE
 	select OMAP_MBOX_FWK
 	select OMAP_IOMMU
 	select OMAP_IOMMU_IVA2
+	select GENERIC_ALLOCATOR
 	help
 	  DSP/BIOS Bridge is designed for platforms that contain a GPP and
 	  one or more attached DSPs.  The GPP is considered the master or
diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c
index 1ca50d9..692a456 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430.c
@@ -23,6 +23,7 @@
 #include <dspbridge/host_os.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
+#include <linux/genalloc.h>
 
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
@@ -114,7 +115,8 @@ static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctxt,
 				  u32 ul_mpu_addr, u32 virt_addr,
 				  u32 ul_num_bytes, struct page **mapped_pages);
 static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctxt,
-				     u32 da);
+				     u32 da, size_t size,
+				     struct page **usr_pgs);
 static int bridge_dev_create(struct bridge_dev_context
 					**dev_cntxt,
 					struct dev_object *hdev_obj,
@@ -229,6 +231,27 @@ static struct notifier_block dsp_mbox_notifier = {
 	.notifier_call = io_mbox_msg,
 };
 
+#ifndef ARCH_HAS_SG_CHAIN
+static struct gen_pool *dmm_pool;
+
+static inline u32 dsptlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
+								u32 pgsz)
+{
+	memset(e, 0, sizeof(*e));
+
+	e->da		= da;
+	e->pa		= pa;
+	e->valid	= 1;
+	e->pgsz		= MMU_CAM_PGSZ_4K;
+	e->pgsz		= pgsz & MMU_CAM_PGSZ_MASK;
+	e->endian	= MMU_RAM_ENDIAN_LITTLE;
+	e->elsz		= MMU_RAM_ELSZ_32;
+	e->mixed	= 0;
+
+	return iopgsz_to_bytes(e->pgsz);
+}
+#endif /* !ARCH_HAS_SG_CHAIN */
+
 static inline void flush_all(struct bridge_dev_context *dev_context)
 {
 	if (dev_context->brd_state == BRD_DSP_HIBERNATION ||
@@ -463,6 +486,27 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
 		dev_context->dsp_mmu = NULL;
 		return PTR_ERR(mmu);
 	}
+#ifndef ARCH_HAS_SG_CHAIN
+	else {
+		u32 start;
+
+		if (dmm_pool) {
+			gen_pool_destroy(dmm_pool);
+			dmm_pool = NULL;
+		}
+
+		dmm_pool = gen_pool_create(PAGE_SHIFT, -1);
+		if (!dmm_pool) {
+			iommu_put(mmu);
+			dev_context->dsp_mmu = NULL;
+			return -ENOMEM;
+		}
+
+		sm_sg = &dev_context->sh_s;
+		start = sm_sg->seg1_da + sm_sg->seg1_size;
+		gen_pool_add(dmm_pool, start, CONFIG_TIDSPBRIDGE_DMM_SIZE, -1);
+	}
+#endif
 
 	dev_context->dsp_mmu = mmu;
 	mmu->isr = mmu_fault_isr;
@@ -741,6 +785,12 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
 		iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg0_da);
 		iommu_put(dev_context->dsp_mmu);
 		dev_context->dsp_mmu = NULL;
+#ifndef ARCH_HAS_SG_CHAIN
+		if (dmm_pool) {
+			gen_pool_destroy(dmm_pool);
+			dmm_pool = NULL;
+		}
+#endif
 	}
 
 	/* Reset IVA IOMMU */
@@ -1194,8 +1244,13 @@ static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctx,
 	struct iommu *mmu = dev_ctx->dsp_mmu;
 	struct vm_area_struct *vma;
 	struct mm_struct *mm = current->mm;
+#ifndef ARCH_HAS_SG_CHAIN
+	u32 pa, addr;
+	struct iotlb_entry e;
+#else
 	struct sg_table *sgt;
 	struct scatterlist *sg;
+#endif
 
 	if (!size || !usr_pgs)
 		return -EINVAL;
@@ -1231,6 +1286,23 @@ static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctx,
 		goto err_pages;
 	}
 
+#ifndef ARCH_HAS_SG_CHAIN
+	da = gen_pool_alloc(dmm_pool, size);
+	if (!da) {
+		res = -ENOMEM;
+		goto err_pages;
+	}
+
+	wake_dsp(dev_ctx, NULL);
+
+	for (i = 0, addr = da; i < pages; i++, addr += PAGE_SIZE) {
+		pa = page_to_phys(usr_pgs[i]);
+		dsptlb_init_entry(&e, addr, pa, MMU_CAM_PGSZ_4K);
+		iopgtable_store_entry(mmu, &e);
+	}
+
+	return da;
+#else
 	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
 	if (!sgt) {
 		res = -ENOMEM;
@@ -1257,6 +1329,7 @@ static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctx,
 err_sg:
 	kfree(sgt);
 	i = pages;
+#endif /* ARCH_HAS_SG_CHAIN */
 err_pages:
 	while (i--)
 		put_page(usr_pgs[i]);
@@ -1271,9 +1344,23 @@ err_pages:
  *      So, instead of looking up the PTE address for every 4K block,
  *      we clear consecutive PTEs until we unmap all the bytes
  */
-static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctx, u32 da)
+static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctx, u32 da,
+				 size_t size, struct page **usr_pgs)
 {
-	unsigned i;
+	unsigned i = 0;
+#ifndef ARCH_HAS_SG_CHAIN
+	gen_pool_free(dmm_pool, da, size);
+
+	wake_dsp(dev_ctx, NULL);
+
+	while (size > 0) {
+		size_t bytes;
+		bytes = iopgtable_clear_entry(dev_ctx->dsp_mmu, da);
+		size -= bytes;
+		da += bytes;
+		put_page(usr_pgs[i++]);
+	}
+#else
 	struct sg_table *sgt;
 	struct scatterlist *sg;
 
@@ -1288,6 +1375,7 @@ static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctx, u32 da)
 
 	sg_free_table(sgt);
 	kfree(sgt);
+#endif /* ARCH_HAS_SG_CHAIN */
 
 	return 0;
 }
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
index 48f91c9..e052bba 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
@@ -194,7 +194,8 @@ typedef int(*fxn_brd_memmap) (struct bridge_dev_context
  */
 typedef int(*fxn_brd_memunmap) (struct bridge_dev_context
 				       * dev_ctxt,
-				       u32 da);
+				       u32 da, size_t size,
+				       struct page **usr_pgs);
 
 /*
  *  ======== bridge_brd_stop ========
diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c
index 9049df8..ce57279 100644
--- a/drivers/staging/tidspbridge/rmgr/proc.c
+++ b/drivers/staging/tidspbridge/rmgr/proc.c
@@ -1731,7 +1731,8 @@ int proc_un_map(void *hprocessor, void *map_addr,
 
 	/* Remove mapping from the page tables. */
 	status = (*p_proc_object->intf_fxns->brd_mem_un_map)
-			(p_proc_object->bridge_context, va_align);
+			(p_proc_object->bridge_context, va_align, dmo->size,
+			 dmo->pages);
 	if (status)
 		goto unmap_failed;
 
-- 
1.7.1

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux