diff mbox

[4/4,V2] sparc/leon: Add LEON dma_ops.

Message ID 1294909535-6290-5-git-send-email-kristoffer@gaisler.com
State Changes Requested
Delegated to: David Miller
Headers show

Commit Message

Kristoffer Glembo Jan. 13, 2011, 9:05 a.m. UTC
This patch introduces a dma_ops structure for LEON. It reuses parts of the SBUS and PCI API to avoid code duplication.

Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com>
---
 arch/sparc/kernel/ioport.c |   69 +++++++++++++++++++++++++++++++++++++-------
 1 files changed, 58 insertions(+), 11 deletions(-)

Comments

Sam Ravnborg Jan. 13, 2011, 6:43 p.m. UTC | #1
Hi Kristoffer.

On Thu, Jan 13, 2011 at 10:05:35AM +0100, Kristoffer Glembo wrote:
> This patch introduces a dma_ops structure for LEON. It reuses parts of the SBUS and PCI API to avoid code duplication.
> 
> Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com>
> ---
>  arch/sparc/kernel/ioport.c |   69 +++++++++++++++++++++++++++++++++++++-------
>  1 files changed, 58 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
> index 699120a..466f1dc 100644
> --- a/arch/sparc/kernel/ioport.c
> +++ b/arch/sparc/kernel/ioport.c
> @@ -291,16 +291,22 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len,
>  	/*
>  	 * XXX That's where sdev would be used. Currently we load
>  	 * all iommu tables with the same translations.
> +	 *
> +	 * For LEON we only set up the SRMMU, no IOMMU.
>  	 */
> -	if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
> -		goto err_noiommu;
> -
> +#ifdef CONFIG_SPARC_LEON
> +	sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);
> +	*dma_addrp = virt_to_phys(va);
> +#else
> +	if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) {
> +		release_resource(res);
> +		goto err_nova;
> +	}
> +#endif
>  	res->name = op->dev.of_node->name;
>  
>  	return (void *)(unsigned long)res->start;
>  
> -err_noiommu:
> -	release_resource(res);
>  err_nova:
>  	free_pages(va, order);
>  err_nomem:


I have failed to see what is the difference between pci32_alloc_coherent()
and the LEON variant of sbus_alloc_coherent().

> @@ -336,9 +342,15 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p,
>  	release_resource(res);
>  	kfree(res);
>  
> -	/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
>  	pgv = virt_to_page(p);
> +
> +	/* No IOMMU support for LEON */
> +#ifdef CONFIG_SPARC_LEON
> +	mmu_inval_dma_area((unsigned long)p, n);
> +	sparc_unmapiorange((unsigned long)p, n);
> +#else
>  	mmu_unmap_dma_area(dev, ba, n);
> +#endif
>  
>  	__free_pages(pgv, get_order(n));
>  }

Likewise for this. It looks equal to pci32_free_coherent().

If they are equal then this patch can be simplified a lot.
Please investigate.

> @@ -413,9 +425,6 @@ struct dma_map_ops sbus_dma_ops = {
>  	.sync_sg_for_device	= sbus_sync_sg_for_device,
>  };
>  
> -struct dma_map_ops *dma_ops = &sbus_dma_ops;
> -EXPORT_SYMBOL(dma_ops);
> -
>  static int __init sparc_register_ioport(void)
>  {
>  	register_proc_sparc_ioport();
> @@ -427,7 +436,9 @@ arch_initcall(sparc_register_ioport);
>  
>  #endif /* CONFIG_SBUS */
>  
> -#ifdef CONFIG_PCI
> +
> +/* LEON reuses PCI DMA ops */
> +#if defined(CONFIG_PCI) || defined(CONFIG_SPARC_LEON)
>  
>  /* Allocate and map kernel buffer using consistent mode DMA for a device.
>   * hwdev should be valid struct pci_dev pointer for PCI devices.
> @@ -667,7 +678,43 @@ struct dma_map_ops pci32_dma_ops = {
>  };
>  EXPORT_SYMBOL(pci32_dma_ops);
>  
> -#endif /* CONFIG_PCI */
> +/*
> + * We can only invalidate the whole cache
> + */
> +static void leon_unmap_sg(struct device *dev, struct scatterlist *sgl,
> +			   int nents, enum dma_data_direction dir,
> +			   struct dma_attrs *attrs)
> +{
> +	if (dir != PCI_DMA_TODEVICE)
> +		mmu_inval_dma_area(0, 0);
> +}
Please investigate if you can use pci32_unmap_sg.
If this is the case you can reuse pci32_dma_ops direct.
As you can use pci32_map_sg() I would assume you can also
use the counterpart for unmap..

	Sam
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kristoffer Glembo Jan. 18, 2011, 9:25 a.m. UTC | #2
Hi,


Sam Ravnborg wrote:
> 
> I have failed to see what is the difference between pci32_alloc_coherent()
> and the LEON variant of sbus_alloc_coherent().

Yes the only difference it the setting of the name in the resource. Maybe it does not warrant the messy code.

>  
> Likewise for this. It looks equal to pci32_free_coherent().
> 

Yes this case is actually totally equal.

For me it is no problem using the pci versions. I tried using the sbus versions on advice from Dave but maybe it was not very successful :)


> Please investigate if you can use pci32_unmap_sg.
> If this is the case you can reuse pci32_dma_ops direct.
> As you can use pci32_map_sg() I would assume you can also
> use the counterpart for unmap..
> 

Yes I can remove it. It was pretty unnecessary.


Thanks,
Kristoffer

--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sam Ravnborg Jan. 18, 2011, 10:29 a.m. UTC | #3
On Tue, Jan 18, 2011 at 10:25:24AM +0100, Kristoffer Glembo wrote:
> Hi,
> 
> 
> Sam Ravnborg wrote:
> > 
> > I have failed to see what is the difference between pci32_alloc_coherent()
> > and the LEON variant of sbus_alloc_coherent().
> 
> Yes the only difference it the setting of the name in the resource. Maybe it does not warrant the messy code.
> 
> >  
> > Likewise for this. It looks equal to pci32_free_coherent().
> > 
> 
> Yes this case is actually totally equal.
> 
> For me it is no problem using the pci versions. I tried using the sbus versions on advice from Dave but maybe it was not very successful :)
> 
> 
> > Please investigate if you can use pci32_unmap_sg.
> > If this is the case you can reuse pci32_dma_ops direct.
> > As you can use pci32_map_sg() I would assume you can also
> > use the counterpart for unmap..
> > 
> 
> Yes I can remove it. It was pretty unnecessary.
I look forward for next version.

Note: I review this with only limited knowledge of the DMA stuff etc.
      So you shall (as always) treat the input as such.

	Sam
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 699120a..466f1dc 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -291,16 +291,22 @@  static void *sbus_alloc_coherent(struct device *dev, size_t len,
 	/*
 	 * XXX That's where sdev would be used. Currently we load
 	 * all iommu tables with the same translations.
+	 *
+	 * For LEON we only set up the SRMMU, no IOMMU.
 	 */
-	if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
-		goto err_noiommu;
-
+#ifdef CONFIG_SPARC_LEON
+	sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);
+	*dma_addrp = virt_to_phys(va);
+#else
+	if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) {
+		release_resource(res);
+		goto err_nova;
+	}
+#endif
 	res->name = op->dev.of_node->name;
 
 	return (void *)(unsigned long)res->start;
 
-err_noiommu:
-	release_resource(res);
 err_nova:
 	free_pages(va, order);
 err_nomem:
@@ -336,9 +342,15 @@  static void sbus_free_coherent(struct device *dev, size_t n, void *p,
 	release_resource(res);
 	kfree(res);
 
-	/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
 	pgv = virt_to_page(p);
+
+	/* No IOMMU support for LEON */
+#ifdef CONFIG_SPARC_LEON
+	mmu_inval_dma_area((unsigned long)p, n);
+	sparc_unmapiorange((unsigned long)p, n);
+#else
 	mmu_unmap_dma_area(dev, ba, n);
+#endif
 
 	__free_pages(pgv, get_order(n));
 }
@@ -413,9 +425,6 @@  struct dma_map_ops sbus_dma_ops = {
 	.sync_sg_for_device	= sbus_sync_sg_for_device,
 };
 
-struct dma_map_ops *dma_ops = &sbus_dma_ops;
-EXPORT_SYMBOL(dma_ops);
-
 static int __init sparc_register_ioport(void)
 {
 	register_proc_sparc_ioport();
@@ -427,7 +436,9 @@  arch_initcall(sparc_register_ioport);
 
 #endif /* CONFIG_SBUS */
 
-#ifdef CONFIG_PCI
+
+/* LEON reuses PCI DMA ops */
+#if defined(CONFIG_PCI) || defined(CONFIG_SPARC_LEON)
 
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices.
@@ -667,7 +678,43 @@  struct dma_map_ops pci32_dma_ops = {
 };
 EXPORT_SYMBOL(pci32_dma_ops);
 
-#endif /* CONFIG_PCI */
+/*
+ * We can only invalidate the whole cache
+ */
+static void leon_unmap_sg(struct device *dev, struct scatterlist *sgl,
+			   int nents, enum dma_data_direction dir,
+			   struct dma_attrs *attrs)
+{
+	if (dir != PCI_DMA_TODEVICE)
+		mmu_inval_dma_area(0, 0);
+}
+
+struct dma_map_ops leon_dma_ops = {
+	.alloc_coherent		= sbus_alloc_coherent,
+	.free_coherent		= sbus_free_coherent,
+	.map_page		= pci32_map_page,
+	.unmap_page		= pci32_unmap_page,
+	.map_sg			= pci32_map_sg,
+	.unmap_sg		= leon_unmap_sg,
+	.sync_single_for_cpu	= pci32_sync_single_for_cpu,
+	.sync_single_for_device	= pci32_sync_single_for_device,
+	.sync_sg_for_cpu	= pci32_sync_sg_for_cpu,
+	.sync_sg_for_device	= pci32_sync_sg_for_device,
+};
+
+#endif /* CONFIG_PCI || CONFIG_SPARC_LEON */
+
+#ifdef CONFIG_SBUS
+
+#ifdef CONFIG_SPARC_LEON
+struct dma_map_ops *dma_ops = &leon_dma_ops;
+#else
+struct dma_map_ops *dma_ops = &sbus_dma_ops;
+#endif
+
+EXPORT_SYMBOL(dma_ops);
+
+#endif
 
 /*
  * Return whether the given PCI device DMA address mask can be