Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07f1c295 authored by Russell King's avatar Russell King
Browse files

Merge branch 'dma' of http://git.linaro.org/git/people/nico/linux into devel-stable

parents 4aa96ccf fb89fcfb
Loading
Loading
Loading
Loading
+83 −110
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@ struct dmabounce_device_info {
	struct dmabounce_pool	large;

	rwlock_t lock;

	int (*needs_bounce)(struct device *, dma_addr_t, size_t);
};

#ifdef STATS
@@ -210,90 +212,71 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev,
	if (!dev || !dev->archdata.dmabounce)
		return NULL;
	if (dma_mapping_error(dev, dma_addr)) {
		if (dev)
		dev_err(dev, "Trying to %s invalid mapping\n", where);
		else
			pr_err("unknown device: Trying to %s invalid mapping\n", where);
		return NULL;
	}
	return find_safe_buffer(dev->archdata.dmabounce, dma_addr);
}

static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
		enum dma_data_direction dir)
static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
{
	struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
	dma_addr_t dma_addr;
	int needs_bounce = 0;

	if (device_info)
		DO_STATS ( device_info->map_op_count++ );

	dma_addr = virt_to_dma(dev, ptr);
	if (!dev || !dev->archdata.dmabounce)
		return 0;

	if (dev->dma_mask) {
		unsigned long mask = *dev->dma_mask;
		unsigned long limit;
		unsigned long limit, mask = *dev->dma_mask;

		limit = (mask + 1) & ~mask;
		if (limit && size > limit) {
			dev_err(dev, "DMA mapping too big (requested %#x "
				"mask %#Lx)\n", size, *dev->dma_mask);
			return ~0;
			return -E2BIG;
		}

		/*
		 * Figure out if we need to bounce from the DMA mask.
		 */
		needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask;
		/* Figure out if we need to bounce from the DMA mask. */
		if ((dma_addr | (dma_addr + size - 1)) & ~mask)
			return 1;
	}

	return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size);
}

	if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) {
static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
		enum dma_data_direction dir)
{
	struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
	struct safe_buffer *buf;

	if (device_info)
		DO_STATS ( device_info->map_op_count++ );

	buf = alloc_safe_buffer(device_info, ptr, size, dir);
		if (buf == 0) {
	if (buf == NULL) {
		dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
		       __func__, ptr);
		return ~0;
	}

		dev_dbg(dev,
			"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
		__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
		buf->safe, buf->safe_dma_addr);

		if ((dir == DMA_TO_DEVICE) ||
		    (dir == DMA_BIDIRECTIONAL)) {
	if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
		dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n",
			__func__, ptr, buf->safe, size);
		memcpy(buf->safe, ptr, size);
	}
		ptr = buf->safe;

		dma_addr = buf->safe_dma_addr;
	} else {
		/*
		 * We don't need to sync the DMA buffer since
		 * it was allocated via the coherent allocators.
		 */
		__dma_single_cpu_to_dev(ptr, size, dir);
	}

	return dma_addr;
	return buf->safe_dma_addr;
}

static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
static inline void unmap_single(struct device *dev, struct safe_buffer *buf,
		size_t size, enum dma_data_direction dir)
{
	struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap");

	if (buf) {
	BUG_ON(buf->size != size);
	BUG_ON(buf->direction != dir);

		dev_dbg(dev,
			"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
		__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
		buf->safe, buf->safe_dma_addr);

@@ -302,8 +285,7 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
	if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
		void *ptr = buf->ptr;

			dev_dbg(dev,
				"%s: copy back safe %p to unsafe %p size %d\n",
		dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n",
			__func__, buf->safe, ptr, size);
		memcpy(ptr, buf->safe, size);

@@ -315,9 +297,6 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
		__cpuc_flush_dcache_area(ptr, size);
	}
	free_safe_buffer(dev->archdata.dmabounce, buf);
	} else {
		__dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir);
	}
}

/* ************************************************** */
@@ -328,45 +307,28 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
 * substitute the safe buffer for the unsafe one.
 * (basically move the buffer from an unsafe area to a safe one)
 */
dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size,
		enum dma_data_direction dir)
{
	dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
		__func__, ptr, size, dir);

	BUG_ON(!valid_dma_direction(dir));

	return map_single(dev, ptr, size, dir);
}
EXPORT_SYMBOL(__dma_map_single);

/*
 * see if a mapped address was really a "safe" buffer and if so, copy
 * the data from the safe buffer back to the unsafe buffer and free up
 * the safe buffer.  (basically return things back to the way they
 * should be)
 */
void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
		enum dma_data_direction dir)
{
	dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
		__func__, (void *) dma_addr, size, dir);

	unmap_single(dev, dma_addr, size, dir);
}
EXPORT_SYMBOL(__dma_unmap_single);

dma_addr_t __dma_map_page(struct device *dev, struct page *page,
		unsigned long offset, size_t size, enum dma_data_direction dir)
{
	dma_addr_t dma_addr;
	int ret;

	dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n",
		__func__, page, offset, size, dir);

	BUG_ON(!valid_dma_direction(dir));
	dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset;

	ret = needs_bounce(dev, dma_addr, size);
	if (ret < 0)
		return ~0;

	if (ret == 0) {
		__dma_page_cpu_to_dev(page, offset, size, dir);
		return dma_addr;
	}

	if (PageHighMem(page)) {
		dev_err(dev, "DMA buffer bouncing of HIGHMEM pages "
			     "is not supported\n");
		dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
		return ~0;
	}

@@ -383,10 +345,19 @@ EXPORT_SYMBOL(__dma_map_page);
void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
		enum dma_data_direction dir)
{
	dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
		__func__, (void *) dma_addr, size, dir);
	struct safe_buffer *buf;

	dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n",
		__func__, dma_addr, size, dir);

	buf = find_safe_buffer_dev(dev, dma_addr, __func__);
	if (!buf) {
		__dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)),
			dma_addr & ~PAGE_MASK, size, dir);
		return;
	}

	unmap_single(dev, dma_addr, size, dir);
	unmap_single(dev, buf, size, dir);
}
EXPORT_SYMBOL(__dma_unmap_page);

@@ -461,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev,
}

int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
		unsigned long large_buffer_size)
		unsigned long large_buffer_size,
		int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t))
{
	struct dmabounce_device_info *device_info;
	int ret;
@@ -497,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
	device_info->dev = dev;
	INIT_LIST_HEAD(&device_info->safe_buffers);
	rwlock_init(&device_info->lock);
	device_info->needs_bounce = needs_bounce_fn;

#ifdef STATS
	device_info->total_allocs = 0;
+7 −9
Original line number Diff line number Diff line
@@ -243,6 +243,12 @@ static struct resource it8152_mem = {
 * ITE8152 chip can address up to 64MByte, so all the devices
 * connected to ITE8152 (PCI and USB) should have limited DMA window
 */
static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
{
	dev_dbg(dev, "%s: dma_addr %08x, size %08x\n",
		__func__, dma_addr, size);
	return (dma_addr + size - PHYS_OFFSET) >= SZ_64M;
}

/*
 * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all
@@ -254,7 +260,7 @@ static int it8152_pci_platform_notify(struct device *dev)
		if (dev->dma_mask)
			*dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET;
		dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET;
		dmabounce_register_dev(dev, 2048, 4096);
		dmabounce_register_dev(dev, 2048, 4096, it8152_needs_bounce);
	}
	return 0;
}
@@ -267,14 +273,6 @@ static int it8152_pci_platform_notify_remove(struct device *dev)
	return 0;
}

int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
{
	dev_dbg(dev, "%s: dma_addr %08x, size %08x\n",
		__func__, dma_addr, size);
	return (dev->bus == &pci_bus_type) &&
		((dma_addr + size - PHYS_OFFSET) >= SZ_64M);
}

int dma_set_coherent_mask(struct device *dev, u64 mask)
{
	if (mask >= PHYS_OFFSET + SZ_64M - 1)
+31 −29
Original line number Diff line number Diff line
@@ -579,7 +579,36 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,

	sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2];
}
#endif

#ifdef CONFIG_DMABOUNCE
/*
 * According to the "Intel StrongARM SA-1111 Microprocessor Companion
 * Chip Specification Update" (June 2000), erratum #7, there is a
 * significant bug in the SA1111 SDRAM shared memory controller.  If
 * an access to a region of memory above 1MB relative to the bank base,
 * it is important that address bit 10 _NOT_ be asserted. Depending
 * on the configuration of the RAM, bit 10 may correspond to one
 * of several different (processor-relative) address bits.
 *
 * This routine only identifies whether or not a given DMA address
 * is susceptible to the bug.
 *
 * This should only get called for sa1111_device types due to the
 * way we configure our device dma_masks.
 */
static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
	/*
	 * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
	 * User's Guide" mentions that jumpers R51 and R52 control the
	 * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
	 * SDRAM bank 1 on Neponset). The default configuration selects
	 * Assabet, so any address in bank 1 is necessarily invalid.
	 */
	return (machine_is_assabet() || machine_is_pfs168()) &&
		(addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
}
#endif

static void sa1111_dev_release(struct device *_dev)
@@ -644,7 +673,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
		dev->dev.dma_mask = &dev->dma_mask;

		if (dev->dma_mask != 0xffffffffUL) {
			ret = dmabounce_register_dev(&dev->dev, 1024, 4096);
			ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
					sa1111_needs_bounce);
			if (ret) {
				dev_err(&dev->dev, "SA1111: Failed to register"
					" with dmabounce\n");
@@ -818,34 +848,6 @@ static void __sa1111_remove(struct sa1111 *sachip)
	kfree(sachip);
}

/*
 * According to the "Intel StrongARM SA-1111 Microprocessor Companion
 * Chip Specification Update" (June 2000), erratum #7, there is a
 * significant bug in the SA1111 SDRAM shared memory controller.  If
 * an access to a region of memory above 1MB relative to the bank base,
 * it is important that address bit 10 _NOT_ be asserted. Depending
 * on the configuration of the RAM, bit 10 may correspond to one
 * of several different (processor-relative) address bits.
 *
 * This routine only identifies whether or not a given DMA address
 * is susceptible to the bug.
 *
 * This should only get called for sa1111_device types due to the
 * way we configure our device dma_masks.
 */
int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
	/*
	 * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
	 * User's Guide" mentions that jumpers R51 and R52 control the
	 * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
	 * SDRAM bank 1 on Neponset). The default configuration selects
	 * Assabet, so any address in bank 1 is necessarily invalid.
	 */
	return ((machine_is_assabet() || machine_is_pfs168()) &&
		(addr >= 0xc8000000 || (addr + size) >= 0xc8000000));
}

struct sa1111_save_data {
	unsigned int	skcr;
	unsigned int	skpcr;
+13 −75
Original line number Diff line number Diff line
@@ -115,39 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
		___dma_page_dev_to_cpu(page, off, size, dir);
}

/*
 * Return whether the given device DMA address mask can be supported
 * properly.  For example, if your device can only drive the low 24-bits
 * during bus mastering, then you would pass 0x00ffffff as the mask
 * to this function.
 *
 * FIXME: This should really be a platform specific issue - we should
 * return false if GFP_DMA allocations may not satisfy the supplied 'mask'.
 */
static inline int dma_supported(struct device *dev, u64 mask)
{
	if (mask < ISA_DMA_THRESHOLD)
		return 0;
	return 1;
}

static inline int dma_set_mask(struct device *dev, u64 dma_mask)
{
#ifdef CONFIG_DMABOUNCE
	if (dev->archdata.dmabounce) {
		if (dma_mask >= ISA_DMA_THRESHOLD)
			return 0;
		else
			return -EIO;
	}
#endif
	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
		return -EIO;

	*dev->dma_mask = dma_mask;

	return 0;
}
extern int dma_supported(struct device *, u64);
extern int dma_set_mask(struct device *, u64);

/*
 * DMA errors are defined by all-bits-set in the DMA address.
@@ -256,14 +225,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
 * @dev: valid struct device pointer
 * @small_buf_size: size of buffers to use with small buffer pool
 * @large_buf_size: size of buffers to use with large buffer pool (can be 0)
 * @needs_bounce_fn: called to determine whether buffer needs bouncing
 *
 * This function should be called by low-level platform code to register
 * a device as requireing DMA buffer bouncing. The function will allocate
 * appropriate DMA pools for the device.
 *
 */
extern int dmabounce_register_dev(struct device *, unsigned long,
		unsigned long);
		unsigned long, int (*)(struct device *, dma_addr_t, size_t));

/**
 * dmabounce_unregister_dev
@@ -277,31 +246,9 @@ extern int dmabounce_register_dev(struct device *, unsigned long,
 */
extern void dmabounce_unregister_dev(struct device *);

/**
 * dma_needs_bounce
 *
 * @dev: valid struct device pointer
 * @dma_handle: dma_handle of unbounced buffer
 * @size: size of region being mapped
 *
 * Platforms that utilize the dmabounce mechanism must implement
 * this function.
 *
 * The dmabounce routines call this function whenever a dma-mapping
 * is requested to determine whether a given buffer needs to be bounced
 * or not. The function must return 0 if the buffer is OK for
 * DMA access and 1 if the buffer needs to be bounced.
 *
 */
extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);

/*
 * The DMA API, implemented by dmabounce.c.  See below for descriptions.
 */
extern dma_addr_t __dma_map_single(struct device *, void *, size_t,
		enum dma_data_direction);
extern void __dma_unmap_single(struct device *, dma_addr_t, size_t,
		enum dma_data_direction);
extern dma_addr_t __dma_map_page(struct device *, struct page *,
		unsigned long, size_t, enum dma_data_direction);
extern void __dma_unmap_page(struct device *, dma_addr_t, size_t,
@@ -328,13 +275,6 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr,
}


static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr,
		size_t size, enum dma_data_direction dir)
{
	__dma_single_cpu_to_dev(cpu_addr, size, dir);
	return virt_to_dma(dev, cpu_addr);
}

static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page,
	     unsigned long offset, size_t size, enum dma_data_direction dir)
{
@@ -342,12 +282,6 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page,
	return pfn_to_dma(dev, page_to_pfn(page)) + offset;
}

static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle,
		size_t size, enum dma_data_direction dir)
{
	__dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);
}

static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
		size_t size, enum dma_data_direction dir)
{
@@ -373,14 +307,18 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
		size_t size, enum dma_data_direction dir)
{
	unsigned long offset;
	struct page *page;
	dma_addr_t addr;

	BUG_ON(!virt_addr_valid(cpu_addr));
	BUG_ON(!virt_addr_valid(cpu_addr + size - 1));
	BUG_ON(!valid_dma_direction(dir));

	addr = __dma_map_single(dev, cpu_addr, size, dir);
	debug_dma_map_page(dev, virt_to_page(cpu_addr),
			(unsigned long)cpu_addr & ~PAGE_MASK, size,
			dir, addr, true);
	page = virt_to_page(cpu_addr);
	offset = (unsigned long)cpu_addr & ~PAGE_MASK;
	addr = __dma_map_page(dev, page, offset, size, dir);
	debug_dma_map_page(dev, page, offset, size, dir, addr, true);

	return addr;
}
@@ -430,7 +368,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
		size_t size, enum dma_data_direction dir)
{
	debug_dma_unmap_page(dev, handle, size, dir, true);
	__dma_unmap_single(dev, handle, size, dir);
	__dma_unmap_page(dev, handle, size, dir);
}

/**
+6 −5
Original line number Diff line number Diff line
#ifndef __ASM_ARM_DMA_H
#define __ASM_ARM_DMA_H

#include <asm/memory.h>

/*
 * This is the maximum virtual address which can be DMA'd from.
 */
#ifndef ARM_DMA_ZONE_SIZE
#define MAX_DMA_ADDRESS	0xffffffff
#ifndef CONFIG_ZONE_DMA
#define MAX_DMA_ADDRESS	0xffffffffUL
#else
#define MAX_DMA_ADDRESS	(PAGE_OFFSET + ARM_DMA_ZONE_SIZE)
#define MAX_DMA_ADDRESS	({ \
	extern unsigned long arm_dma_zone_size; \
	arm_dma_zone_size ? \
		(PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; })
#endif

#ifdef CONFIG_ISA_DMA_API
Loading