[kernel] r9818 - in dists/sid/linux-2.6/debian: . config/arm patches/bugfix/arm patches/series

Martin Michlmayr tbm at alioth.debian.org
Wed Nov 28 09:59:48 UTC 2007


Author: tbm
Date: Wed Nov 28 09:59:48 2007
New Revision: 9818

Log:
Backport and enable POLLED_DMA_COPY_USER. (closes: #444271)


Added:
   dists/sid/linux-2.6/debian/patches/bugfix/arm/try-dma-copy-to-user.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/config/arm/config.iop32x
   dists/sid/linux-2.6/debian/patches/series/1~experimental.1

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	(original)
+++ dists/sid/linux-2.6/debian/changelog	Wed Nov 28 09:59:48 2007
@@ -47,6 +47,7 @@
     options.
   * [mipsel/r5k-cobalt] Enable the modern Cobalt LEDs driver.
   * [arm/iop32x] Enable Intel IOP ADMA support.
+  * [arm/iop32x] Backport and enable POLLED_DMA_COPY_USER. (closes: #444271)
   * [arm] Mark BCM43XX as broken on ARM.
   * [mips/r4k-ip22] Disable EARLY PRINTK because it breaks serial console.
   * [mips] Add some IP22 fixes from Thomas Bogendoerfer:

Modified: dists/sid/linux-2.6/debian/config/arm/config.iop32x
==============================================================================
--- dists/sid/linux-2.6/debian/config/arm/config.iop32x	(original)
+++ dists/sid/linux-2.6/debian/config/arm/config.iop32x	Wed Nov 28 09:59:48 2007
@@ -1148,6 +1148,8 @@
 # DMA Clients
 #
 CONFIG_NET_DMA=y
+CONFIG_POLLED_DMA_COPY_USER=y
+CONFIG_POLLED_DMA_MEMCPY_THRESHOLD=768
 
 #
 # DMA Devices

Added: dists/sid/linux-2.6/debian/patches/bugfix/arm/try-dma-copy-to-user.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/bugfix/arm/try-dma-copy-to-user.patch	Wed Nov 28 09:59:48 2007
@@ -0,0 +1,373 @@
+From: Dan Williams <dan.j.williams at intel.com>
+
+async_tx: divert large copy_to_user calls to a dma engine
+
+[Taken from the IOP tree]
+
+--- a/drivers/dma/Kconfig~	2007-10-24 10:24:04.000000000 +0000
++++ b/drivers/dma/Kconfig	2007-10-24 10:28:10.000000000 +0000
+@@ -23,6 +23,26 @@
+ 	  Since this is the main user of the DMA engine, it should be enabled;
+ 	  say Y here.
+ 
++config POLLED_DMA_COPY_USER
++	bool "Perform copy_to_user with a DMA engine (polled)"
++	depends on ARCH_IOP32X && DMA_ENGINE && !SMP && !PREEMPT
++	select ASYNC_MEMCPY
++	---help---
++	  If a memory copy request is larger than the POLLED_DMA_COPY_USER_THRESHOLD
++	  then async_tx will trap it and attempt to use a dma engine for the copy.
++	  This operation is polled so it will not benefit CPU utilization.
++	  say Y here.
++
++ config POLLED_DMA_MEMCPY_THRESHOLD
++	int "Polled DMA memcpy threshold (bytes)"
++	depends on POLLED_DMA_MEMCPY || POLLED_DMA_COPY_USER
++	default "768" if ARM
++	default "4096" if !ARM
++	---help---
++	  Minimum number of bytes that must be requested in a memcpy call before it
++	  is handed to a DMA engine for processing.  This does not affect code that
++	  directly calls DMA memcpy routines.
++
+ comment "DMA Devices"
+ 
+ config INTEL_IOATDMA
+--- a/drivers/dma/Makefile~	2007-10-24 10:24:07.000000000 +0000
++++ b/drivers/dma/Makefile	2007-10-24 10:26:46.000000000 +0000
+@@ -2,3 +2,4 @@
+ obj-$(CONFIG_NET_DMA) += iovlock.o
+ obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
+ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
++obj-$(CONFIG_POLLED_DMA_COPY_USER) += copy_to_user.o
+--- /dev/null	2007-09-25 12:43:17.000000000 +0000
++++ b/drivers/dma/copy_to_user.c	2007-11-21 09:40:14.000000000 +0000
+@@ -0,0 +1,248 @@
++/*
++ * Copyright (c) 2007, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ *
++ */
++#include <linux/async_tx.h>
++#include <asm/cacheflush.h>
++#include <asm/uaccess.h>
++#include "copy_user.h"
++
++#undef __copy_to_user
++#define DMA_COPY_TO_USER_DEBUG 0
++#define PRINTK(x...) ((void)(DMA_COPY_TO_USER_DEBUG && printk(x)))
++
++extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
++
++static unsigned long dma_copy_to_user_threshold =
++	CONFIG_POLLED_DMA_MEMCPY_THRESHOLD;
++
++/*=======================================================================*/
++/*  Procedure:  dma_copy_to_user()                                       */
++/*                                                                       */
++/*  Description:    DMA-based copy_to_user.                              */
++/*                                                                       */
++/*  Parameters:  to: destination address                                 */
++/*               from: source address                                    */
++/*               n: number of bytes to transfer                          */
++/*                                                                       */
++/*  Returns:     unsigned long: number of bytes NOT copied               */
++/*                                                                       */
++/*  Notes/Assumptions:                                                   */
++/*              Assumes that kernel physical memory is contiguous, i.e., */
++/*              the physical addresses of contiguous virtual addresses   */
++/*              are also contiguous.                                     */
++/*              Assumes that kernel memory doesn't get paged.            */
++/*              Assumes that to/from memory regions cannot overlap       */
++/*		This code breaks a lot of Linux rules, but it has had	 */
++/*		a long exposure to IOP end users			 */
++/*                                                                       */
++/*  History:    Carl Staelin 1/27/03  Initial Creation                   */
++/*              Dave Jiang   2/22/03  Attemped to DMA chaining           */
++/*                                    (data corrupt with full chain)     */
++/*                                    back to Carl's way for now         */
++/*              Dan Williams 3/12/07  Port to use dmaengine and iop-adma */
++/*=======================================================================*/
++unsigned long __try_polled_dma_copy_to_user(void __user *to, const void *from,
++	unsigned long n)
++{
++	u32 chunk;
++	u32 from_chunk;
++	u32 to_chunk;
++	u32 to_pa = 0;
++	u32 unaligned_to, unaligned_from;
++	void *u, *k;
++	int ua = 0;
++	struct dma_chan *chan = async_tx_find_channel(NULL, DMA_MEMCPY);
++	struct dma_device *device = chan ? chan->device : NULL;
++	struct dma_async_tx_descriptor *tx = NULL;
++
++	if (!chan || n < dma_copy_to_user_threshold)
++		return __copy_to_user(to, from, n);
++
++	PRINTK("%s: (%p, %p, %lu): entering\n",
++		__FUNCTION__, to, from, n);
++	if (((u32) to > PAGE_OFFSET) && ((u32) from > PAGE_OFFSET)) {
++		PRINTK("%s: (%p, %p, %lu): kernel memcpy\n",
++			__FUNCTION__, to, from, n);
++		memcpy(to, from, n);
++		return 0;
++	}
++
++	if(!is_kernel_static((u32) from))
++	{
++		PRINTK("%s: (%p, %p, %lu): vmalloc memcpy\n",
++			__FUNCTION__, to, from, n);
++		return __copy_to_user(to, from, n);
++	}
++
++	to_pa = physical_address((u32) to);
++	PRINTK("  physaddr(to) = %#010x\n", to_pa);
++	/*
++	 * We _only_ support mem -> mem
++	 */
++	if (to_pa < PHYS_OFFSET || to_pa > __pa(high_memory)) {
++		PRINTK("user buffer not in memory\n");
++		return __copy_to_user(to, from, n);
++	}
++
++	/*
++	 * Walk the address range forcing page faults.  We must do writes
++	 * instead of reads in case we have COW pages and need to get
++	 * them re-mapped to a new address range.
++	 */
++	for (u = to, k = (void*)from; u < to + n; u += PAGE_SIZE, k += PAGE_SIZE)
++		put_user(*(char *)k, (char *)u);
++
++	/*
++	 * Ok, start addr is not cache line-aligned, so we need to make it so.
++	 */
++	unaligned_to = (u32) to & 31;
++	unaligned_from = (u32) from & 31;;
++	if (unaligned_to | unaligned_from) {
++		ua++;
++		PRINTK("Fixing up starting address\n");
++		if (unaligned_from > unaligned_to) {
++			PRINTK("unaligned_from larger, copying %d bytes\n",
++				32 - unaligned_to);
++			if (__copy_to_user(to, from, 32 - unaligned_to))
++				return -EFAULT;
++			to = (void *)((u32)to + 32 - unaligned_to);
++			from = (void *)((u32)from + 32 - unaligned_to);
++			n -= (32 - unaligned_to);
++		} else {
++			PRINTK("unaligned_to larger, copying %d bytes\n",
++				32 - unaligned_from);
++			if (__copy_to_user(to, from, 32 - unaligned_from))
++				return -EFAULT;
++			to = (void *)((u32)to + 32 - unaligned_from);
++			from = (void *)((u32)from + 32 - unaligned_from);
++			n -= (32 - unaligned_from);
++		}
++	}
++
++	/*
++	 * Ok, we're aligned at the top, now let's check the end
++	 * of the buffer and align that. After this we should have
++	 * a block that is a multiple of cache line size.
++	 */
++	unaligned_to = ((u32) to + n) & 31;
++	unaligned_from = ((u32) from + n) & 31;;
++	if (unaligned_to | unaligned_from) {
++		ua++;
++		PRINTK("Fixing ending alignment\n");
++		if (unaligned_to > unaligned_from) {
++			u32 tmp_to = (u32) to + (n - unaligned_to);
++			u32 tmp_from = (u32) from + (n - unaligned_to);
++
++			PRINTK("unaligned_to: Copying %d bytes\n",
++				unaligned_to);
++
++			if (__copy_to_user((void *)tmp_to, (void *)tmp_from,
++				unaligned_to))
++				return -EFAULT;
++
++			n -= unaligned_to;
++		} else {
++			u32 tmp_to = (u32) to + (n - unaligned_from);
++			u32 tmp_from = (u32) from + (n - unaligned_from);
++
++			PRINTK("unaligned_from: Copying %d bytes\n",
++				unaligned_from);
++
++			if (__copy_to_user((void *)tmp_to, (void *)tmp_from,
++					    unaligned_from))
++				return -EFAULT;
++
++			n -= unaligned_from;
++		}
++	}
++
++	/*
++	 * OK! We should now be fully aligned on both ends. 
++	 */
++	PRINTK("Done fixup...to: %p from: %p len: %lu\n", to, from, n);
++	dmac_inv_range(to, to + n);
++	dmac_clean_range(from, from + n);
++
++	preempt_disable();	
++
++	from_chunk = 0;
++	to_chunk = 0;
++
++	PRINTK("USING DMA: %p, %p, %lu\n", to, from, n);
++
++	while (n > 0) {
++		if (from_chunk == 0) {
++			/* kernel logical address ==> contiguous */
++			if (is_kernel_static((u32) from)) {
++				from_chunk = n;
++			} else {
++				/* virtual address */
++				from_chunk = page_remainder((u32) from);
++			}
++		}
++
++		if (to_chunk == 0) {
++			to_chunk = page_remainder((u32) to);
++			to_pa = physical_address((u32) to);
++
++			/*
++			 * This should NOT happen...
++			 */
++			if (!to_pa) {
++				PRINTK("%s: no physical address for %p,"
++						" falling back! **** \n",
++					__FUNCTION__, to);
++				return __copy_to_user(to, from, n);
++			}
++		}
++		chunk = ((to_chunk < from_chunk) ? to_chunk : from_chunk);
++		if (n < chunk) {
++			chunk = n;
++		}
++
++		if (chunk == 0) {
++			break;
++		}
++
++		tx = device->device_prep_dma_memcpy(chan, chunk, 0);
++		if (!tx) {
++			PRINTK("%s: no descriptors available\n", __FUNCTION__);
++			return __copy_to_user(to, from, n);
++		}
++
++		tx->tx_set_dest(to_pa, tx, 0);
++		tx->tx_set_src(physical_address((u32) from), tx, 0);
++
++		async_tx_submit(chan, tx, ASYNC_TX_ACK, NULL, NULL, NULL);
++
++		/* do some work while waiting */
++		from += chunk;
++		to += chunk;
++		n -= chunk;
++		to_chunk -= chunk;
++		from_chunk -= chunk;
++	}
++
++	dma_wait_for_async_tx(tx);
++
++	preempt_enable();
++
++	PRINTK("%s: (%p, %p, %lu): exiting\n", __FUNCTION__, to, from, n);
++	return 0;
++}
++EXPORT_SYMBOL(__try_polled_dma_copy_to_user);
++
+--- /dev/null	2007-09-25 12:43:17.000000000 +0000
++++ b/drivers/dma/copy_user.h	2007-10-24 10:27:04.000000000 +0000
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (c) 2007, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ *
++ */
++#ifndef _COPY_USER_H_
++#define _COPY_USER_H_
++struct dma_chan *
++async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
++	enum dma_transaction_type tx_type);
++void async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx,
++	enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
++	dma_async_tx_callback callback, void *callback_param);
++
++static inline u32 page_offset_xscale(u32 virt)
++{
++	return virt & (PAGE_SIZE - 1);
++}
++
++static inline u32 page_remainder(u32 virt)
++{
++	return PAGE_SIZE - page_offset_xscale(virt);
++}
++
++static inline int is_kernel_static(u32 virt)
++{
++	return ((virt >= PAGE_OFFSET) && (virt < (unsigned long)high_memory));
++}
++
++/* 
++ * map a kernel virtual address or kernel logical address to a phys address
++ */
++static inline u32 physical_address(u32 virt)
++{
++	struct page *page;
++
++	/* kernel static-mapped address */
++	if (is_kernel_static((u32) virt)) {
++		return __pa((u32) virt);
++	}
++	page = follow_page(current->mm->mmap, (u32) virt, 1);
++	if (pfn_valid(page_to_pfn(page))) {
++		return ((page_to_pfn(page) << PAGE_SHIFT) |
++			page_offset_xscale((u32) virt & (PAGE_SIZE - 1)));
++	} else {
++		return 0;
++	}
++}
++#endif
++
+--- include/asm-arm/uaccess.h~	2007-10-24 10:24:10.000000000 +0000
++++ b/include/asm-arm/uaccess.h	2007-10-24 10:27:04.000000000 +0000
+@@ -392,6 +392,12 @@
+ #define __clear_user(addr,n)		(memset((void __force *)addr, 0, n), 0)
+ #endif
+ 
++#ifdef CONFIG_POLLED_DMA_COPY_USER
++extern unsigned long __must_check __try_polled_dma_copy_to_user(void __user *to, const void *from, unsigned long n);
++
++#define __copy_to_user(to, from, n) __try_polled_dma_copy_to_user(to, from, n)
++#endif
++
+ extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count);
+ extern unsigned long __must_check __strnlen_user(const char __user *s, long n);
+ 

Modified: dists/sid/linux-2.6/debian/patches/series/1~experimental.1
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/1~experimental.1	(original)
+++ dists/sid/linux-2.6/debian/patches/series/1~experimental.1	Wed Nov 28 09:59:48 2007
@@ -46,6 +46,7 @@
 + bugfix/arm/disable-video_bt848.patch
 + bugfix/arm/disable-bcm43xx.patch
 + bugfix/arm/binutils-notes.patch
++ bugfix/arm/try-dma-copy-to-user.patch
 + bugfix/all/git-ieee1394.patch
 + features/all/v7-iwlwifi-add-iwlwifi-wireless-drivers.patch
 + features/all/e1000e-20070806.patch



More information about the Kernel-svn-changes mailing list