public inbox for linuxppc-dev@ozlabs.org 
 help / color / mirror / Atom feed
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle•com>
To: Albert Herranz <albert_herranz@yahoo•es>
Cc: iommu@lists•linux-foundation.org, linux-usb@vger•kernel.org,
	linuxppc-dev@lists•ozlabs.org
Subject: Re: [PATCH v5 08/10] wii: add mem2 dma mapping ops
Date: Fri, 19 Mar 2010 15:50:13 -0400	[thread overview]
Message-ID: <20100319195013.GC31908@phenom.dumpdata.com> (raw)
In-Reply-To: <1269023546-25534-9-git-send-email-albert_herranz@yahoo.es>

> +int wii_set_mem2_dma_constraints(struct device *dev)
> +{
> +	struct dev_archdata *sd;
> +
> +	sd = &dev->archdata;
> +	sd->max_direct_dma_addr = 0;
> +	sd->min_direct_dma_addr = wii_hole_start + wii_hole_size;
> +
> +	set_dma_ops(dev, &wii_mem2_dma_ops);
> +	return 0;
> +}
> +EXPORT_SYMBOL(wii_set_mem2_dma_constraints);

Can you make them EXPORT_SYMBOL_GPL?
> +
> +/**
> + * wii_clear_mem2_dma_constraints() - clears device MEM2 DMA constraints
> + * @dev:	device for which DMA constraints are cleared
> + *
> + * Instructs device @dev to stop using MEM2 DMA buffers for DMA transfers.
> + * Must be called to undo wii_set_mem2_dma_constraints().
> + */
> +void wii_clear_mem2_dma_constraints(struct device *dev)
> +{
> +	struct dev_archdata *sd;
> +
> +	sd = &dev->archdata;
> +	sd->max_direct_dma_addr = 0;
> +	sd->min_direct_dma_addr = 0;
> +
> +	set_dma_ops(dev, &dma_direct_ops);
> +}
> +EXPORT_SYMBOL(wii_clear_mem2_dma_constraints);

Ditto..
> +
> +/*
> + * swiotlb-based DMA ops for MEM2-only devices on the Wii.
> + *
> + */
> +
> +/*
> + * Allocate the SWIOTLB from MEM2.
> + */
> +void * __init swiotlb_alloc_boot(size_t size, unsigned long nslabs)
> +{
> +	return __alloc_bootmem_low(size, PAGE_SIZE,
> +				   wii_hole_start + wii_hole_size);
> +}
> +
> +/*
> + * Bounce: copy the swiotlb buffer back to the original dma location
> + * This is a platform specific version replacing the generic __weak version.
> + */
> +void swiotlb_bounce(phys_addr_t phys, char *dma_buf, size_t size,
> +		    enum dma_data_direction dir)
> +{
> +	void *vaddr = phys_to_virt(phys);
> +
> +	if (dir == DMA_TO_DEVICE) {
> +		memcpy(dma_buf, vaddr, size);
> +		__dma_sync(dma_buf, size, dir);
> +	} else {
> +		__dma_sync(dma_buf, size, dir);
> +		memcpy(vaddr, dma_buf, size);
> +	}
> +}
> +
> +static dma_addr_t
> +mem2_virt_to_bus(struct device *dev, void *address)
> +{
> +	return phys_to_dma(dev, virt_to_phys(address));
> +}
> +
> +static int
> +mem2_dma_mapping_error(struct device *dev, dma_addr_t dma_handle)
> +{
> +	return dma_handle == mem2_virt_to_bus(dev, swiotlb_bk_overflow_buffer);
> +}
> +
> +static int
> +mem2_dma_supported(struct device *dev, u64 mask)
> +{
> +	return mem2_virt_to_bus(dev, swiotlb_bk_end - 1) <= mask;
> +}
> +
> +/*
> + * Determines if a given DMA region specified by @dma_handle
> + * requires bouncing.
> + *
> + * Bouncing is required if the DMA region falls within MEM1.
> + */
> +static int mem2_needs_dmabounce(dma_addr_t dma_handle)
> +{
> +	return dma_handle < wii_hole_start;
> +}
> +
> +/*
> + * Use the dma_direct_ops hooks for allocating and freeing coherent memory
> + * from the MEM2 DMA region.
> + */
> +
> +static void *mem2_alloc_coherent(struct device *dev, size_t size,
> +				 dma_addr_t *dma_handle, gfp_t gfp)
> +{
> +	void *vaddr;
> +
> +	vaddr = dma_direct_ops.alloc_coherent(wii_mem2_dma_dev(), size,
> +					      dma_handle, gfp);
> +	if (vaddr && mem2_needs_dmabounce(*dma_handle)) {
> +		dma_direct_ops.free_coherent(wii_mem2_dma_dev(), size, vaddr,
> +					     *dma_handle);
> +		dev_err(dev, "failed to allocate MEM2 coherent memory\n");
> +		vaddr = NULL;
> +	}
> +	return vaddr;
> +}
> +
> +static void mem2_free_coherent(struct device *dev, size_t size,
> +			       void *vaddr, dma_addr_t dma_handle)
> +{
> +	dma_direct_ops.free_coherent(wii_mem2_dma_dev(), size, vaddr,
> +				     dma_handle);
> +}
> +
> +/*
> + * Maps (part of) a page so it can be safely accessed by a device.
> + *
> + * Calls the corresponding dma_direct_ops hook if the page region falls
> + * within MEM2.
> + * Otherwise, a bounce buffer allocated from MEM2 coherent memory is used.
> + */
> +static dma_addr_t
> +mem2_map_page(struct device *dev, struct page *page, unsigned long offset,
> +	      size_t size, enum dma_data_direction dir,
> +	      struct dma_attrs *attrs)
> +{
> +	phys_addr_t phys = page_to_phys(page) + offset;
> +	dma_addr_t dma_handle = phys_to_dma(dev, phys);
> +	dma_addr_t swiotlb_start_dma;
> +	void *map;
> +
> +	BUG_ON(dir == DMA_NONE);
> +
> +	if (dma_capable(dev, dma_handle, size) && !swiotlb_force) {
> +		return dma_direct_ops.map_page(dev, page, offset, size,
> +					       dir, attrs);
> +	}
> +
> +	swiotlb_start_dma = mem2_virt_to_bus(dev, swiotlb_bk_start);
> +	map = swiotlb_bk_map_single(dev, phys, swiotlb_start_dma, size, dir);
> +	if (!map) {
> +		swiotlb_full(dev, size, dir, 1);
> +		map = swiotlb_bk_overflow_buffer;
> +	}
> +
> +	dma_handle = mem2_virt_to_bus(dev, map);
> +	BUG_ON(!dma_capable(dev, dma_handle, size));
> +
> +	return dma_handle;
> +}
> +
> +/*
> + * Unmaps (part of) a page previously mapped.
> + *
> + * Calls the corresponding dma_direct_ops hook if the DMA region associated
> + * to the dma handle @dma_handle wasn't bounced.
> + * Otherwise, the associated bounce buffer is de-bounced.
> + */
> +static void
> +mem2_unmap_page(struct device *dev, dma_addr_t dma_handle, size_t size,
> +		enum dma_data_direction dir, struct dma_attrs *attrs)
> +{
> +	swiotlb_unmap_page(dev, dma_handle, size, dir, attrs);
> +}
> +
> +/*
> + * Unmaps a scatter/gather list by unmapping each entry.
> + */
> +static void
> +mem2_unmap_sg(struct device *dev, struct scatterlist *sgl, int nents,
> +	      enum dma_data_direction dir, struct dma_attrs *attrs)
> +{
> +	struct scatterlist *sg;
> +	int i;
> +
> +	for_each_sg(sgl, sg, nents, i)
> +		mem2_unmap_page(dev, sg->dma_address, sg->length, dir, attrs);
> +}
> +
> +/*
> + * Maps a scatter/gather list by mapping each entry.
> + */
> +static int
> +mem2_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
> +	    enum dma_data_direction dir, struct dma_attrs *attrs)
> +{
> +	struct scatterlist *sg;
> +	int i;
> +
> +	for_each_sg(sgl, sg, nents, i) {
> +		sg->dma_length = sg->length;
> +		sg->dma_address = mem2_map_page(dev, sg_page(sg), sg->offset,
> +						sg->length, dir, attrs);
> +		if (mem2_dma_mapping_error(dev, sg->dma_address)) {
> +			mem2_unmap_sg(dev, sgl, i, dir, attrs);
> +			nents = 0;
> +			sgl[nents].dma_length = 0;
> +			pr_debug("%s: mem2_map_page error\n", __func__);

Maybe use 'dev_err(dev," mem2..." ?

> +			break;
> +		}
> +	}
> +	return nents;
> +}
> +
> +/*
> + * The sync functions synchronize streaming mode DMA translations
> + * making physical memory consistent before/after a DMA transfer.
> + *
> + * They call the corresponding dma_direct_ops hook if the DMA region
> + * associated to the dma handle @dma_handle wasn't bounced.
> + * Otherwise, original DMA buffers and their matching bounce buffers are put
> + * in sync.
> + */
> +
> +static int
> +mem2_sync_range(struct device *dev, dma_addr_t dma_handle,
> +		unsigned long offset, size_t size, int dir, int target)
> +{
> +	phys_addr_t paddr = dma_to_phys(dev, dma_handle) + offset;
> +	void *vaddr = phys_to_virt(paddr);
> +
> +	BUG_ON(dir == DMA_NONE);
> +
> +	if (is_swiotlb_buffer(paddr)) {
> +		swiotlb_bk_sync_single(dev, vaddr, size, dir, target);
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +static void
> +mem2_sync_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
> +			unsigned long offset, size_t size,
> +			enum dma_data_direction dir)
> +{
> +	int done = mem2_sync_range(dev, dma_handle, offset, size, dir,
> +				   SYNC_FOR_CPU);
> +	if (!done) {
> +		dma_direct_ops.sync_single_range_for_cpu(dev, dma_handle,
> +							 offset, size, dir);
> +	}
> +}
> +
> +static void
> +mem2_sync_range_for_device(struct device *dev, dma_addr_t dma_handle,
> +			   unsigned long offset, size_t size,
> +			   enum dma_data_direction dir)
> +{
> +	int done = mem2_sync_range(dev, dma_handle, offset, size, dir,
> +				   SYNC_FOR_DEVICE);
> +	if (!done) {
> +		dma_direct_ops.sync_single_range_for_device(dev, dma_handle,
> +							    offset, size, dir);
> +	}
> +}
> +
> +static void
> +mem2_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nents,
> +		     enum dma_data_direction dir)
> +{
> +	struct scatterlist *sg;
> +	int i;
> +
> +	for_each_sg(sgl, sg, nents, i) {
> +		mem2_sync_range_for_cpu(dev, sg_dma_address(sg), sg->offset,
> +					sg_dma_len(sg), dir);
> +	}
> +}
> +
> +static void
> +mem2_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nents,
> +			enum dma_data_direction dir)
> +{
> +	struct scatterlist *sg;
> +	int i;
> +
> +	for_each_sg(sgl, sg, nents, i) {
> +		mem2_sync_range_for_device(dev, sg_dma_address(sg), sg->offset,
> +					   sg_dma_len(sg), dir);
> +	}
> +}
> +
> +/*
> + * Set of DMA operations for devices requiring MEM2 DMA buffers.
> + */
> +struct dma_map_ops wii_mem2_dma_ops = {
> +	.alloc_coherent = mem2_alloc_coherent,
> +	.free_coherent = mem2_free_coherent,
> +	.map_sg = mem2_map_sg,
> +	.unmap_sg = mem2_unmap_sg,
> +	.dma_supported = mem2_dma_supported,
> +	.map_page = mem2_map_page,
> +	.unmap_page = mem2_unmap_page,
> +	.sync_single_range_for_cpu = mem2_sync_range_for_cpu,
> +	.sync_single_range_for_device = mem2_sync_range_for_device,
> +	.sync_sg_for_cpu = mem2_sync_sg_for_cpu,
> +	.sync_sg_for_device = mem2_sync_sg_for_device,
> +	.mapping_error = mem2_dma_mapping_error,
> +};
> -- 
> 1.6.3.3
> 
> _______________________________________________
> iommu mailing list
> iommu@lists•linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/iommu

  reply	other threads:[~2010-03-19 20:20 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-03-19 18:32 [PATCH v5 00/10] wii: add usb 2.0 support Albert Herranz
2010-03-19 18:32 ` [PATCH v5 01/10] swiotbl: add back swiotlb_alloc_boot() Albert Herranz
2010-03-19 18:32 ` [PATCH v5 02/10] swiotlb: make swiotlb_bounce() __weak Albert Herranz
2010-03-19 18:32 ` [PATCH v5 03/10] powerpc: add per-device dma coherent support Albert Herranz
2010-03-19 18:32 ` [PATCH v5 04/10] powerpc: add min_direct_dma_addr Albert Herranz
2010-03-19 18:32 ` [PATCH v5 05/10] USB: refactor unmap_urb_for_dma/map_urb_for_dma Albert Herranz
2010-03-19 18:32 ` [PATCH v5 06/10] USB: add HCD_NO_COHERENT_MEM host controller driver flag Albert Herranz
2010-03-19 18:32 ` [PATCH v5 07/10] wii: have generic dma coherent Albert Herranz
2010-03-19 18:32 ` [PATCH v5 08/10] wii: add mem2 dma mapping ops Albert Herranz
2010-03-19 19:50   ` Konrad Rzeszutek Wilk [this message]
2010-03-20  0:59     ` Albert Herranz
2010-03-19 19:51   ` Konrad Rzeszutek Wilk
2010-03-20  0:58     ` Albert Herranz
2010-03-19 18:32 ` [PATCH v5 09/10] wii: enable swiotlb Albert Herranz
2010-03-19 18:32 ` [PATCH v5 10/10] wii: hollywood ehci controller support Albert Herranz
2010-03-19 19:01 ` [PATCH v5 00/10] wii: add usb 2.0 support Alan Stern
2010-03-19 19:13   ` Albert Herranz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100319195013.GC31908@phenom.dumpdata.com \
    --to=konrad.wilk@oracle$(echo .)com \
    --cc=albert_herranz@yahoo$(echo .)es \
    --cc=iommu@lists$(echo .)linux-foundation.org \
    --cc=linux-usb@vger$(echo .)kernel.org \
    --cc=linuxppc-dev@lists$(echo .)ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox