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 <[EMAIL PROTECTED]>
+
+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

_______________________________________________
Kernel-svn-changes mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/kernel-svn-changes

Reply via email to