From f65e4fa8e0c6022ad58dc88d1b11b12589ed7f9f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 28 Sep 2006 01:45:21 +0100 Subject: [PATCH 01/15] [MIPS] Improve branch prediction in ll/sc atomic operations. Now that finally all supported versions of binutils have functioning support for .subsection use .subsection to tweak the branch prediction I did not modify the R10000 errata variants because it seems unclear if this will invalidate the workaround which actually relies on the cheesy prediction of branch likely to cause a misspredict if the sc was successful. Signed-off-by: Ralf Baechle --- include/asm-mips/atomic.h | 50 +++++++++++++++++++++++++------- include/asm-mips/bitops.h | 33 +++++++++++++++++---- include/asm-mips/spinlock.h | 58 ++++++++++++++++++++++++++++--------- include/asm-mips/system.h | 20 ++++++++++--- 4 files changed, 128 insertions(+), 33 deletions(-) diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h index c1a2409bb52a..8578869a8bcf 100644 --- a/include/asm-mips/atomic.h +++ b/include/asm-mips/atomic.h @@ -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) diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index 06445de1324b..06c08228a525 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -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/spinlock.h b/include/asm-mips/spinlock.h index fc3217fc1118..f1755d28a36a 100644 --- a/include/asm-mips/spinlock.h +++ b/include/asm-mips/spinlock.h @@ -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" - __WEAK_ORDERING_MB - " li %2, 1 \n" - " .set reorder \n" + " beqz %1, 3f \n" + " li %2, 1 \n" "2: \n" + __WEAK_ORDERING_MB + " .subsection 2 \n" + "3: b 1b \n" + " li %2, 0 \n" + " .previous \n" + " .set reorder \n" : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) : "m" (rw->lock) : "memory"); diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 5e1289c85ed9..597a3743f6a1 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -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) From 9a88cbb5227970757881b1a65be01dea61fe2584 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 16 Nov 2006 02:56:12 +0000 Subject: [PATCH 02/15] [MIPS] Unify dma-{coherent,noncoherent.ip27,ip32} Platforms will now have to supply a function dma_device_is_coherent which returns if a particular device participates in the coherence domain. For most platforms this function will always return 0 or 1. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 5 - arch/mips/mm/Makefile | 14 +- arch/mips/mm/dma-coherent.c | 254 ------------ .../mm/{dma-noncoherent.c => dma-default.c} | 209 +++++----- arch/mips/mm/dma-ip27.c | 257 ------------ arch/mips/mm/dma-ip32.c | 383 ------------------ arch/mips/pci/Makefile | 2 +- arch/mips/pci/pci-dac.c | 79 ++++ include/asm-mips/mach-generic/dma-coherence.h | 43 ++ include/asm-mips/mach-generic/kmalloc.h | 1 + include/asm-mips/mach-ip27/dma-coherence.h | 49 +++ include/asm-mips/mach-ip32/dma-coherence.h | 71 ++++ include/asm-mips/mach-jazz/dma-coherence.h | 40 ++ 13 files changed, 387 insertions(+), 1020 deletions(-) delete mode 100644 arch/mips/mm/dma-coherent.c rename arch/mips/mm/{dma-noncoherent.c => dma-default.c} (63%) delete mode 100644 arch/mips/mm/dma-ip27.c delete mode 100644 arch/mips/mm/dma-ip32.c create mode 100644 arch/mips/pci/pci-dac.c create mode 100644 include/asm-mips/mach-generic/dma-coherence.h create mode 100644 include/asm-mips/mach-ip27/dma-coherence.h create mode 100644 include/asm-mips/mach-ip32/dma-coherence.h create mode 100644 include/asm-mips/mach-jazz/dma-coherence.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5fe195a41a80..a92ce6bd7cf1 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -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 diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 19e41fd186c4..de5727385bc6 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -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) diff --git a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c deleted file mode 100644 index 5697c6e250a3..000000000000 --- a/arch/mips/mm/dma-coherent.c +++ /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 - * Copyright (C) 2000, 2001 Ralf Baechle - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include -#include -#include -#include -#include - -#include -#include - -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 - -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 */ diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-default.c similarity index 63% rename from arch/mips/mm/dma-noncoherent.c rename to arch/mips/mm/dma-default.c index 8cecef0957c3..4a32e939698f 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-default.c @@ -4,28 +4,39 @@ * for more details. * * Copyright (C) 2000 Ani Joshi - * Copyright (C) 2000, 2001 Ralf Baechle + * Copyright (C) 2000, 2001, 06 Ralf Baechle * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. */ + #include +#include #include #include #include -#include #include #include +#include + /* * 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; - return page_to_phys(page) + offset; + addr = (unsigned long) page_address(page) + offset; + dma_cache_wback_inv(addr, size); + } + + 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 - -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 index f088344db465..000000000000 --- a/arch/mips/mm/dma-ip27.c +++ /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 - * Copyright (C) 2000, 2001 Ralf Baechle - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include -#include -#include -#include -#include - -#include -#include - -#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 index b42b6f7456e6..000000000000 --- a/arch/mips/mm/dma-ip32.c +++ /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 - * Copyright (C) 2000, 2001 Ralf Baechle - * Copyright (C) 2005 Ilya A. Volynets-Evenbakh - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - * IP32 changes by Ilya. - */ -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * 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); - diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 82b20c28bef8..bf85995ca042 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -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 index 000000000000..0f0ea1b7d4dd --- /dev/null +++ b/arch/mips/pci/pci-dac.c @@ -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 + * Copyright (C) 2000, 2001, 06 Ralf Baechle + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +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); diff --git a/include/asm-mips/mach-generic/dma-coherence.h b/include/asm-mips/mach-generic/dma-coherence.h new file mode 100644 index 000000000000..df71822fd27b --- /dev/null +++ b/include/asm-mips/mach-generic/dma-coherence.h @@ -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 + * + */ +#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 */ diff --git a/include/asm-mips/mach-generic/kmalloc.h b/include/asm-mips/mach-generic/kmalloc.h index 410ab5f6c563..b8e6deba352f 100644 --- a/include/asm-mips/mach-generic/kmalloc.h +++ b/include/asm-mips/mach-generic/kmalloc.h @@ -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 index 000000000000..659816e200d4 --- /dev/null +++ b/include/asm-mips/mach-ip27/dma-coherence.h @@ -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 + * + */ +#ifndef __ASM_MACH_IP27_DMA_COHERENCE_H +#define __ASM_MACH_IP27_DMA_COHERENCE_H + +#include + +#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 index 000000000000..950be17bbb86 --- /dev/null +++ b/include/asm-mips/mach-ip32/dma-coherence.h @@ -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 + * + */ +#ifndef __ASM_MACH_IP35_DMA_COHERENCE_H +#define __ASM_MACH_IP35_DMA_COHERENCE_H + +#include + +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 index 000000000000..d66979a124a8 --- /dev/null +++ b/include/asm-mips/mach-jazz/dma-coherence.h @@ -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 + */ +#ifndef __ASM_MACH_JAZZ_DMA_COHERENCE_H +#define __ASM_MACH_JAZZ_DMA_COHERENCE_H + +#include + +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 */ From 84b47a959b55930e86d6178d49769bc9ba34bce1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 12 Feb 2007 22:22:53 +0000 Subject: [PATCH 03/15] [MIPS] Don't claim we support dma_declare_coherent_memory - we don't. Signed-off-by: Ralf Baechle --- include/asm-mips/dma-mapping.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-mips/dma-mapping.h b/include/asm-mips/dma-mapping.h index 236d1a467cc7..230b3f1b69b1 100644 --- a/include/asm-mips/dma-mapping.h +++ b/include/asm-mips/dma-mapping.h @@ -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 */ From cd1fb9eabea38489579284e0cae0c7019b77b10f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 12 Feb 2007 23:12:38 +0000 Subject: [PATCH 04/15] Revert "[MIPS] Fix warning in get_user when fetching pointer object from userspace." This reverts commit 4ed3a77f38c023658784804cb39a7ce18063dc88. --- include/asm-mips/uaccess.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index 825fcbd9eabd..c12ebc53ef31 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -265,6 +265,8 @@ do { \ */ #define __get_user_asm_ll32(val, addr) \ { \ + unsigned long long __gu_tmp; \ + \ __asm__ __volatile__( \ "1: lw %1, (%3) \n" \ "2: lw %D1, 4(%3) \n" \ @@ -279,8 +281,9 @@ do { \ " " __UA_ADDR " 1b, 4b \n" \ " " __UA_ADDR " 2b, 4b \n" \ " .previous \n" \ - : "=r" (__gu_err), "=&r" (val) \ + : "=r" (__gu_err), "=&r" (__gu_tmp) \ : "0" (0), "r" (addr), "i" (-EFAULT)); \ + (val) = (__typeof__(*(addr))) __gu_tmp; \ } /* From af3d10d52d38d2c56a8bca9943c07b00031fc718 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 12 Feb 2007 23:26:01 +0000 Subject: [PATCH 05/15] [MIPS] IP27: Enable N32 support in defconfig. Signed-off-by: Ralf Baechle --- arch/mips/configs/ip27_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 96090f28373b..f21186c12d81 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -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 # From dd02f06aa96ab4590da12704366450a2d4753d3c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 13 Feb 2007 00:50:57 +0000 Subject: [PATCH 06/15] [MIPS] signal: Fix warnings in o32 compat code. Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal32.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 183fc7e55f34..1b9262d3fd23 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -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,10 +513,10 @@ 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))) @@ -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)); From 205d84aaea380bbd1cc1079d44086cd50c2c2dad Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 13 Feb 2007 01:28:09 +0000 Subject: [PATCH 07/15] [MIPS] signal: Move {restore,setup}_sigcontext prototypes to their user Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal-common.h | 6 ------ arch/mips/kernel/signal_n32.c | 4 ++++ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 9a8abd67ec5c..d9a832f67e8a 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -45,12 +45,6 @@ struct sigframe { #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 *); - /* * Determine which stack to use.. */ diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 57456e6a0c62..b17ef04691e3 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -49,6 +49,10 @@ #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 { s32 ss_sp; From 66680583461d7cae281cef63c050c9b6371e3286 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 13 Feb 2007 01:31:48 +0000 Subject: [PATCH 08/15] [MIPS] signal: Move sigframe definition for native O32/N64 into signal.c Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal-common.h | 26 -------------------------- arch/mips/kernel/signal.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index d9a832f67e8a..b95e542ace27 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -19,32 +19,6 @@ # 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 */ - /* * Determine which stack to use.. */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 54398af2371f..e7b04928caec 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -36,8 +36,20 @@ #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 +59,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]; From 24c556e99ec8a61ce1fbc75bee61dc19edf2c4df Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Fri, 9 Feb 2007 16:07:37 +0100 Subject: [PATCH 09/15] [MIPS] signals: make common _BLOCKABLE macro Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal-common.h | 2 ++ arch/mips/kernel/signal.c | 2 -- arch/mips/kernel/signal32.c | 2 -- arch/mips/kernel/signal_n32.c | 2 -- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index b95e542ace27..fdbdbdc65b54 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -19,6 +19,8 @@ # define DEBUGP(fmt, args...) #endif +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * Determine which stack to use.. */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index e7b04928caec..b2e9ab1bb101 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -34,8 +34,6 @@ #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 diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 1b9262d3fd23..db00c333bff3 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -104,8 +104,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 diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index b17ef04691e3..1a5f248faf3b 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -47,8 +47,6 @@ #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 *); From d01f06ef0c783eceb53030fc5407caa94586bd6a Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Mon, 12 Feb 2007 23:48:26 +0900 Subject: [PATCH 10/15] [MIPS] DECstation: Fix irq handling When I post a patch (commit f431baa55abf8adeed0c718b51deacbc151f58f1), I just tried to not change behavior of existing codes, but it seems dec/int-handler.S had been broken since its previous commit 937a801576f954bd030d7c4a5a94571710d87c0b. The caller of plat_irq_dispatch do setup/restore TI_REGS($28), so dec's plat_irq_dispatch should not do it, and there is no need to adjust RA. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/dec/int-handler.S | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index b251ef864c33..00cecdcc75f2 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -264,9 +264,6 @@ 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) From cb66fb3f156b485b22db97db22e96db4786dc68b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 13 Feb 2007 11:45:24 +0000 Subject: [PATCH 11/15] [MIPS] 32-bit: Fix warning about cast for fetching pointer from userspace. Signed-off-by: Ralf Baechle --- include/asm-mips/uaccess.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index c12ebc53ef31..36b3a427f123 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -265,7 +265,10 @@ do { \ */ #define __get_user_asm_ll32(val, addr) \ { \ - unsigned long long __gu_tmp; \ + union { \ + unsigned long long l; \ + __typeof__(*(addr)) t; \ + } __gu_tmp; \ \ __asm__ __volatile__( \ "1: lw %1, (%3) \n" \ @@ -281,9 +284,10 @@ do { \ " " __UA_ADDR " 1b, 4b \n" \ " " __UA_ADDR " 2b, 4b \n" \ " .previous \n" \ - : "=r" (__gu_err), "=&r" (__gu_tmp) \ + : "=r" (__gu_err), "=&r" (__gu_tmp.l) \ : "0" (0), "r" (addr), "i" (-EFAULT)); \ - (val) = (__typeof__(*(addr))) __gu_tmp; \ + \ + (val) = __gu_tmp.t; \ } /* From 6f3aa38e191326a82d5dcae1f6cdc88b1d9a8d32 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 13 Feb 2007 15:01:21 +0000 Subject: [PATCH 12/15] [MIPS] Remove stray instruction from __get_user_asm_ll32. This did result in double clearing of the error return value on success only but should make a meassurable overhead for sigreturn. Signed-off-by: Ralf Baechle --- include/asm-mips/uaccess.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index 36b3a427f123..3eff8d8fe28a 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -273,7 +273,6 @@ do { \ __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" \ From 7da8a581f5ec0ecac5f0afc9ec26ce13b780d48d Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Tue, 13 Feb 2007 14:50:18 +0100 Subject: [PATCH 13/15] [MIPS] Make entry.S a little more readable. When CONFIG_PREEMPT is not set, it also moves one branch instruction from ret_from_irq() to ret_from_exception(). Therefore we favour the return from irq case which should be more common than the other one. Signed-off-by: Franck Bui-Huu Acked-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/entry.S | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index f10b6a19f8bf..0b78fcbf044a 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -21,24 +21,21 @@ #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 +#ifndef CONFIG_PREEMPT +FEXPORT(ret_from_exception) + local_irq_disable # preempt stop + b __ret_from_irq +#endif FEXPORT(ret_from_irq) LONG_S s0, TI_REGS($28) -#ifdef CONFIG_PREEMPT -FEXPORT(ret_from_exception) -#else - b _ret_from_irq -FEXPORT(ret_from_exception) - preempt_stop -#endif -FEXPORT(_ret_from_irq) +FEXPORT(__ret_from_irq) LONG_L t0, PT_STATUS(sp) # returning to kernel mode? andi t0, t0, KU_USER beqz t0, resume_kernel From 366d6aef281a670b32a51d289fc07bf0e5e72d9a Mon Sep 17 00:00:00 2001 From: Andrew Sharp Date: Fri, 9 Feb 2007 17:35:28 -0800 Subject: [PATCH 14/15] [MIPS] Fix uniprocessor Sibyte builds. Signed-off-by: Andrew Sharp Signed-off-by: Ralf Baechle --- arch/mips/mm/c-sb1.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c index 3a8afd47feaa..9ea460b16bda 100644 --- a/arch/mips/mm/c-sb1.c +++ b/arch/mips/mm/c-sb1.c @@ -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 From 431dc8040354db65e4f8d4d4e21ae4fab41f5bc3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 13 Feb 2007 00:05:11 +0000 Subject: [PATCH 15/15] [MIPS] Fix sigset_t endianess swapping issues in 32-bit compat code. Signed-off-by: Ralf Baechle --- arch/mips/kernel/linux32.c | 47 +++++++++++++++++++++++++++ arch/mips/kernel/scall64-64.S | 2 +- arch/mips/kernel/scall64-n32.S | 2 +- arch/mips/kernel/signal32.c | 11 ++++--- arch/mips/kernel/signal_n32.c | 7 ++-- include/asm-mips/compat-signal.h | 55 ++++++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 include/asm-mips/compat-signal.h diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index ca7ad78f4def..fc4dd6c9dd80 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs) return do_fork(clone_flags, newsp, ®s, 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(¤t->saved_sigmask, &sigsaved, + sizeof(sigsaved)); + set_thread_flag(TIF_RESTORE_SIGMASK); + } else + sigprocmask(SIG_SETMASK, &sigsaved, NULL); + } + + return error; +} diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index e569b846e9a3..10e9a18630aa 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -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 diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index ee8802b59758..2ceda4644a4d 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -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 diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index db00c333bff3..c28cb21514c8 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -8,6 +8,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include +#include #include #include #include @@ -517,7 +519,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) 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); @@ -554,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); @@ -609,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; @@ -668,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; diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 1a5f248faf3b..7ca2a078841f 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -63,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 @@ -129,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); @@ -195,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; diff --git a/include/asm-mips/compat-signal.h b/include/asm-mips/compat-signal.h new file mode 100644 index 000000000000..672077084aa1 --- /dev/null +++ b/include/asm-mips/compat-signal.h @@ -0,0 +1,55 @@ +#ifndef __ASM_COMPAT_SIGNAL_H +#define __ASM_COMPAT_SIGNAL_H + +#include +#include +#include + +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 */