Re: [PATCH] sparc32: Added LEON dma_ops

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

 



On Wed, Jan 05, 2011 at 05:09:45PM +0100, Daniel Hellstrom wrote:
> From: Kristoffer Glembo <kristoffer@xxxxxxxxxxx>
> 
> Added leon3_dma_ops and mmu_inval_dma_area.

Hi Kristoffer.

This patch mixes cleanup with added functionality.
I would have preferred that you divided this into
several smaller patches.

I am not familiar with the area that your patch touches - but
I have tried to give some feedback below.

	Sam

> ---
>  arch/sparc/include/asm/dma-mapping.h |   13 +---
>  arch/sparc/kernel/ioport.c           |  139 +++++++++++++++++++++++++---------
>  2 files changed, 103 insertions(+), 49 deletions(-)
> 
> diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h
> index 8c0e4f7..fadc653 100644
> --- a/arch/sparc/include/asm/dma-mapping.h
> +++ b/arch/sparc/include/asm/dma-mapping.h
> @@ -51,17 +51,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
>  	return (dma_addr == DMA_ERROR_CODE);
>  }
>  
> -static inline int dma_set_mask(struct device *dev, u64 mask)
> -{
> -#ifdef CONFIG_PCI
> -	if (dev->bus == &pci_bus_type) {
> -		if (!dev->dma_mask || !dma_supported(dev, mask))
> -			return -EINVAL;
> -		*dev->dma_mask = mask;
> -		return 0;
> -	}
> -#endif
> -	return -EINVAL;
> -}
> +extern int dma_set_mask(struct device *dev, u64 dma_mask);

So dma_set_mask() is moved to ioport.c
>  
> +int dma_set_mask(struct device *dev, u64 dma_mask)
> +{
> +#ifdef CONFIG_PCI
> +	if (dev->bus == &pci_bus_type)
> +		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
> +#endif
> +	return -EOPNOTSUPP;
> +}
> +EXPORT_SYMBOL(dma_set_mask);

And it is now an exported symbol - looks OK.
But the new implementation differs from the old implementation.

Grepping for pci_set_dma_mask() turned up this implmentation:
static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
{
        return dma_set_mask(&dev->dev, mask);
}

It looks like an infinite loop??


Note: This change alone warrant an independent patch.

>  #endif
> diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
> index 41f7e4e..7359369 100644
> --- a/arch/sparc/kernel/ioport.c
> +++ b/arch/sparc/kernel/ioport.c
> @@ -50,10 +50,15 @@
>  #include <asm/io-unit.h>
>  #include <asm/leon.h>
>  
> -#ifdef CONFIG_SPARC_LEON
> -#define mmu_inval_dma_area(p, l) leon_flush_dcache_all()
> -#else
> +#ifndef CONFIG_SPARC_LEON
>  #define mmu_inval_dma_area(p, l)	/* Anton pulled it out for 2.4.0-xx */
> +#else
> +static inline void mmu_inval_dma_area(unsigned long va, unsigned long len)
> +{
> +	if (!sparc_leon3_snooping_enabled()) {
> +		leon_flush_dcache_all();
> +	}
> +}
>  #endif
This is better than before as we no longer has a double definition.
But why do we call mmu_inval_dma_area() wich is empty in SPARC32 build
from SBUS code? LEON does not support SBUS only AMBA + PCI IIRC.
Hmm - looking at Kconfig LEON supports SBUS too. Is that correct?

>  
>  static struct resource *_sparc_find_resource(struct resource *r,
> @@ -254,7 +259,7 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len,
>  				 dma_addr_t *dma_addrp, gfp_t gfp)
>  {
>  	struct platform_device *op = to_platform_device(dev);
> -	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
> +	unsigned long len_total = PAGE_ALIGN(len);
PAGE_ALIGN is much better than the old version.
But again - please do such cleanup in a separate step.
If we are going to revert your functional change we do not
want to lose such cleanups.


>  	unsigned long va;
>  	struct resource *res;
>  	int order;
> @@ -287,15 +292,19 @@ 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.
>  	 */
> -	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


I cannot follow why you need this ugly ifdef here.
Some comments please.

>  	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:
> @@ -321,7 +330,7 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p,
>  		return;
>  	}
>  
> -	n = (n + PAGE_SIZE-1) & PAGE_MASK;
> +	n = PAGE_ALIGN(n);
Another patch..

>  	if ((res->end-res->start)+1 != n) {
>  		printk("sbus_free_consistent: region 0x%lx asked 0x%zx\n",
>  		    (long)((res->end-res->start)+1), n);
> @@ -333,7 +342,12 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p,
>  
>  	/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
>  	pgv = virt_to_page(p);
> +
> +#ifdef CONFIG_SPARC_LEON
> +	sparc_unmapiorange((unsigned long)p, n);
> +#else
>  	mmu_unmap_dma_area(dev, ba, n);
> +#endif
Why? comemnts needed again.
Or better find another way to do this.

Looking a bit around...
Is it correct understood that BTFIXUPSET_CALL() is used
to patch in another function here for for example sun4c?
So mmu_unmap_dma_area() becomes a call to sun4c_unmap_dma_area()?


>  
>  	__free_pages(pgv, get_order(n));
>  }
> @@ -408,9 +422,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();
> @@ -422,7 +433,7 @@ arch_initcall(sparc_register_ioport);
>  
>  #endif /* CONFIG_SBUS */
>  
> -#ifdef CONFIG_PCI
> +#if defined(CONFIG_PCI) || defined(CONFIG_SPARC_LEON)

Why do we need PCI functions when PCI is not defined?
>  
>  /* Allocate and map kernel buffer using consistent mode DMA for a device.
>   * hwdev should be valid struct pci_dev pointer for PCI devices.
> @@ -430,7 +441,7 @@ arch_initcall(sparc_register_ioport);
>  static void *pci32_alloc_coherent(struct device *dev, size_t len,
>  				  dma_addr_t *pba, gfp_t gfp)
>  {
> -	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
> +	unsigned long len_total = PAGE_ALIGN(len);
>  	unsigned long va;
>  	struct resource *res;
>  	int order;
> @@ -463,10 +474,6 @@ static void *pci32_alloc_coherent(struct device *dev, size_t len,
>  		return NULL;
>  	}
>  	mmu_inval_dma_area(va, len_total);
> -#if 0
> -/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %lx\n",
> -  (long)va, (long)res->start, (long)virt_to_phys(va), len_total);
> -#endif
unrealted cleanup...

>  	sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);
>  
>  	*pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */
> @@ -498,7 +505,7 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p,
>  		return;
>  	}
>  
> -	n = (n + PAGE_SIZE-1) & PAGE_MASK;
> +	n = PAGE_ALIGN(n);
Another patch.

>  	if ((res->end-res->start)+1 != n) {
>  		printk("pci_free_consistent: region 0x%lx asked 0x%lx\n",
>  		    (long)((res->end-res->start)+1), (long)n);
> @@ -515,6 +522,15 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p,
>  	free_pages(pgp, get_order(n));
>  }
>  
> +static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
> +			     enum dma_data_direction dir,
> +			     struct dma_attrs *attrs)
> +{
> +	if (dir != PCI_DMA_TODEVICE)
> +		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
> +				   PAGE_ALIGN(size));
> +}
Looks like ordinary SPARC32 gained an unmap_page - correct?
Looks like a separate chage to me.

> +
>  /*
>   * Same as pci_map_single, but with pages.
>   */
> @@ -551,8 +567,7 @@ static int pci32_map_sg(struct device *device, struct scatterlist *sgl,
>  
>  	/* IIep is write-through, not flushing. */
>  	for_each_sg(sgl, sg, nents, n) {
> -		BUG_ON(page_address(sg_page(sg)) == NULL);
Why is this BUG_ON() removed?

> -		sg->dma_address = virt_to_phys(sg_virt(sg));
> +		sg->dma_address = sg_phys(sg);

Why - is this better or what?

>  		sg->dma_length = sg->length;
>  	}
>  	return nents;
> @@ -571,10 +586,8 @@ static void pci32_unmap_sg(struct device *dev, struct scatterlist *sgl,
>  
>  	if (dir != PCI_DMA_TODEVICE) {
>  		for_each_sg(sgl, sg, nents, n) {
> -			BUG_ON(page_address(sg_page(sg)) == NULL);
> -			mmu_inval_dma_area(
> -			    (unsigned long) page_address(sg_page(sg)),
> -			    (sg->length + PAGE_SIZE-1) & PAGE_MASK);
> +			mmu_inval_dma_area((unsigned long)sg_virt(sg),
> +					   PAGE_ALIGN(sg->length));
>  		}

Partly same type of comments like above.


>  	}
>  }
> @@ -594,7 +607,7 @@ static void pci32_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
>  {
>  	if (dir != PCI_DMA_TODEVICE) {
>  		mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
> -		    (size + PAGE_SIZE-1) & PAGE_MASK);
> +				   PAGE_ALIGN(size));
Another patch...
Same goes for additional spots in this file - I did not comment these.

> +/* LEON3 unmapping functions
> + *
> + * We can only invalidate the whole cache so unmap_page and unmap_sg do the
> + * same thing
> + */
> +static void leon3_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
> +			     enum dma_data_direction dir,
> +			     struct dma_attrs *attrs)
> +{
> +	if (dir != PCI_DMA_TODEVICE)
> +		mmu_inval_dma_area(0, 0);
> +}
> +
> +static void leon3_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 pci32_dma_ops = {
>  	.alloc_coherent		= pci32_alloc_coherent,
>  	.free_coherent		= pci32_free_coherent,
>  	.map_page		= pci32_map_page,
> +	.unmap_page		= pci32_unmap_page,
>  	.map_sg			= pci32_map_sg,
>  	.unmap_sg		= pci32_unmap_sg,
>  	.sync_single_for_cpu	= pci32_sync_single_for_cpu,
> @@ -658,7 +689,30 @@ struct dma_map_ops pci32_dma_ops = {
>  };
>  EXPORT_SYMBOL(pci32_dma_ops);
>  
> -#endif /* CONFIG_PCI */
> +struct dma_map_ops leon3_dma_ops = {
> +	.alloc_coherent		= sbus_alloc_coherent,
> +	.free_coherent		= sbus_free_coherent,
> +	.map_page		= pci32_map_page,
> +	.unmap_page		= leon3_unmap_page,
> +	.map_sg			= pci32_map_sg,
> +	.unmap_sg		= leon3_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_SPARC_LEON
> +struct dma_map_ops *dma_ops = &leon3_dma_ops;
> +#else
> +struct dma_map_ops *dma_ops = &sbus_dma_ops;
> +#endif
> +
> +#ifdef CONFIG_SBUS
> +EXPORT_SYMBOL(dma_ops);
> +#endif

This just looks wrong to me...
Why we need to export only is SBUS is defined - but
we define leon3_dma_ops if LEON is defined.

I think this need to be revisited - and then see if you
can hide more of the ifdef in dma-mapping.h


>  
>  /*
>   * Return whether the given PCI device DMA address mask can be
> @@ -676,6 +730,17 @@ int dma_supported(struct device *dev, u64 mask)
>  }
>  EXPORT_SYMBOL(dma_supported);
>  
> +int dma_set_mask(struct device *dev, u64 dma_mask)
> +{
> +#ifdef CONFIG_PCI
> +	if (dev->bus == &pci_bus_type)
> +		return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
> +#endif
> +	return -EOPNOTSUPP;
> +}
> +EXPORT_SYMBOL(dma_set_mask);
> +
> +
>  #ifdef CONFIG_PROC_FS
>  
>  static int sparc_io_proc_show(struct seq_file *m, void *v)
> @@ -717,7 +782,7 @@ static const struct file_operations sparc_io_proc_fops = {
>  static struct resource *_sparc_find_resource(struct resource *root,
>  					     unsigned long hit)
>  {
> -        struct resource *tmp;
> +	struct resource *tmp;

Minor nit but unrelated change.

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


[Index of Archives]     [Kernel Development]     [DCCP]     [Linux ARM Development]     [Linux]     [Photo]     [Yosemite Help]     [Linux ARM Kernel]     [Linux SCSI]     [Linux x86_64]     [Linux Hams]

  Powered by Linux