[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