Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 14 Feb 2007 00:12:23 +0000 (16:12 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 14 Feb 2007 00:12:23 +0000 (16:12 -0800)
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus:
  [MIPS] Fix sigset_t endianess swapping issues in 32-bit compat code.
  [MIPS] Fix uniprocessor Sibyte builds.
  [MIPS] Make entry.S a little more readable.
  [MIPS] Remove stray instruction from __get_user_asm_ll32.
  [MIPS] 32-bit: Fix warning about cast for fetching pointer from userspace.
  [MIPS] DECstation: Fix irq handling
  [MIPS] signals: make common _BLOCKABLE macro
  [MIPS] signal: Move sigframe definition for native O32/N64 into signal.c
  [MIPS] signal: Move {restore,setup}_sigcontext prototypes to their user
  [MIPS] signal: Fix warnings in o32 compat code.
  [MIPS] IP27: Enable N32 support in defconfig.
  Revert "[MIPS] Fix warning in get_user when fetching pointer object from userspace."
  [MIPS] Don't claim we support dma_declare_coherent_memory - we don't.
  [MIPS] Unify dma-{coherent,noncoherent.ip27,ip32}
  [MIPS] Improve branch prediction in ll/sc atomic operations.

31 files changed:
arch/mips/Kconfig
arch/mips/configs/ip27_defconfig
arch/mips/dec/int-handler.S
arch/mips/kernel/entry.S
arch/mips/kernel/linux32.c
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/signal-common.h
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/signal_n32.c
arch/mips/mm/Makefile
arch/mips/mm/c-sb1.c
arch/mips/mm/dma-coherent.c [deleted file]
arch/mips/mm/dma-default.c [moved from arch/mips/mm/dma-noncoherent.c with 63% similarity]
arch/mips/mm/dma-ip27.c [deleted file]
arch/mips/mm/dma-ip32.c [deleted file]
arch/mips/pci/Makefile
arch/mips/pci/pci-dac.c [new file with mode: 0644]
include/asm-mips/atomic.h
include/asm-mips/bitops.h
include/asm-mips/compat-signal.h [new file with mode: 0644]
include/asm-mips/dma-mapping.h
include/asm-mips/mach-generic/dma-coherence.h [new file with mode: 0644]
include/asm-mips/mach-generic/kmalloc.h
include/asm-mips/mach-ip27/dma-coherence.h [new file with mode: 0644]
include/asm-mips/mach-ip32/dma-coherence.h [new file with mode: 0644]
include/asm-mips/mach-jazz/dma-coherence.h [new file with mode: 0644]
include/asm-mips/spinlock.h
include/asm-mips/system.h
include/asm-mips/uaccess.h

index 5fe195a..a92ce6b 100644 (file)
@@ -598,8 +598,6 @@ config SGI_IP32
        select ARC
        select ARC32
        select BOOT_ELF32
-       select OWN_DMA
-       select DMA_IP32
        select DMA_NONCOHERENT
        select HW_HAS_PCI
        select R5000_CPU_SCACHE
@@ -883,9 +881,6 @@ config DMA_NONCOHERENT
 config DMA_NEED_PCI_MAP_STATE
        bool
 
-config OWN_DMA
-       bool
-
 config EARLY_PRINTK
        bool
 
index 96090f2..f21186c 100644 (file)
@@ -264,7 +264,7 @@ CONFIG_BINFMT_ELF=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
-# CONFIG_MIPS32_N32 is not set
+CONFIG_MIPS32_N32=y
 CONFIG_BINFMT_ELF32=y
 
 #
index b251ef8..00cecdc 100644 (file)
                 srlv   t3,t1,t2
 
 handle_it:
-               LONG_L  s0, TI_REGS($28)
-               LONG_S  sp, TI_REGS($28)
-               PTR_LA  ra, ret_from_irq
                j       dec_irq_dispatch
                 nop
 
@@ -277,7 +274,6 @@ fpu:
 #endif
 
 spurious:
-               PTR_LA  ra, _ret_from_irq
                j       spurious_interrupt
                 nop
                END(plat_irq_dispatch)
index f10b6a1..0b78fcb 100644 (file)
 #endif
 
 #ifndef CONFIG_PREEMPT
-       .macro  preempt_stop
-       local_irq_disable
-       .endm
 #define resume_kernel  restore_all
+#else
+#define __ret_from_irq ret_from_exception
 #endif
 
        .text
        .align  5
-FEXPORT(ret_from_irq)
-       LONG_S  s0, TI_REGS($28)
-#ifdef CONFIG_PREEMPT
-FEXPORT(ret_from_exception)
-#else
-       b       _ret_from_irq
+#ifndef CONFIG_PREEMPT
 FEXPORT(ret_from_exception)
-       preempt_stop
+       local_irq_disable                       # preempt stop
+       b       __ret_from_irq
 #endif
-FEXPORT(_ret_from_irq)
+FEXPORT(ret_from_irq)
+       LONG_S  s0, TI_REGS($28)
+FEXPORT(__ret_from_irq)
        LONG_L  t0, PT_STATUS(sp)               # returning to kernel mode?
        andi    t0, t0, KU_USER
        beqz    t0, resume_kernel
index ca7ad78..fc4dd6c 100644 (file)
@@ -39,6 +39,7 @@
 #include <net/sock.h>
 #include <net/scm.h>
 
+#include <asm/compat-signal.h>
 #include <asm/ipc.h>
 #include <asm/sim.h>
 #include <asm/uaccess.h>
@@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
        return do_fork(clone_flags, newsp, &regs, 0,
                       parent_tidptr, child_tidptr);
 }
+
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_pwait(2).
+ */
+asmlinkage long compat_sys_epoll_pwait(int epfd,
+       struct epoll_event __user *events, int maxevents, int timeout,
+       const compat_sigset_t __user *sigmask, size_t sigsetsize)
+{
+       int error;
+       sigset_t ksigmask, sigsaved;
+
+       /*
+        * If the caller wants a certain signal mask to be set during the wait,
+        * we apply it here.
+        */
+       if (sigmask) {
+               if (sigsetsize != sizeof(sigset_t))
+                       return -EINVAL;
+               if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask)))
+                       return -EFAULT;
+               if (__copy_conv_sigset_from_user(&ksigmask, sigmask))
+                       return -EFAULT;
+               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+       }
+
+       error = sys_epoll_wait(epfd, events, maxevents, timeout);
+
+       /*
+        * If we changed the signal mask, we need to restore the original one.
+        * In case we've got a signal while waiting, we do not restore the
+        * signal mask yet, and we allow do_signal() to deliver the signal on
+        * the way back to userspace, before the signal mask is restored.
+        */
+       if (sigmask) {
+               if (error == -EINTR) {
+                       memcpy(&current->saved_sigmask, &sigsaved,
+                               sizeof(sigsaved));
+                       set_thread_flag(TIF_RESTORE_SIGMASK);
+               } else
+                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+       }
+
+       return error;
+}
index e569b84..10e9a18 100644 (file)
@@ -470,4 +470,4 @@ sys_call_table:
        PTR     sys_get_robust_list
        PTR     sys_kexec_load                  /* 5270 */
        PTR     sys_getcpu
-       PTR     sys_epoll_pwait
+       PTR     compat_sys_epoll_pwait
index ee8802b..2ceda46 100644 (file)
@@ -396,4 +396,4 @@ EXPORT(sysn32_call_table)
        PTR     compat_sys_get_robust_list
        PTR     compat_sys_kexec_load
        PTR     sys_getcpu
-       PTR     sys_epoll_pwait
+       PTR     compat_sys_epoll_pwait
index 9a8abd6..fdbdbdc 100644 (file)
 #  define DEBUGP(fmt, args...)
 #endif
 
-/*
- * Horribly complicated - with the bloody RM9000 workarounds enabled
- * the signal trampolines is moving to the end of the structure so we can
- * increase the alignment without breaking software compatibility.
- */
-#if ICACHE_REFILLS_WORKAROUND_WAR == 0
-
-struct sigframe {
-       u32 sf_ass[4];          /* argument save space for o32 */
-       u32 sf_code[2];         /* signal trampoline */
-       struct sigcontext sf_sc;
-       sigset_t sf_mask;
-};
-
-#else  /* ICACHE_REFILLS_WORKAROUND_WAR */
-
-struct sigframe {
-       u32 sf_ass[4];                  /* argument save space for o32 */
-       u32 sf_pad[2];
-       struct sigcontext sf_sc;        /* hw context */
-       sigset_t sf_mask;
-       u32 sf_code[8] ____cacheline_aligned;   /* signal trampoline */
-};
-
-#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
-
-/*
- * handle hardware context
- */
-extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *);
-extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 /*
  * Determine which stack to use..
index 54398af..b2e9ab1 100644 (file)
 
 #include "signal-common.h"
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
+/*
+ * Horribly complicated - with the bloody RM9000 workarounds enabled
+ * the signal trampolines is moving to the end of the structure so we can
+ * increase the alignment without breaking software compatibility.
+ */
 #if ICACHE_REFILLS_WORKAROUND_WAR == 0
 
+struct sigframe {
+       u32 sf_ass[4];          /* argument save space for o32 */
+       u32 sf_code[2];         /* signal trampoline */
+       struct sigcontext sf_sc;
+       sigset_t sf_mask;
+};
+
 struct rt_sigframe {
        u32 rs_ass[4];          /* argument save space for o32 */
        u32 rs_code[2];         /* signal trampoline */
@@ -47,6 +57,14 @@ struct rt_sigframe {
 
 #else
 
+struct sigframe {
+       u32 sf_ass[4];                  /* argument save space for o32 */
+       u32 sf_pad[2];
+       struct sigcontext sf_sc;        /* hw context */
+       sigset_t sf_mask;
+       u32 sf_code[8] ____cacheline_aligned;   /* signal trampoline */
+};
+
 struct rt_sigframe {
        u32 rs_ass[4];                  /* argument save space for o32 */
        u32 rs_pad[2];
index 183fc7e..c28cb21 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #include <linux/cache.h>
+#include <linux/compat.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -24,6 +25,7 @@
 
 #include <asm/abi.h>
 #include <asm/asm.h>
+#include <asm/compat-signal.h>
 #include <linux/bitops.h>
 #include <asm/cacheflush.h>
 #include <asm/sim.h>
@@ -104,8 +106,6 @@ typedef struct compat_siginfo {
 #define __NR_O32_rt_sigreturn          4193
 #define __NR_O32_restart_syscall       4253
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
 /* 32-bit compatibility types */
 
 #define _NSIG_BPW32    32
@@ -139,8 +139,20 @@ struct ucontext32 {
        sigset_t32          uc_sigmask;   /* mask last for extensibility */
 };
 
+/*
+ * Horribly complicated - with the bloody RM9000 workarounds enabled
+ * the signal trampolines is moving to the end of the structure so we can
+ * increase the alignment without breaking software compatibility.
+ */
 #if ICACHE_REFILLS_WORKAROUND_WAR == 0
 
+struct sigframe32 {
+       u32 sf_ass[4];          /* argument save space for o32 */
+       u32 sf_code[2];         /* signal trampoline */
+       struct sigcontext32 sf_sc;
+       sigset_t sf_mask;
+};
+
 struct rt_sigframe32 {
        u32 rs_ass[4];                  /* argument save space for o32 */
        u32 rs_code[2];                 /* signal trampoline */
@@ -150,6 +162,14 @@ struct rt_sigframe32 {
 
 #else  /* ICACHE_REFILLS_WORKAROUND_WAR */
 
+struct sigframe32 {
+       u32 sf_ass[4];                  /* argument save space for o32 */
+       u32 sf_pad[2];
+       struct sigcontext32 sf_sc;      /* hw context */
+       sigset_t sf_mask;
+       u32 sf_code[8] ____cacheline_aligned;   /* signal trampoline */
+};
+
 struct rt_sigframe32 {
        u32 rs_ass[4];                  /* argument save space for o32 */
        u32 rs_pad[2];
@@ -493,13 +513,13 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
 
 asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
 {
-       struct sigframe __user *frame;
+       struct sigframe32 __user *frame;
        sigset_t blocked;
 
-       frame = (struct sigframe __user *) regs.regs[29];
+       frame = (struct sigframe32 __user *) regs.regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
-       if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
+       if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
                goto badframe;
 
        sigdelsetmask(&blocked, ~_BLOCKABLE);
@@ -536,7 +556,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
        frame = (struct rt_sigframe32 __user *) regs.regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
-       if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
+       if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
                goto badframe;
 
        sigdelsetmask(&set, ~_BLOCKABLE);
@@ -581,7 +601,7 @@ badframe:
 int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
        int signr, sigset_t *set)
 {
-       struct sigframe __user *frame;
+       struct sigframe32 __user *frame;
        int err = 0;
 
        frame = get_sigframe(ka, regs, sizeof(*frame));
@@ -591,7 +611,8 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
        err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
 
        err |= setup_sigcontext32(regs, &frame->sf_sc);
-       err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
+       err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
+
        if (err)
                goto give_sigsegv;
 
@@ -650,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
        err |= __put_user(current->sas_ss_size,
                          &frame->rs_uc.uc_stack.ss_size);
        err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
-       err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
+       err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
 
        if (err)
                goto give_sigsegv;
index 57456e6..7ca2a07 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <asm/asm.h>
 #include <asm/cacheflush.h>
+#include <asm/compat-signal.h>
 #include <asm/sim.h>
 #include <asm/uaccess.h>
 #include <asm/ucontext.h>
@@ -47,7 +48,9 @@
 #define __NR_N32_rt_sigreturn          6211
 #define __NR_N32_restart_syscall       6214
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *);
+extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
+
 
 /* IRIX compatible stack_t  */
 typedef struct sigaltstack32 {
@@ -61,7 +64,7 @@ struct ucontextn32 {
        s32                 uc_link;
        stack32_t           uc_stack;
        struct sigcontext   uc_mcontext;
-       sigset_t            uc_sigmask;   /* mask last for extensibility */
+       compat_sigset_t     uc_sigmask;   /* mask last for extensibility */
 };
 
 #if ICACHE_REFILLS_WORKAROUND_WAR == 0
@@ -127,7 +130,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
        frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
-       if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
+       if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
                goto badframe;
 
        sigdelsetmask(&set, ~_BLOCKABLE);
@@ -193,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
        err |= __put_user(current->sas_ss_size,
                          &frame->rs_uc.uc_stack.ss_size);
        err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
-       err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
+       err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
 
        if (err)
                goto give_sigsegv;
index 19e41fd..de57273 100644 (file)
@@ -2,8 +2,8 @@
 # Makefile for the Linux/MIPS-specific parts of the memory manager.
 #
 
-obj-y                          += cache.o extable.o fault.o init.o pgtable.o \
-                                  tlbex.o tlbex-fault.o
+obj-y                          += cache.o dma-default.o extable.o fault.o \
+                                  init.o pgtable.o tlbex.o tlbex-fault.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
@@ -32,14 +32,4 @@ obj-$(CONFIG_R5000_CPU_SCACHE)  += sc-r5k.o
 obj-$(CONFIG_RM7000_CPU_SCACHE)        += sc-rm7k.o
 obj-$(CONFIG_MIPS_CPU_SCACHE)  += sc-mips.o
 
-#
-# Choose one DMA coherency model
-#
-ifndef CONFIG_OWN_DMA
-obj-$(CONFIG_DMA_COHERENT)     += dma-coherent.o
-obj-$(CONFIG_DMA_NONCOHERENT)  += dma-noncoherent.o
-endif
-obj-$(CONFIG_DMA_IP27)         += dma-ip27.o
-obj-$(CONFIG_DMA_IP32)         += dma-ip32.o
-
 EXTRA_AFLAGS := $(CFLAGS)
index 3a8afd4..9ea460b 100644 (file)
@@ -259,6 +259,12 @@ static void sb1_flush_cache_data_page(unsigned long addr)
                on_each_cpu(sb1_flush_cache_data_page_ipi, (void *) addr, 1, 1);
 }
 #else
+
+static void local_sb1_flush_cache_data_page(unsigned long addr)
+{
+       __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE);
+}
+
 void sb1_flush_cache_data_page(unsigned long)
        __attribute__((alias("local_sb1_flush_cache_data_page")));
 #endif
diff --git a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c
deleted file mode 100644 (file)
index 5697c6e..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
- * Copyright (C) 2000, 2001  Ralf Baechle <ralf@gnu.org>
- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
- */
-#include <linux/types.h>
-#include <linux/dma-mapping.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/string.h>
-
-#include <asm/cache.h>
-#include <asm/io.h>
-
-void *dma_alloc_noncoherent(struct device *dev, size_t size,
-       dma_addr_t * dma_handle, gfp_t gfp)
-{
-       void *ret;
-       /* ignore region specifiers */
-       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-
-       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-               gfp |= GFP_DMA;
-       ret = (void *) __get_free_pages(gfp, get_order(size));
-
-       if (ret != NULL) {
-               memset(ret, 0, size);
-               *dma_handle = virt_to_phys(ret);
-       }
-
-       return ret;
-}
-
-EXPORT_SYMBOL(dma_alloc_noncoherent);
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-       dma_addr_t * dma_handle, gfp_t gfp)
-       __attribute__((alias("dma_alloc_noncoherent")));
-
-EXPORT_SYMBOL(dma_alloc_coherent);
-
-void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-       dma_addr_t dma_handle)
-{
-       unsigned long addr = (unsigned long) vaddr;
-
-       free_pages(addr, get_order(size));
-}
-
-EXPORT_SYMBOL(dma_free_noncoherent);
-
-void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-       dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent")));
-
-EXPORT_SYMBOL(dma_free_coherent);
-
-dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-       enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       return __pa(ptr);
-}
-
-EXPORT_SYMBOL(dma_map_single);
-
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_unmap_single);
-
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-       enum dma_data_direction direction)
-{
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-
-       for (i = 0; i < nents; i++, sg++) {
-               sg->dma_address = (dma_addr_t)page_to_phys(sg->page) + sg->offset;
-       }
-
-       return nents;
-}
-
-EXPORT_SYMBOL(dma_map_sg);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-       unsigned long offset, size_t size, enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       return page_to_phys(page) + offset;
-}
-
-EXPORT_SYMBOL(dma_map_page);
-
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_unmap_page);
-
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-            enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_unmap_sg);
-
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-       size_t size, enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_for_cpu);
-
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-       size_t size, enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_for_device);
-
-void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                     unsigned long offset, size_t size,
-                     enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-
-void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-                     unsigned long offset, size_t size,
-                     enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
-
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-                enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
-
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-                enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_sg_for_device);
-
-int dma_mapping_error(dma_addr_t dma_addr)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(dma_mapping_error);
-
-int dma_supported(struct device *dev, u64 mask)
-{
-       /*
-        * we fall back to GFP_DMA when the mask isn't all 1s,
-        * so we can't guarantee allocations that must be
-        * within a tighter range than GFP_DMA..
-        */
-       if (mask < 0x00ffffff)
-               return 0;
-
-       return 1;
-}
-
-EXPORT_SYMBOL(dma_supported);
-
-int dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
-{
-       return 1;
-}
-
-EXPORT_SYMBOL(dma_is_consistent);
-
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_cache_sync);
-
-/* The DAC routines are a PCIism.. */
-
-#ifdef CONFIG_PCI
-
-#include <linux/pci.h>
-
-dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
-       struct page *page, unsigned long offset, int direction)
-{
-       return (dma64_addr_t)page_to_phys(page) + offset;
-}
-
-EXPORT_SYMBOL(pci_dac_page_to_dma);
-
-struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
-       dma64_addr_t dma_addr)
-{
-       return mem_map + (dma_addr >> PAGE_SHIFT);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_page);
-
-unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
-       dma64_addr_t dma_addr)
-{
-       return dma_addr & ~PAGE_MASK;
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_offset);
-
-void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
-       dma64_addr_t dma_addr, size_t len, int direction)
-{
-       BUG_ON(direction == PCI_DMA_NONE);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
-
-void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
-       dma64_addr_t dma_addr, size_t len, int direction)
-{
-       BUG_ON(direction == PCI_DMA_NONE);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
-
-#endif /* CONFIG_PCI */
similarity index 63%
rename from arch/mips/mm/dma-noncoherent.c
rename to arch/mips/mm/dma-default.c
index 8cecef0..4a32e93 100644 (file)
@@ -4,28 +4,39 @@
  * for more details.
  *
  * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
- * Copyright (C) 2000, 2001  Ralf Baechle <ralf@gnu.org>
+ * Copyright (C) 2000, 2001, 06  Ralf Baechle <ralf@linux-mips.org>
  * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
  */
+
 #include <linux/types.h>
+#include <linux/dma-mapping.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/dma-mapping.h>
 
 #include <asm/cache.h>
 #include <asm/io.h>
 
+#include <dma-coherence.h>
+
 /*
  * Warning on the terminology - Linux calls an uncached area coherent;
  * MIPS terminology calls memory areas with hardware maintained coherency
  * coherent.
  */
 
+static inline int cpu_is_noncoherent_r10000(struct device *dev)
+{
+       return !plat_device_is_coherent(dev) &&
+              (current_cpu_data.cputype == CPU_R10000 &&
+              current_cpu_data.cputype == CPU_R12000);
+}
+
 void *dma_alloc_noncoherent(struct device *dev, size_t size,
        dma_addr_t * dma_handle, gfp_t gfp)
 {
        void *ret;
+
        /* ignore region specifiers */
        gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
@@ -35,7 +46,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size,
 
        if (ret != NULL) {
                memset(ret, 0, size);
-               *dma_handle = virt_to_phys(ret);
+               *dma_handle = plat_map_dma_mem(dev, ret, size);
        }
 
        return ret;
@@ -48,10 +59,21 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 {
        void *ret;
 
-       ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
+       /* ignore region specifiers */
+       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
+               gfp |= GFP_DMA;
+       ret = (void *) __get_free_pages(gfp, get_order(size));
+
        if (ret) {
-               dma_cache_wback_inv((unsigned long) ret, size);
-               ret = UNCAC_ADDR(ret);
+               memset(ret, 0, size);
+               *dma_handle = plat_map_dma_mem(dev, ret, size);
+
+               if (!plat_device_is_coherent(dev)) {
+                       dma_cache_wback_inv((unsigned long) ret, size);
+                       ret = UNCAC_ADDR(ret);
+               }
        }
 
        return ret;
@@ -72,7 +94,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 {
        unsigned long addr = (unsigned long) vaddr;
 
-       addr = CAC_ADDR(addr);
+       if (!plat_device_is_coherent(dev))
+               addr = CAC_ADDR(addr);
+
        free_pages(addr, get_order(size));
 }
 
@@ -104,9 +128,10 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 {
        unsigned long addr = (unsigned long) ptr;
 
-       __dma_sync(addr, size, direction);
+       if (!plat_device_is_coherent(dev))
+               __dma_sync(addr, size, direction);
 
-       return virt_to_phys(ptr);
+       return plat_map_dma_mem(dev, ptr, size);
 }
 
 EXPORT_SYMBOL(dma_map_single);
@@ -114,10 +139,11 @@ EXPORT_SYMBOL(dma_map_single);
 void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
        enum dma_data_direction direction)
 {
-       unsigned long addr;
-       addr = dma_addr + PAGE_OFFSET;
+       if (cpu_is_noncoherent_r10000(dev))
+               __dma_sync(plat_dma_addr_to_phys(dma_addr) + PAGE_OFFSET, size,
+                          direction);
 
-       //__dma_sync(addr, size, direction);
+       plat_unmap_dma_mem(dma_addr);
 }
 
 EXPORT_SYMBOL(dma_unmap_single);
@@ -133,11 +159,10 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
                unsigned long addr;
 
                addr = (unsigned long) page_address(sg->page);
-               if (addr) {
+               if (!plat_device_is_coherent(dev) && addr)
                        __dma_sync(addr + sg->offset, sg->length, direction);
-                       sg->dma_address = (dma_addr_t)page_to_phys(sg->page)
-                                         + sg->offset;
-               }
+               sg->dma_address = plat_map_dma_mem_page(dev, sg->page) +
+                                 sg->offset;
        }
 
        return nents;
@@ -148,14 +173,16 @@ EXPORT_SYMBOL(dma_map_sg);
 dma_addr_t dma_map_page(struct device *dev, struct page *page,
        unsigned long offset, size_t size, enum dma_data_direction direction)
 {
-       unsigned long addr;
-
        BUG_ON(direction == DMA_NONE);
 
-       addr = (unsigned long) page_address(page) + offset;
-       dma_cache_wback_inv(addr, size);
+       if (!plat_device_is_coherent(dev)) {
+               unsigned long addr;
+
+               addr = (unsigned long) page_address(page) + offset;
+               dma_cache_wback_inv(addr, size);
+       }
 
-       return page_to_phys(page) + offset;
+       return plat_map_dma_mem_page(dev, page) + offset;
 }
 
 EXPORT_SYMBOL(dma_map_page);
@@ -165,12 +192,14 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
 {
        BUG_ON(direction == DMA_NONE);
 
-       if (direction != DMA_TO_DEVICE) {
+       if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) {
                unsigned long addr;
 
-               addr = dma_address + PAGE_OFFSET;
+               addr = plat_dma_addr_to_phys(dma_address);
                dma_cache_wback_inv(addr, size);
        }
+
+       plat_unmap_dma_mem(dma_address);
 }
 
 EXPORT_SYMBOL(dma_unmap_page);
@@ -183,13 +212,15 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
 
        BUG_ON(direction == DMA_NONE);
 
-       if (direction == DMA_TO_DEVICE)
-               return;
-
        for (i = 0; i < nhwentries; i++, sg++) {
-               addr = (unsigned long) page_address(sg->page);
-               if (addr)
-                       __dma_sync(addr + sg->offset, sg->length, direction);
+               if (!plat_device_is_coherent(dev) &&
+                   direction != DMA_TO_DEVICE) {
+                       addr = (unsigned long) page_address(sg->page);
+                       if (addr)
+                               __dma_sync(addr + sg->offset, sg->length,
+                                          direction);
+               }
+               plat_unmap_dma_mem(sg->dma_address);
        }
 }
 
@@ -198,12 +229,14 @@ EXPORT_SYMBOL(dma_unmap_sg);
 void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
        size_t size, enum dma_data_direction direction)
 {
-       unsigned long addr;
-
        BUG_ON(direction == DMA_NONE);
 
-       addr = dma_handle + PAGE_OFFSET;
-       __dma_sync(addr, size, direction);
+       if (cpu_is_noncoherent_r10000(dev)) {
+               unsigned long addr;
+
+               addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle);
+               __dma_sync(addr, size, direction);
+       }
 }
 
 EXPORT_SYMBOL(dma_sync_single_for_cpu);
@@ -211,12 +244,14 @@ EXPORT_SYMBOL(dma_sync_single_for_cpu);
 void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
        size_t size, enum dma_data_direction direction)
 {
-       unsigned long addr;
-
        BUG_ON(direction == DMA_NONE);
 
-       addr = dma_handle + PAGE_OFFSET;
-       __dma_sync(addr, size, direction);
+       if (cpu_is_noncoherent_r10000(dev)) {
+               unsigned long addr;
+
+               addr = plat_dma_addr_to_phys(dma_handle);
+               __dma_sync(addr, size, direction);
+       }
 }
 
 EXPORT_SYMBOL(dma_sync_single_for_device);
@@ -224,12 +259,14 @@ EXPORT_SYMBOL(dma_sync_single_for_device);
 void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
        unsigned long offset, size_t size, enum dma_data_direction direction)
 {
-       unsigned long addr;
-
        BUG_ON(direction == DMA_NONE);
 
-       addr = dma_handle + offset + PAGE_OFFSET;
-       __dma_sync(addr, size, direction);
+       if (cpu_is_noncoherent_r10000(dev)) {
+               unsigned long addr;
+
+               addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle);
+               __dma_sync(addr + offset, size, direction);
+       }
 }
 
 EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
@@ -237,12 +274,14 @@ EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
 void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
        unsigned long offset, size_t size, enum dma_data_direction direction)
 {
-       unsigned long addr;
-
        BUG_ON(direction == DMA_NONE);
 
-       addr = dma_handle + offset + PAGE_OFFSET;
-       __dma_sync(addr, size, direction);
+       if (cpu_is_noncoherent_r10000(dev)) {
+               unsigned long addr;
+
+               addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle);
+               __dma_sync(addr + offset, size, direction);
+       }
 }
 
 EXPORT_SYMBOL(dma_sync_single_range_for_device);
@@ -255,9 +294,12 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
        BUG_ON(direction == DMA_NONE);
 
        /* Make sure that gcc doesn't leave the empty loop body.  */
-       for (i = 0; i < nelems; i++, sg++)
-               __dma_sync((unsigned long)page_address(sg->page),
-                          sg->length, direction);
+       for (i = 0; i < nelems; i++, sg++) {
+               if (!plat_device_is_coherent(dev))
+                       __dma_sync((unsigned long)page_address(sg->page),
+                                  sg->length, direction);
+               plat_unmap_dma_mem(sg->dma_address);
+       }
 }
 
 EXPORT_SYMBOL(dma_sync_sg_for_cpu);
@@ -270,9 +312,12 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nele
        BUG_ON(direction == DMA_NONE);
 
        /* Make sure that gcc doesn't leave the empty loop body.  */
-       for (i = 0; i < nelems; i++, sg++)
-               __dma_sync((unsigned long)page_address(sg->page),
-                          sg->length, direction);
+       for (i = 0; i < nelems; i++, sg++) {
+               if (!plat_device_is_coherent(dev))
+                       __dma_sync((unsigned long)page_address(sg->page),
+                                  sg->length, direction);
+               plat_unmap_dma_mem(sg->dma_address);
+       }
 }
 
 EXPORT_SYMBOL(dma_sync_sg_for_device);
@@ -301,70 +346,18 @@ EXPORT_SYMBOL(dma_supported);
 
 int dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
 {
-       return 1;
+       return plat_device_is_coherent(dev);
 }
 
 EXPORT_SYMBOL(dma_is_consistent);
 
 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-       enum dma_data_direction direction)
+              enum dma_data_direction direction)
 {
-       if (direction == DMA_NONE)
-               return;
+       BUG_ON(direction == DMA_NONE);
 
-       dma_cache_wback_inv((unsigned long)vaddr, size);
+       if (!plat_device_is_coherent(dev))
+               dma_cache_wback_inv((unsigned long)vaddr, size);
 }
 
 EXPORT_SYMBOL(dma_cache_sync);
-
-/* The DAC routines are a PCIism.. */
-
-#ifdef CONFIG_PCI
-
-#include <linux/pci.h>
-
-dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
-       struct page *page, unsigned long offset, int direction)
-{
-       return (dma64_addr_t)page_to_phys(page) + offset;
-}
-
-EXPORT_SYMBOL(pci_dac_page_to_dma);
-
-struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
-       dma64_addr_t dma_addr)
-{
-       return mem_map + (dma_addr >> PAGE_SHIFT);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_page);
-
-unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
-       dma64_addr_t dma_addr)
-{
-       return dma_addr & ~PAGE_MASK;
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_offset);
-
-void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
-       dma64_addr_t dma_addr, size_t len, int direction)
-{
-       BUG_ON(direction == PCI_DMA_NONE);
-
-       dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
-
-void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
-       dma64_addr_t dma_addr, size_t len, int direction)
-{
-       BUG_ON(direction == PCI_DMA_NONE);
-
-       dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
-
-#endif /* CONFIG_PCI */
diff --git a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c
deleted file mode 100644 (file)
index f088344..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
- * Copyright (C) 2000, 2001  Ralf Baechle <ralf@gnu.org>
- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-
-#include <asm/cache.h>
-#include <asm/pci/bridge.h>
-
-#define pdev_to_baddr(pdev, addr) \
-       (BRIDGE_CONTROLLER(pdev->bus)->baddr + (addr))
-#define dev_to_baddr(dev, addr) \
-       pdev_to_baddr(to_pci_dev(dev), (addr))
-
-void *dma_alloc_noncoherent(struct device *dev, size_t size,
-       dma_addr_t * dma_handle, gfp_t gfp)
-{
-       void *ret;
-
-       /* ignore region specifiers */
-       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-
-       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-               gfp |= GFP_DMA;
-       ret = (void *) __get_free_pages(gfp, get_order(size));
-
-       if (ret != NULL) {
-               memset(ret, 0, size);
-               *dma_handle = dev_to_baddr(dev, virt_to_phys(ret));
-       }
-
-       return ret;
-}
-
-EXPORT_SYMBOL(dma_alloc_noncoherent);
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-       dma_addr_t * dma_handle, gfp_t gfp)
-       __attribute__((alias("dma_alloc_noncoherent")));
-
-EXPORT_SYMBOL(dma_alloc_coherent);
-
-void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-       dma_addr_t dma_handle)
-{
-       unsigned long addr = (unsigned long) vaddr;
-
-       free_pages(addr, get_order(size));
-}
-
-EXPORT_SYMBOL(dma_free_noncoherent);
-
-void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-       dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent")));
-
-EXPORT_SYMBOL(dma_free_coherent);
-
-dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-       enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       return dev_to_baddr(dev, __pa(ptr));
-}
-
-EXPORT_SYMBOL(dma_map_single);
-
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-                enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_unmap_single);
-
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-       enum dma_data_direction direction)
-{
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-
-       for (i = 0; i < nents; i++, sg++) {
-               sg->dma_address = (dma_addr_t) dev_to_baddr(dev,
-                       page_to_phys(sg->page) + sg->offset);
-       }
-
-       return nents;
-}
-
-EXPORT_SYMBOL(dma_map_sg);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-       unsigned long offset, size_t size, enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       return dev_to_baddr(dev, page_to_phys(page) + offset);
-}
-
-EXPORT_SYMBOL(dma_map_page);
-
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_unmap_page);
-
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-            enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_unmap_sg);
-
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_for_cpu);
-
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_for_device);
-
-void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                     unsigned long offset, size_t size,
-                     enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-
-void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-                     unsigned long offset, size_t size,
-                     enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
-
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-                enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
-
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-                enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_sync_sg_for_device);
-
-int dma_mapping_error(dma_addr_t dma_addr)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(dma_mapping_error);
-
-int dma_supported(struct device *dev, u64 mask)
-{
-       /*
-        * we fall back to GFP_DMA when the mask isn't all 1s,
-        * so we can't guarantee allocations that must be
-        * within a tighter range than GFP_DMA..
-        */
-       if (mask < 0x00ffffff)
-               return 0;
-
-       return 1;
-}
-
-EXPORT_SYMBOL(dma_supported);
-
-int dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
-{
-       return 1;
-}
-
-EXPORT_SYMBOL(dma_is_consistent);
-
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-              enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-}
-
-EXPORT_SYMBOL(dma_cache_sync);
-
-dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
-       struct page *page, unsigned long offset, int direction)
-{
-       dma64_addr_t addr = page_to_phys(page) + offset;
-
-       return (dma64_addr_t) pdev_to_baddr(pdev, addr);
-}
-
-EXPORT_SYMBOL(pci_dac_page_to_dma);
-
-struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
-       dma64_addr_t dma_addr)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus);
-
-       return pfn_to_page((dma_addr - bc->baddr) >> PAGE_SHIFT);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_page);
-
-unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
-       dma64_addr_t dma_addr)
-{
-       return dma_addr & ~PAGE_MASK;
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_offset);
-
-void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
-       dma64_addr_t dma_addr, size_t len, int direction)
-{
-       BUG_ON(direction == PCI_DMA_NONE);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
-
-void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
-       dma64_addr_t dma_addr, size_t len, int direction)
-{
-       BUG_ON(direction == PCI_DMA_NONE);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
diff --git a/arch/mips/mm/dma-ip32.c b/arch/mips/mm/dma-ip32.c
deleted file mode 100644 (file)
index b42b6f7..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
- * Copyright (C) 2000, 2001  Ralf Baechle <ralf@gnu.org>
- * Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
- * IP32 changes by Ilya.
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/cache.h>
-#include <asm/io.h>
-#include <asm/ip32/crime.h>
-
-/*
- * Warning on the terminology - Linux calls an uncached area coherent;
- * MIPS terminology calls memory areas with hardware maintained coherency
- * coherent.
- */
-
-/*
- * Few notes.
- * 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M
- * 2. PCI sees memory as one big chunk @0x0 (or we could use 0x40000000 for native-endian)
- * 3. All other devices see memory as one big chunk at 0x40000000
- * 4. Non-PCI devices will pass NULL as struct device*
- * Thus we translate differently, depending on device.
- */
-
-#define RAM_OFFSET_MASK        0x3fffffff
-
-void *dma_alloc_noncoherent(struct device *dev, size_t size,
-       dma_addr_t * dma_handle, gfp_t gfp)
-{
-       void *ret;
-       /* ignore region specifiers */
-       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-
-       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-               gfp |= GFP_DMA;
-       ret = (void *) __get_free_pages(gfp, get_order(size));
-
-       if (ret != NULL) {
-               unsigned long addr = virt_to_phys(ret)&RAM_OFFSET_MASK;
-               memset(ret, 0, size);
-               if(dev==NULL)
-                   addr+= CRIME_HI_MEM_BASE;
-               *dma_handle = addr;
-       }
-
-       return ret;
-}
-
-EXPORT_SYMBOL(dma_alloc_noncoherent);
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-       dma_addr_t * dma_handle, gfp_t gfp)
-{
-       void *ret;
-
-       ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
-       if (ret) {
-               dma_cache_wback_inv((unsigned long) ret, size);
-               ret = UNCAC_ADDR(ret);
-       }
-
-       return ret;
-}
-
-EXPORT_SYMBOL(dma_alloc_coherent);
-
-void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-       dma_addr_t dma_handle)
-{
-       free_pages((unsigned long) vaddr, get_order(size));
-}
-
-EXPORT_SYMBOL(dma_free_noncoherent);
-
-void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-       dma_addr_t dma_handle)
-{
-       unsigned long addr = (unsigned long) vaddr;
-
-       addr = CAC_ADDR(addr);
-       free_pages(addr, get_order(size));
-}
-
-EXPORT_SYMBOL(dma_free_coherent);
-
-static inline void __dma_sync(unsigned long addr, size_t size,
-       enum dma_data_direction direction)
-{
-       switch (direction) {
-       case DMA_TO_DEVICE:
-               dma_cache_wback(addr, size);
-               break;
-
-       case DMA_FROM_DEVICE:
-               dma_cache_inv(addr, size);
-               break;
-
-       case DMA_BIDIRECTIONAL:
-               dma_cache_wback_inv(addr, size);
-               break;
-
-       default:
-               BUG();
-       }
-}
-
-dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-       enum dma_data_direction direction)
-{
-       unsigned long addr = (unsigned long) ptr;
-
-       switch (direction) {
-       case DMA_TO_DEVICE:
-               dma_cache_wback(addr, size);
-               break;
-
-       case DMA_FROM_DEVICE:
-               dma_cache_inv(addr, size);
-               break;
-
-       case DMA_BIDIRECTIONAL:
-               dma_cache_wback_inv(addr, size);
-               break;
-
-       default:
-               BUG();
-       }
-
-       addr = virt_to_phys(ptr)&RAM_OFFSET_MASK;
-       if(dev == NULL)
-           addr+=CRIME_HI_MEM_BASE;
-       return (dma_addr_t)addr;
-}
-
-EXPORT_SYMBOL(dma_map_single);
-
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-       enum dma_data_direction direction)
-{
-       switch (direction) {
-       case DMA_TO_DEVICE:
-               break;
-
-       case DMA_FROM_DEVICE:
-               break;
-
-       case DMA_BIDIRECTIONAL:
-               break;
-
-       default:
-               BUG();
-       }
-}
-
-EXPORT_SYMBOL(dma_unmap_single);
-
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-       enum dma_data_direction direction)
-{
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-
-       for (i = 0; i < nents; i++, sg++) {
-               unsigned long addr;
-
-               addr = (unsigned long) page_address(sg->page)+sg->offset;
-               if (addr)
-                       __dma_sync(addr, sg->length, direction);
-               addr = __pa(addr)&RAM_OFFSET_MASK;
-               if(dev == NULL)
-                       addr +=  CRIME_HI_MEM_BASE;
-               sg->dma_address = (dma_addr_t)addr;
-       }
-
-       return nents;
-}
-
-EXPORT_SYMBOL(dma_map_sg);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-       unsigned long offset, size_t size, enum dma_data_direction direction)
-{
-       unsigned long addr;
-
-       BUG_ON(direction == DMA_NONE);
-
-       addr = (unsigned long) page_address(page) + offset;
-       dma_cache_wback_inv(addr, size);
-       addr = __pa(addr)&RAM_OFFSET_MASK;
-       if(dev == NULL)
-               addr +=  CRIME_HI_MEM_BASE;
-
-       return (dma_addr_t)addr;
-}
-
-EXPORT_SYMBOL(dma_map_page);
-
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-       enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       if (direction != DMA_TO_DEVICE) {
-               unsigned long addr;
-
-               dma_address&=RAM_OFFSET_MASK;
-               addr = dma_address + PAGE_OFFSET;
-               if(dma_address>=256*1024*1024)
-                       addr+=CRIME_HI_MEM_BASE;
-               dma_cache_wback_inv(addr, size);
-       }
-}
-
-EXPORT_SYMBOL(dma_unmap_page);
-
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-       enum dma_data_direction direction)
-{
-       unsigned long addr;
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-
-       if (direction == DMA_TO_DEVICE)
-               return;
-
-       for (i = 0; i < nhwentries; i++, sg++) {
-               addr = (unsigned long) page_address(sg->page);
-               if (!addr)
-                       continue;
-               dma_cache_wback_inv(addr + sg->offset, sg->length);
-       }
-}
-
-EXPORT_SYMBOL(dma_unmap_sg);
-
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-       size_t size, enum dma_data_direction direction)
-{
-       unsigned long addr;
-
-       BUG_ON(direction == DMA_NONE);
-
-       dma_handle&=RAM_OFFSET_MASK;
-       addr = dma_handle + PAGE_OFFSET;
-       if(dma_handle>=256*1024*1024)
-           addr+=CRIME_HI_MEM_BASE;
-       __dma_sync(addr, size, direction);
-}
-
-EXPORT_SYMBOL(dma_sync_single_for_cpu);
-
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-       size_t size, enum dma_data_direction direction)
-{
-       unsigned long addr;
-
-       BUG_ON(direction == DMA_NONE);
-
-       dma_handle&=RAM_OFFSET_MASK;
-       addr = dma_handle + PAGE_OFFSET;
-       if(dma_handle>=256*1024*1024)
-           addr+=CRIME_HI_MEM_BASE;
-       __dma_sync(addr, size, direction);
-}
-
-EXPORT_SYMBOL(dma_sync_single_for_device);
-
-void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-       unsigned long offset, size_t size, enum dma_data_direction direction)
-{
-       unsigned long addr;
-
-       BUG_ON(direction == DMA_NONE);
-
-       dma_handle&=RAM_OFFSET_MASK;
-       addr = dma_handle + offset + PAGE_OFFSET;
-       if(dma_handle>=256*1024*1024)
-           addr+=CRIME_HI_MEM_BASE;
-       __dma_sync(addr, size, direction);
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-
-void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-       unsigned long offset, size_t size, enum dma_data_direction direction)
-{
-       unsigned long addr;
-
-       BUG_ON(direction == DMA_NONE);
-
-       dma_handle&=RAM_OFFSET_MASK;
-       addr = dma_handle + offset + PAGE_OFFSET;
-       if(dma_handle>=256*1024*1024)
-           addr+=CRIME_HI_MEM_BASE;
-       __dma_sync(addr, size, direction);
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
-
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-       enum dma_data_direction direction)
-{
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-
-       /* Make sure that gcc doesn't leave the empty loop body.  */
-       for (i = 0; i < nelems; i++, sg++)
-               __dma_sync((unsigned long)page_address(sg->page),
-                          sg->length, direction);
-}
-
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
-
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-       enum dma_data_direction direction)
-{
-       int i;
-
-       BUG_ON(direction == DMA_NONE);
-
-       /* Make sure that gcc doesn't leave the empty loop body.  */
-       for (i = 0; i < nelems; i++, sg++)
-               __dma_sync((unsigned long)page_address(sg->page),
-                          sg->length, direction);
-}
-
-EXPORT_SYMBOL(dma_sync_sg_for_device);
-
-int dma_mapping_error(dma_addr_t dma_addr)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(dma_mapping_error);
-
-int dma_supported(struct device *dev, u64 mask)
-{
-       /*
-        * we fall back to GFP_DMA when the mask isn't all 1s,
-        * so we can't guarantee allocations that must be
-        * within a tighter range than GFP_DMA..
-        */
-       if (mask < 0x00ffffff)
-               return 0;
-
-       return 1;
-}
-
-EXPORT_SYMBOL(dma_supported);
-
-int dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
-{
-       return 1;
-}
-
-EXPORT_SYMBOL(dma_is_consistent);
-
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-       enum dma_data_direction direction)
-{
-       if (direction == DMA_NONE)
-               return;
-
-       dma_cache_wback_inv((unsigned long)vaddr, size);
-}
-
-EXPORT_SYMBOL(dma_cache_sync);
-
index 82b20c2..bf85995 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the PCI specific kernel interface routines under Linux.
 #
 
-obj-y                          += pci.o
+obj-y                          += pci.o pci-dac.o
 
 #
 # PCI bus host bridge specific code
diff --git a/arch/mips/pci/pci-dac.c b/arch/mips/pci/pci-dac.c
new file mode 100644 (file)
index 0000000..0f0ea1b
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
+ * Copyright (C) 2000, 2001, 06  Ralf Baechle <ralf@linux-mips.org>
+ * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
+ */
+
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/cache.h>
+#include <asm/io.h>
+
+#include <dma-coherence.h>
+
+#include <linux/pci.h>
+
+dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
+       struct page *page, unsigned long offset, int direction)
+{
+       struct device *dev = &pdev->dev;
+
+       BUG_ON(direction == DMA_NONE);
+
+       if (!plat_device_is_coherent(dev)) {
+               unsigned long addr;
+
+               addr = (unsigned long) page_address(page) + offset;
+               dma_cache_wback_inv(addr, PAGE_SIZE);
+       }
+
+       return plat_map_dma_mem_page(dev, page) + offset;
+}
+
+EXPORT_SYMBOL(pci_dac_page_to_dma);
+
+struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
+       dma64_addr_t dma_addr)
+{
+       return pfn_to_page(plat_dma_addr_to_phys(dma_addr) >> PAGE_SHIFT);
+}
+
+EXPORT_SYMBOL(pci_dac_dma_to_page);
+
+unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
+       dma64_addr_t dma_addr)
+{
+       return dma_addr & ~PAGE_MASK;
+}
+
+EXPORT_SYMBOL(pci_dac_dma_to_offset);
+
+void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
+       dma64_addr_t dma_addr, size_t len, int direction)
+{
+       BUG_ON(direction == PCI_DMA_NONE);
+
+       if (!plat_device_is_coherent(&pdev->dev))
+               dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
+}
+
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
+
+void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
+       dma64_addr_t dma_addr, size_t len, int direction)
+{
+       BUG_ON(direction == PCI_DMA_NONE);
+
+       if (!plat_device_is_coherent(&pdev->dev))
+               dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
+}
+
+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
index c1a2409..8578869 100644 (file)
@@ -69,7 +69,10 @@ static __inline__ void atomic_add(int i, atomic_t * v)
                "1:     ll      %0, %1          # atomic_add            \n"
                "       addu    %0, %2                                  \n"
                "       sc      %0, %1                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter));
@@ -111,7 +114,10 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
                "1:     ll      %0, %1          # atomic_sub            \n"
                "       subu    %0, %2                                  \n"
                "       sc      %0, %1                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter));
@@ -155,8 +161,11 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
                "1:     ll      %1, %2          # atomic_add_return     \n"
                "       addu    %0, %1, %3                              \n"
                "       sc      %0, %2                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
                "       addu    %0, %1, %3                              \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter)
@@ -204,8 +213,11 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
                "1:     ll      %1, %2          # atomic_sub_return     \n"
                "       subu    %0, %1, %3                              \n"
                "       sc      %0, %2                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
                "       subu    %0, %1, %3                              \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter)
@@ -267,10 +279,13 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
                "       bltz    %0, 1f                                  \n"
                "       sc      %0, %2                                  \n"
                "       .set    noreorder                               \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
                "        subu   %0, %1, %3                              \n"
                "       .set    reorder                                 \n"
                "1:                                                     \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter)
@@ -429,7 +444,10 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
                "1:     lld     %0, %1          # atomic64_add          \n"
                "       addu    %0, %2                                  \n"
                "       scd     %0, %1                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter));
@@ -471,7 +489,10 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
                "1:     lld     %0, %1          # atomic64_sub          \n"
                "       subu    %0, %2                                  \n"
                "       scd     %0, %1                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter));
@@ -515,8 +536,11 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
                "1:     lld     %1, %2          # atomic64_add_return   \n"
                "       addu    %0, %1, %3                              \n"
                "       scd     %0, %2                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
                "       addu    %0, %1, %3                              \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter)
@@ -564,8 +588,11 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
                "1:     lld     %1, %2          # atomic64_sub_return   \n"
                "       subu    %0, %1, %3                              \n"
                "       scd     %0, %2                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
                "       subu    %0, %1, %3                              \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter)
@@ -627,10 +654,13 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
                "       bltz    %0, 1f                                  \n"
                "       scd     %0, %2                                  \n"
                "       .set    noreorder                               \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
                "        dsubu  %0, %1, %3                              \n"
                "       .set    reorder                                 \n"
                "1:                                                     \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp), "=m" (v->counter)
                : "Ir" (i), "m" (v->counter)
index 06445de..06c0822 100644 (file)
@@ -68,7 +68,10 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
                "1:     " __LL "%0, %1                  # set_bit       \n"
                "       or      %0, %2                                  \n"
                "       " __SC  "%0, %1                                 \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (temp), "=m" (*m)
                : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
@@ -116,7 +119,10 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
                "1:     " __LL "%0, %1                  # clear_bit     \n"
                "       and     %0, %2                                  \n"
                "       " __SC "%0, %1                                  \n"
-               "       beqz    %0, 1b                                  \n"
+               "       beqz    %0, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (temp), "=m" (*m)
                : "ir" (~(1UL << (nr & SZLONG_MASK))), "m" (*m));
@@ -166,7 +172,10 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
                "1:     " __LL "%0, %1          # change_bit    \n"
                "       xor     %0, %2                          \n"
                "       " __SC  "%0, %1                         \n"
-               "       beqz    %0, 1b                          \n"
+               "       beqz    %0, 2f                          \n"
+               "       .subsection 2                           \n"
+               "2:     b       1b                              \n"
+               "       .previous                               \n"
                "       .set    mips0                           \n"
                : "=&r" (temp), "=m" (*m)
                : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
@@ -222,8 +231,12 @@ static inline int test_and_set_bit(unsigned long nr,
                "1:     " __LL "%0, %1          # test_and_set_bit      \n"
                "       or      %2, %0, %3                              \n"
                "       " __SC  "%2, %1                                 \n"
-               "       beqz    %2, 1b                                  \n"
+               "       beqz    %2, 2f                                  \n"
                "        and    %2, %0, %3                              \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    pop                                     \n"
                : "=&r" (temp), "=m" (*m), "=&r" (res)
                : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
@@ -290,8 +303,12 @@ static inline int test_and_clear_bit(unsigned long nr,
                "       or      %2, %0, %3                              \n"
                "       xor     %2, %3                                  \n"
                "       " __SC  "%2, %1                                 \n"
-               "       beqz    %2, 1b                                  \n"
+               "       beqz    %2, 2f                                  \n"
                "        and    %2, %0, %3                              \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    pop                                     \n"
                : "=&r" (temp), "=m" (*m), "=&r" (res)
                : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
@@ -356,8 +373,12 @@ static inline int test_and_change_bit(unsigned long nr,
                "1:     " __LL  "%0, %1         # test_and_change_bit   \n"
                "       xor     %2, %0, %3                              \n"
                "       " __SC  "\t%2, %1                               \n"
-               "       beqz    %2, 1b                                  \n"
+               "       beqz    %2, 2f                                  \n"
                "        and    %2, %0, %3                              \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    pop                                     \n"
                : "=&r" (temp), "=m" (*m), "=&r" (res)
                : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
diff --git a/include/asm-mips/compat-signal.h b/include/asm-mips/compat-signal.h
new file mode 100644 (file)
index 0000000..6720770
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __ASM_COMPAT_SIGNAL_H
+#define __ASM_COMPAT_SIGNAL_H
+
+#include <linux/bug.h>
+#include <linux/compat.h>
+#include <linux/compiler.h>
+
+static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d,
+       const sigset_t *s)
+{
+       int err;
+
+       BUG_ON(sizeof(*d) != sizeof(*s));
+       BUG_ON(_NSIG_WORDS != 2);
+
+       err  = __put_user(s->sig[0],       &d->sig[0]);
+       err |= __put_user(s->sig[0] >> 32, &d->sig[1]);
+       err |= __put_user(s->sig[1],       &d->sig[2]);
+       err |= __put_user(s->sig[1] >> 32, &d->sig[3]);
+
+       return err;
+}
+
+static inline int __copy_conv_sigset_from_user(sigset_t *d,
+       const compat_sigset_t __user *s)
+{
+       int err;
+       union sigset_u {
+               sigset_t        s;
+               compat_sigset_t c;
+       } *u = (union sigset_u *) d;
+
+       BUG_ON(sizeof(*d) != sizeof(*s));
+       BUG_ON(_NSIG_WORDS != 2);
+
+       if (unlikely(!access_ok(VERIFY_READ, d, sizeof(*d))))
+               return -EFAULT;
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       err  = __get_user(u->c.sig[1], &s->sig[0]);
+       err |= __get_user(u->c.sig[0], &s->sig[1]);
+       err |= __get_user(u->c.sig[3], &s->sig[2]);
+       err |= __get_user(u->c.sig[2], &s->sig[3]);
+#endif
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+       err  = __get_user(u->c.sig[0], &s->sig[0]);
+       err |= __get_user(u->c.sig[1], &s->sig[1]);
+       err |= __get_user(u->c.sig[2], &s->sig[2]);
+       err |= __get_user(u->c.sig[3], &s->sig[3]);
+#endif
+
+       return err;
+}
+
+#endif /* __ASM_COMPAT_SIGNAL_H */
index 236d1a4..230b3f1 100644 (file)
@@ -68,6 +68,7 @@ extern int dma_is_consistent(struct device *dev, dma_addr_t dma_addr);
 extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
               enum dma_data_direction direction);
 
+#if 0
 #define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
 
 extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
@@ -75,5 +76,6 @@ extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
 extern void dma_release_declared_memory(struct device *dev);
 extern void * dma_mark_declared_memory_occupied(struct device *dev,
        dma_addr_t device_addr, size_t size);
+#endif
 
 #endif /* _ASM_DMA_MAPPING_H */
diff --git a/include/asm-mips/mach-generic/dma-coherence.h b/include/asm-mips/mach-generic/dma-coherence.h
new file mode 100644 (file)
index 0000000..df71822
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006  Ralf Baechle <ralf@linux-mips.org>
+ *
+ */
+#ifndef __ASM_MACH_GENERIC_DMA_COHERENCE_H
+#define __ASM_MACH_GENERIC_DMA_COHERENCE_H
+
+struct device;
+
+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
+{
+       return virt_to_phys(addr);
+}
+
+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+{
+       return page_to_phys(page);
+}
+
+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
+{
+       return dma_addr;
+}
+
+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
+{
+}
+
+static inline int plat_device_is_coherent(struct device *dev)
+{
+#ifdef CONFIG_DMA_COHERENT
+       return 1;
+#endif
+#ifdef CONFIG_DMA_NONCOHERENT
+       return 0;
+#endif
+}
+
+#endif /* __ASM_MACH_GENERIC_DMA_COHERENCE_H */
index 410ab5f..b8e6deb 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef CONFIG_DMA_COHERENT
 /*
  * Total overkill for most systems but need as a safe default.
+ * Set this one if any device in the system might do non-coherent DMA.
  */
 #define ARCH_KMALLOC_MINALIGN  128
 #endif
diff --git a/include/asm-mips/mach-ip27/dma-coherence.h b/include/asm-mips/mach-ip27/dma-coherence.h
new file mode 100644 (file)
index 0000000..659816e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006  Ralf Baechle <ralf@linux-mips.org>
+ *
+ */
+#ifndef __ASM_MACH_IP27_DMA_COHERENCE_H
+#define __ASM_MACH_IP27_DMA_COHERENCE_H
+
+#include <asm/pci/bridge.h>
+
+#define pdev_to_baddr(pdev, addr) \
+       (BRIDGE_CONTROLLER(pdev->bus)->baddr + (addr))
+#define dev_to_baddr(dev, addr) \
+       pdev_to_baddr(to_pci_dev(dev), (addr))
+
+struct device;
+
+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
+{
+       dma_addr_t pa = dev_to_baddr(dev, virt_to_phys(addr));
+
+       return pa;
+}
+
+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+{
+       dma_addr_t pa = dev_to_baddr(dev, page_to_phys(page));
+
+       return pa;
+}
+
+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
+{
+       return dma_addr & (0xffUL << 56);
+}
+
+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
+{
+}
+
+static inline int plat_device_is_coherent(struct device *dev)
+{
+       return 1;               /* IP27 non-cohernet mode is unsupported */
+}
+
+#endif /* __ASM_MACH_IP27_DMA_COHERENCE_H */
diff --git a/include/asm-mips/mach-ip32/dma-coherence.h b/include/asm-mips/mach-ip32/dma-coherence.h
new file mode 100644 (file)
index 0000000..950be17
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006  Ralf Baechle <ralf@linux-mips.org>
+ *
+ */
+#ifndef __ASM_MACH_IP35_DMA_COHERENCE_H
+#define __ASM_MACH_IP35_DMA_COHERENCE_H
+
+#include <asm/ip32/crime.h>
+
+struct device;
+
+/*
+ * Few notes.
+ * 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M
+ * 2. PCI sees memory as one big chunk @0x0 (or we could use 0x40000000 for
+ *    native-endian)
+ * 3. All other devices see memory as one big chunk at 0x40000000
+ * 4. Non-PCI devices will pass NULL as struct device*
+ *
+ * Thus we translate differently, depending on device.
+ */
+
+#define RAM_OFFSET_MASK 0x3fffffffUL
+
+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
+{
+       dma_addr_t pa = virt_to_phys(addr) & RAM_OFFSET_MASK;
+
+       if (dev == NULL)
+               pa += CRIME_HI_MEM_BASE;
+
+       return pa;
+}
+
+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+{
+       dma_addr_t pa;
+
+       pa = page_to_phys(page) & RAM_OFFSET_MASK;
+
+       if (dev == NULL)
+               pa += CRIME_HI_MEM_BASE;
+
+       return pa;
+}
+
+/* This is almost certainly wrong but it's what dma-ip32.c used to use  */
+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
+{
+       unsigned long addr = dma_addr & RAM_OFFSET_MASK;
+
+       if (dma_addr >= 256*1024*1024)
+               addr += CRIME_HI_MEM_BASE;
+
+       return addr;
+}
+
+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
+{
+}
+
+static inline int plat_device_is_coherent(struct device *dev)
+{
+       return 0;               /* IP32 is non-cohernet */
+}
+
+#endif /* __ASM_MACH_IP35_DMA_COHERENCE_H */
diff --git a/include/asm-mips/mach-jazz/dma-coherence.h b/include/asm-mips/mach-jazz/dma-coherence.h
new file mode 100644 (file)
index 0000000..d66979a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006  Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MACH_JAZZ_DMA_COHERENCE_H
+#define __ASM_MACH_JAZZ_DMA_COHERENCE_H
+
+#include <asm/jazzdma.h>
+
+struct device;
+
+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
+{
+       return vdma_alloc(virt_to_phys(addr), size);
+}
+
+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+{
+       return vdma_alloc(page_to_phys(page), PAGE_SIZE);
+}
+
+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
+{
+       return vdma_log2phys(dma_addr);
+}
+
+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
+{
+       vdma_free(dma_addr);
+}
+
+static inline int plat_device_is_coherent(struct device *dev)
+{
+       return 0;
+}
+
+#endif /* __ASM_MACH_JAZZ_DMA_COHERENCE_H */
index fc3217f..f1755d2 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1999, 2000, 06 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 06 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #ifndef _ASM_SPINLOCK_H
@@ -49,11 +49,18 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                __asm__ __volatile__(
                "       .set    noreorder       # __raw_spin_lock       \n"
                "1:     ll      %1, %2                                  \n"
-               "       bnez    %1, 1b                                  \n"
+               "       bnez    %1, 2f                                  \n"
                "        li     %1, 1                                   \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
+               "       beqz    %1, 2f                                  \n"
                "        nop                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     ll      %1, %2                                  \n"
+               "       bnez    %1, 2b                                  \n"
+               "        li     %1, 1                                   \n"
+               "       b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (lock->lock), "=&r" (tmp)
                : "m" (lock->lock)
@@ -99,8 +106,12 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
                "1:     ll      %0, %3                                  \n"
                "       ori     %2, %0, 1                               \n"
                "       sc      %2, %1                                  \n"
-               "       beqz    %2, 1b                                  \n"
+               "       beqz    %2, 2f                                  \n"
                "        andi   %2, %0, 1                               \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder"
                : "=&r" (temp), "=m" (lock->lock), "=&r" (res)
                : "m" (lock->lock)
@@ -154,11 +165,18 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
                __asm__ __volatile__(
                "       .set    noreorder       # __raw_read_lock       \n"
                "1:     ll      %1, %2                                  \n"
-               "       bltz    %1, 1b                                  \n"
+               "       bltz    %1, 2f                                  \n"
                "        addu   %1, 1                                   \n"
                "       sc      %1, %0                                  \n"
                "       beqz    %1, 1b                                  \n"
                "        nop                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     ll      %1, %2                                  \n"
+               "       bltz    %1, 2b                                  \n"
+               "        addu   %1, 1                                   \n"
+               "       b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
@@ -192,8 +210,12 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
                "1:     ll      %1, %2                                  \n"
                "       sub     %1, 1                                   \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
+               "       beqz    %1, 2f                                  \n"
+               "        nop                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
                "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
@@ -222,11 +244,18 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
                __asm__ __volatile__(
                "       .set    noreorder       # __raw_write_lock      \n"
                "1:     ll      %1, %2                                  \n"
-               "       bnez    %1, 1b                                  \n"
+               "       bnez    %1, 2f                                  \n"
                "        lui    %1, 0x8000                              \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
+               "       beqz    %1, 2f                                  \n"
+               "        nop                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     ll      %1, %2                                  \n"
+               "       bnez    %1, 2b                                  \n"
+               "        lui    %1, 0x8000                              \n"
+               "       b       1b                                      \n"
                "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
@@ -322,12 +351,15 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
                "       bnez    %1, 2f                                  \n"
                "       lui     %1, 0x8000                              \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
-               "        nop                                            \n"
+               "       beqz    %1, 3f                                  \n"
+               "        li     %2, 1                                   \n"
+               "2:                                                     \n"
                __WEAK_ORDERING_MB
-               "       li      %2, 1                                   \n"
+               "       .subsection 2                                   \n"
+               "3:     b       1b                                      \n"
+               "        li     %2, 0                                   \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
-               "2:                                                     \n"
                : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
                : "m" (rw->lock)
                : "memory");
index 5e1289c..597a374 100644 (file)
@@ -110,7 +110,10 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
                "       move    %2, %z4                                 \n"
                "       .set    mips3                                   \n"
                "       sc      %2, %1                                  \n"
-               "       beqz    %2, 1b                                  \n"
+               "       beqz    %2, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (retval), "=m" (*m), "=&r" (dummy)
                : "R" (*m), "Jr" (val)
@@ -155,7 +158,10 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
                "1:     lld     %0, %3                  # xchg_u64      \n"
                "       move    %2, %z4                                 \n"
                "       scd     %2, %1                                  \n"
-               "       beqz    %2, 1b                                  \n"
+               "       beqz    %2, 2f                                  \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    mips0                                   \n"
                : "=&r" (retval), "=m" (*m), "=&r" (dummy)
                : "R" (*m), "Jr" (val)
@@ -232,8 +238,11 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
                "       move    $1, %z4                                 \n"
                "       .set    mips3                                   \n"
                "       sc      $1, %1                                  \n"
-               "       beqz    $1, 1b                                  \n"
+               "       beqz    $1, 3f                                  \n"
                "2:                                                     \n"
+               "       .subsection 2                                   \n"
+               "3:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    pop                                     \n"
                : "=&r" (retval), "=R" (*m)
                : "R" (*m), "Jr" (old), "Jr" (new)
@@ -283,8 +292,11 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
                "       bne     %0, %z3, 2f                             \n"
                "       move    $1, %z4                                 \n"
                "       scd     $1, %1                                  \n"
-               "       beqz    $1, 1b                                  \n"
+               "       beqz    $1, 3f                                  \n"
                "2:                                                     \n"
+               "       .subsection 2                                   \n"
+               "3:     b       1b                                      \n"
+               "       .previous                                       \n"
                "       .set    pop                                     \n"
                : "=&r" (retval), "=R" (*m)
                : "R" (*m), "Jr" (old), "Jr" (new)
index 825fcbd..3eff8d8 100644 (file)
@@ -265,10 +265,14 @@ do {                                                                      \
  */
 #define __get_user_asm_ll32(val, addr)                                 \
 {                                                                      \
+       union {                                                         \
+               unsigned long long      l;                              \
+               __typeof__(*(addr))     t;                              \
+       } __gu_tmp;                                                     \
+                                                                       \
        __asm__ __volatile__(                                           \
        "1:     lw      %1, (%3)                                \n"     \
        "2:     lw      %D1, 4(%3)                              \n"     \
-       "       move    %0, $0                                  \n"     \
        "3:     .section        .fixup,\"ax\"                   \n"     \
        "4:     li      %0, %4                                  \n"     \
        "       move    %1, $0                                  \n"     \
@@ -279,8 +283,10 @@ do {                                                                       \
        "       " __UA_ADDR "   1b, 4b                          \n"     \
        "       " __UA_ADDR "   2b, 4b                          \n"     \
        "       .previous                                       \n"     \
-       : "=r" (__gu_err), "=&r" (val)                                  \
+       : "=r" (__gu_err), "=&r" (__gu_tmp.l)                           \
        : "0" (0), "r" (addr), "i" (-EFAULT));                          \
+                                                                       \
+       (val) = __gu_tmp.t;                                             \
 }
 
 /*