Commit 463020ce authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

* '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.
parents 58a3bb59 431dc804
...@@ -598,8 +598,6 @@ config SGI_IP32 ...@@ -598,8 +598,6 @@ config SGI_IP32
select ARC select ARC
select ARC32 select ARC32
select BOOT_ELF32 select BOOT_ELF32
select OWN_DMA
select DMA_IP32
select DMA_NONCOHERENT select DMA_NONCOHERENT
select HW_HAS_PCI select HW_HAS_PCI
select R5000_CPU_SCACHE select R5000_CPU_SCACHE
...@@ -883,9 +881,6 @@ config DMA_NONCOHERENT ...@@ -883,9 +881,6 @@ config DMA_NONCOHERENT
config DMA_NEED_PCI_MAP_STATE config DMA_NEED_PCI_MAP_STATE
bool bool
config OWN_DMA
bool
config EARLY_PRINTK config EARLY_PRINTK
bool bool
......
...@@ -264,7 +264,7 @@ CONFIG_BINFMT_ELF=y ...@@ -264,7 +264,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_MIPS32_COMPAT=y CONFIG_MIPS32_COMPAT=y
CONFIG_COMPAT=y CONFIG_COMPAT=y
CONFIG_MIPS32_O32=y CONFIG_MIPS32_O32=y
# CONFIG_MIPS32_N32 is not set CONFIG_MIPS32_N32=y
CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_ELF32=y
# #
......
...@@ -264,9 +264,6 @@ ...@@ -264,9 +264,6 @@
srlv t3,t1,t2 srlv t3,t1,t2
handle_it: handle_it:
LONG_L s0, TI_REGS($28)
LONG_S sp, TI_REGS($28)
PTR_LA ra, ret_from_irq
j dec_irq_dispatch j dec_irq_dispatch
nop nop
...@@ -277,7 +274,6 @@ fpu: ...@@ -277,7 +274,6 @@ fpu:
#endif #endif
spurious: spurious:
PTR_LA ra, _ret_from_irq
j spurious_interrupt j spurious_interrupt
nop nop
END(plat_irq_dispatch) END(plat_irq_dispatch)
......
...@@ -21,24 +21,21 @@ ...@@ -21,24 +21,21 @@
#endif #endif
#ifndef CONFIG_PREEMPT #ifndef CONFIG_PREEMPT
.macro preempt_stop
local_irq_disable
.endm
#define resume_kernel restore_all #define resume_kernel restore_all
#else
#define __ret_from_irq ret_from_exception
#endif #endif
.text .text
.align 5 .align 5
FEXPORT(ret_from_irq) #ifndef CONFIG_PREEMPT
LONG_S s0, TI_REGS($28)
#ifdef CONFIG_PREEMPT
FEXPORT(ret_from_exception)
#else
b _ret_from_irq
FEXPORT(ret_from_exception) FEXPORT(ret_from_exception)
preempt_stop local_irq_disable # preempt stop
b __ret_from_irq
#endif #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? LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
andi t0, t0, KU_USER andi t0, t0, KU_USER
beqz t0, resume_kernel beqz t0, resume_kernel
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <net/sock.h> #include <net/sock.h>
#include <net/scm.h> #include <net/scm.h>
#include <asm/compat-signal.h>
#include <asm/ipc.h> #include <asm/ipc.h>
#include <asm/sim.h> #include <asm/sim.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs) ...@@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
return do_fork(clone_flags, newsp, &regs, 0, return do_fork(clone_flags, newsp, &regs, 0,
parent_tidptr, child_tidptr); 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;
}
...@@ -470,4 +470,4 @@ sys_call_table: ...@@ -470,4 +470,4 @@ sys_call_table:
PTR sys_get_robust_list PTR sys_get_robust_list
PTR sys_kexec_load /* 5270 */ PTR sys_kexec_load /* 5270 */
PTR sys_getcpu PTR sys_getcpu
PTR sys_epoll_pwait PTR compat_sys_epoll_pwait
...@@ -396,4 +396,4 @@ EXPORT(sysn32_call_table) ...@@ -396,4 +396,4 @@ EXPORT(sysn32_call_table)
PTR compat_sys_get_robust_list PTR compat_sys_get_robust_list
PTR compat_sys_kexec_load PTR compat_sys_kexec_load
PTR sys_getcpu PTR sys_getcpu
PTR sys_epoll_pwait PTR compat_sys_epoll_pwait
...@@ -19,37 +19,7 @@ ...@@ -19,37 +19,7 @@
# define DEBUGP(fmt, args...) # define DEBUGP(fmt, args...)
#endif #endif
/* #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;
};
#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 *);
/* /*
* Determine which stack to use.. * Determine which stack to use..
......
...@@ -34,10 +34,20 @@ ...@@ -34,10 +34,20 @@
#include "signal-common.h" #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 #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 { struct rt_sigframe {
u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_ass[4]; /* argument save space for o32 */
u32 rs_code[2]; /* signal trampoline */ u32 rs_code[2]; /* signal trampoline */
...@@ -47,6 +57,14 @@ struct rt_sigframe { ...@@ -47,6 +57,14 @@ struct rt_sigframe {
#else #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 { struct rt_sigframe {
u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_ass[4]; /* argument save space for o32 */
u32 rs_pad[2]; u32 rs_pad[2];
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/ */
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/compat.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/smp.h> #include <linux/smp.h>
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
#include <asm/abi.h> #include <asm/abi.h>
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/compat-signal.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/sim.h> #include <asm/sim.h>
...@@ -104,8 +106,6 @@ typedef struct compat_siginfo { ...@@ -104,8 +106,6 @@ typedef struct compat_siginfo {
#define __NR_O32_rt_sigreturn 4193 #define __NR_O32_rt_sigreturn 4193
#define __NR_O32_restart_syscall 4253 #define __NR_O32_restart_syscall 4253
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
/* 32-bit compatibility types */ /* 32-bit compatibility types */
#define _NSIG_BPW32 32 #define _NSIG_BPW32 32
...@@ -139,8 +139,20 @@ struct ucontext32 { ...@@ -139,8 +139,20 @@ struct ucontext32 {
sigset_t32 uc_sigmask; /* mask last for extensibility */ 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 #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 { struct rt_sigframe32 {
u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_ass[4]; /* argument save space for o32 */
u32 rs_code[2]; /* signal trampoline */ u32 rs_code[2]; /* signal trampoline */
...@@ -150,6 +162,14 @@ struct rt_sigframe32 { ...@@ -150,6 +162,14 @@ struct rt_sigframe32 {
#else /* ICACHE_REFILLS_WORKAROUND_WAR */ #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 { struct rt_sigframe32 {
u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_ass[4]; /* argument save space for o32 */
u32 rs_pad[2]; u32 rs_pad[2];
...@@ -493,13 +513,13 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) ...@@ -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) asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
{ {
struct sigframe __user *frame; struct sigframe32 __user *frame;
sigset_t blocked; 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))) if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe; goto badframe;
if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
goto badframe; goto badframe;
sigdelsetmask(&blocked, ~_BLOCKABLE); sigdelsetmask(&blocked, ~_BLOCKABLE);
...@@ -536,7 +556,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) ...@@ -536,7 +556,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
frame = (struct rt_sigframe32 __user *) regs.regs[29]; frame = (struct rt_sigframe32 __user *) regs.regs[29];
if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe; 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; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
...@@ -581,7 +601,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) ...@@ -581,7 +601,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
int signr, sigset_t *set) int signr, sigset_t *set)
{ {
struct sigframe __user *frame; struct sigframe32 __user *frame;
int err = 0; int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame));
...@@ -591,7 +611,8 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, ...@@ -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 |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
err |= setup_sigcontext32(regs, &frame->sf_sc); 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) if (err)
goto give_sigsegv; goto give_sigsegv;
...@@ -650,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, ...@@ -650,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
err |= __put_user(current->sas_ss_size, err |= __put_user(current->sas_ss_size,
&frame->rs_uc.uc_stack.ss_size); &frame->rs_uc.uc_stack.ss_size);
err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); 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) if (err)
goto give_sigsegv; goto give_sigsegv;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/compat-signal.h>
#include <asm/sim.h> #include <asm/sim.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ucontext.h> #include <asm/ucontext.h>
...@@ -47,7 +48,9 @@ ...@@ -47,7 +48,9 @@
#define __NR_N32_rt_sigreturn 6211 #define __NR_N32_rt_sigreturn 6211
#define __NR_N32_restart_syscall 6214 #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 */ /* IRIX compatible stack_t */
typedef struct sigaltstack32 { typedef struct sigaltstack32 {
...@@ -61,7 +64,7 @@ struct ucontextn32 { ...@@ -61,7 +64,7 @@ struct ucontextn32 {
s32 uc_link; s32 uc_link;
stack32_t uc_stack; stack32_t uc_stack;
struct sigcontext uc_mcontext; 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 #if ICACHE_REFILLS_WORKAROUND_WAR == 0
...@@ -127,7 +130,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) ...@@ -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]; frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe; 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; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
...@@ -193,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka, ...@@ -193,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
err |= __put_user(current->sas_ss_size, err |= __put_user(current->sas_ss_size,
&frame->rs_uc.uc_stack.ss_size); &frame->rs_uc.uc_stack.ss_size);
err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 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) if (err)
goto give_sigsegv; goto give_sigsegv;
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
# Makefile for the Linux/MIPS-specific parts of the memory manager. # Makefile for the Linux/MIPS-specific parts of the memory manager.
# #
obj-y += cache.o extable.o fault.o init.o pgtable.o \ obj-y += cache.o dma-default.o extable.o fault.o \
tlbex.o tlbex-fault.o init.o pgtable.o tlbex.o tlbex-fault.o
obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o
obj-$(CONFIG_64BIT) += pgtable-64.o obj-$(CONFIG_64BIT) += pgtable-64.o
...@@ -32,14 +32,4 @@ obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o ...@@ -32,14 +32,4 @@ obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.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) EXTRA_AFLAGS := $(CFLAGS)
...@@ -259,6 +259,12 @@ static void sb1_flush_cache_data_page(unsigned long addr) ...@@ -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); on_each_cpu(sb1_flush_cache_data_page_ipi, (void *) addr, 1, 1);
} }
#else #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) void sb1_flush_cache_data_page(unsigned long)
__attribute__((alias("local_sb1_flush_cache_data_page"))); __attribute__((alias("local_sb1_flush_cache_data_page")));
#endif #endif
......
/*
* 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 */
...@@ -4,28 +4,39 @@ ...@@ -4,28 +4,39 @@
* for more details. * for more details.
* *
* Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> * 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. * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/dma-mapping.h>
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/io.h> #include <asm/io.h>
#include <dma-coherence.h>
/* /*
* Warning on the terminology - Linux calls an uncached area coherent; * Warning on the terminology - Linux calls an uncached area coherent;
* MIPS terminology calls memory areas with hardware maintained coherency * MIPS terminology calls memory areas with hardware maintained coherency
* coherent. * 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, void *dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t * dma_handle, gfp_t gfp) dma_addr_t * dma_handle, gfp_t gfp)
{ {
void *ret; void *ret;
/* ignore region specifiers */ /* ignore region specifiers */
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
...@@ -35,7 +46,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, ...@@ -35,7 +46,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size,
if (ret != NULL) { if (ret != NULL) {
memset(ret, 0, size); memset(ret, 0, size);
*dma_handle = virt_to_phys(ret); *dma_handle = plat_map_dma_mem(dev, ret, size);
} }
return ret; return ret;
...@@ -48,11 +59,22 @@ void *dma_alloc_coherent(struct device *dev, size_t size, ...@@ -48,11 +59,22 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
{ {
void *ret; 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) { if (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); dma_cache_wback_inv((unsigned long) ret, size);
ret = UNCAC_ADDR(ret); ret = UNCAC_ADDR(ret);
} }
}
return ret; return ret;
} }
...@@ -72,7 +94,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, ...@@ -72,7 +94,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
{ {
unsigned long addr = (unsigned long) vaddr; unsigned long addr = (unsigned long) vaddr;
if (!plat_device_is_coherent(dev))
addr = CAC_ADDR(addr); addr = CAC_ADDR(addr);
free_pages(addr, get_order(size)); free_pages(addr, get_order(size));
} }
...@@ -104,9 +128,10 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t 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; unsigned long addr = (unsigned long) ptr;
if (!plat_device_is_coherent(dev))
__dma_sync(addr, size, direction); __dma_sync(addr, size, direction);
return virt_to_phys(ptr); return plat_map_dma_mem(dev, ptr, size);
} }
EXPORT_SYMBOL(dma_map_single); EXPORT_SYMBOL(dma_map_single);
...@@ -114,10 +139,11 @@ 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, void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
unsigned long addr; if (cpu_is_noncoherent_r10000(dev))
addr = dma_addr + PAGE_OFFSET; __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); EXPORT_SYMBOL(dma_unmap_single);
...@@ -133,11 +159,10 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -133,11 +159,10 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
unsigned long addr; unsigned long addr;
addr = (unsigned long) page_address(sg->page); addr = (unsigned long) page_address(sg->page);
if (addr) { if (!plat_device_is_coherent(dev) && addr)
__dma_sync(addr + sg->offset, sg->length, direction); __dma_sync(addr + sg->offset, sg->length, direction);
sg->dma_address = (dma_addr_t)page_to_phys(sg->page) sg->dma_address = plat_map_dma_mem_page(dev, sg->page) +
+ sg->offset; sg->offset;
}
} }
return nents; return nents;
...@@ -148,14 +173,16 @@ EXPORT_SYMBOL(dma_map_sg); ...@@ -148,14 +173,16 @@ EXPORT_SYMBOL(dma_map_sg);
dma_addr_t dma_map_page(struct device *dev, struct page *page, 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 offset, size_t size, enum dma_data_direction direction)
{ {
unsigned long addr;
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
if (!plat_device_is_coherent(dev)) {
unsigned long addr;
addr = (unsigned long) page_address(page) + offset; addr = (unsigned long) page_address(page) + offset;
dma_cache_wback_inv(addr, size); 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); EXPORT_SYMBOL(dma_map_page);
...@@ -165,12 +192,14 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ...@@ -165,12 +192,14 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
{ {
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
if (direction != DMA_TO_DEVICE) { if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) {
unsigned long addr; unsigned long addr;
addr = dma_address + PAGE_OFFSET; addr = plat_dma_addr_to_phys(dma_address);
dma_cache_wback_inv(addr, size); dma_cache_wback_inv(addr, size);
} }
plat_unmap_dma_mem(dma_address);
} }
EXPORT_SYMBOL(dma_unmap_page); EXPORT_SYMBOL(dma_unmap_page);
...@@ -183,13 +212,15 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ...@@ -183,13 +212,15 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
if (direction == DMA_TO_DEVICE)
return;
for (i = 0; i < nhwentries; i++, sg++) { for (i = 0; i < nhwentries; i++, sg++) {
if (!plat_device_is_coherent(dev) &&
direction != DMA_TO_DEVICE) {
addr = (unsigned long) page_address(sg->page); addr = (unsigned long) page_address(sg->page);
if (addr) if (addr)
__dma_sync(addr + sg->offset, sg->length, direction); __dma_sync(addr + sg->offset, sg->length,
direction);
}
plat_unmap_dma_mem(sg->dma_address);
} }
} }
...@@ -198,12 +229,14 @@ EXPORT_SYMBOL(dma_unmap_sg); ...@@ -198,12 +229,14 @@ EXPORT_SYMBOL(dma_unmap_sg);
void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction) size_t size, enum dma_data_direction direction)
{ {
unsigned long addr;
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
addr = dma_handle + PAGE_OFFSET; if (cpu_is_noncoherent_r10000(dev)) {
unsigned long addr;
addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle);
__dma_sync(addr, size, direction); __dma_sync(addr, size, direction);
}
} }
EXPORT_SYMBOL(dma_sync_single_for_cpu); EXPORT_SYMBOL(dma_sync_single_for_cpu);
...@@ -211,12 +244,14 @@ 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, void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction) size_t size, enum dma_data_direction direction)
{ {
unsigned long addr;
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
addr = dma_handle + PAGE_OFFSET; if (cpu_is_noncoherent_r10000(dev)) {
unsigned long addr;
addr = plat_dma_addr_to_phys(dma_handle);
__dma_sync(addr, size, direction); __dma_sync(addr, size, direction);
}
} }
EXPORT_SYMBOL(dma_sync_single_for_device); EXPORT_SYMBOL(dma_sync_single_for_device);
...@@ -224,12 +259,14 @@ 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, 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 offset, size_t size, enum dma_data_direction direction)
{ {
unsigned long addr;
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
addr = dma_handle + offset + PAGE_OFFSET; if (cpu_is_noncoherent_r10000(dev)) {
__dma_sync(addr, size, direction); 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); EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
...@@ -237,12 +274,14 @@ 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, 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 offset, size_t size, enum dma_data_direction direction)
{ {
unsigned long addr;
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
addr = dma_handle + offset + PAGE_OFFSET; if (cpu_is_noncoherent_r10000(dev)) {
__dma_sync(addr, size, direction); 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); 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, ...@@ -255,9 +294,12 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
/* Make sure that gcc doesn't leave the empty loop body. */ /* Make sure that gcc doesn't leave the empty loop body. */
for (i = 0; i < nelems; i++, sg++) for (i = 0; i < nelems; i++, sg++) {
if (!plat_device_is_coherent(dev))
__dma_sync((unsigned long)page_address(sg->page), __dma_sync((unsigned long)page_address(sg->page),
sg->length, direction); sg->length, direction);
plat_unmap_dma_mem(sg->dma_address);
}
} }
EXPORT_SYMBOL(dma_sync_sg_for_cpu); 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 ...@@ -270,9 +312,12 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nele
BUG_ON(direction == DMA_NONE); BUG_ON(direction == DMA_NONE);
/* Make sure that gcc doesn't leave the empty loop body. */ /* Make sure that gcc doesn't leave the empty loop body. */
for (i = 0; i < nelems; i++, sg++) for (i = 0; i < nelems; i++, sg++) {
if (!plat_device_is_coherent(dev))
__dma_sync((unsigned long)page_address(sg->page), __dma_sync((unsigned long)page_address(sg->page),
sg->length, direction); sg->length, direction);
plat_unmap_dma_mem(sg->dma_address);
}
} }
EXPORT_SYMBOL(dma_sync_sg_for_device); EXPORT_SYMBOL(dma_sync_sg_for_device);
...@@ -301,7 +346,7 @@ EXPORT_SYMBOL(dma_supported); ...@@ -301,7 +346,7 @@ EXPORT_SYMBOL(dma_supported);
int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) 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); EXPORT_SYMBOL(dma_is_consistent);
...@@ -309,62 +354,10 @@ EXPORT_SYMBOL(dma_is_consistent); ...@@ -309,62 +354,10 @@ EXPORT_SYMBOL(dma_is_consistent);
void dma_cache_sync(struct device *dev, void *vaddr, size_t size, 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) BUG_ON(direction == DMA_NONE);
return;
if (!plat_device_is_coherent(dev))
dma_cache_wback_inv((unsigned long)vaddr, size); dma_cache_wback_inv((unsigned long)vaddr, size);
} }
EXPORT_SYMBOL(dma_cache_sync); 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 */
/*
* 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);
/*
* 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);
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the PCI specific kernel interface routines under Linux. # 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 # PCI bus host bridge specific code
......
/*
* 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);
...@@ -69,7 +69,10 @@ static __inline__ void atomic_add(int i, atomic_t * v) ...@@ -69,7 +69,10 @@ static __inline__ void atomic_add(int i, atomic_t * v)
"1: ll %0, %1 # atomic_add \n" "1: ll %0, %1 # atomic_add \n"
" addu %0, %2 \n" " addu %0, %2 \n"
" sc %0, %1 \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" " .set mips0 \n"
: "=&r" (temp), "=m" (v->counter) : "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter)); : "Ir" (i), "m" (v->counter));
...@@ -111,7 +114,10 @@ static __inline__ void atomic_sub(int i, atomic_t * v) ...@@ -111,7 +114,10 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
"1: ll %0, %1 # atomic_sub \n" "1: ll %0, %1 # atomic_sub \n"
" subu %0, %2 \n" " subu %0, %2 \n"
" sc %0, %1 \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" " .set mips0 \n"
: "=&r" (temp), "=m" (v->counter) : "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter)); : "Ir" (i), "m" (v->counter));
...@@ -155,8 +161,11 @@ static __inline__ int atomic_add_return(int i, atomic_t * v) ...@@ -155,8 +161,11 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
"1: ll %1, %2 # atomic_add_return \n" "1: ll %1, %2 # atomic_add_return \n"
" addu %0, %1, %3 \n" " addu %0, %1, %3 \n"
" sc %0, %2 \n" " sc %0, %2 \n"
" beqz %0, 1b \n" " beqz %0, 2f \n"
" addu %0, %1, %3 \n" " addu %0, %1, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
" .set mips0 \n" " .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter) : "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter) : "Ir" (i), "m" (v->counter)
...@@ -204,8 +213,11 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v) ...@@ -204,8 +213,11 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
"1: ll %1, %2 # atomic_sub_return \n" "1: ll %1, %2 # atomic_sub_return \n"
" subu %0, %1, %3 \n" " subu %0, %1, %3 \n"
" sc %0, %2 \n" " sc %0, %2 \n"
" beqz %0, 1b \n" " beqz %0, 2f \n"
" subu %0, %1, %3 \n" " subu %0, %1, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
" .set mips0 \n" " .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter) : "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter) : "Ir" (i), "m" (v->counter)
...@@ -267,10 +279,13 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) ...@@ -267,10 +279,13 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
" bltz %0, 1f \n" " bltz %0, 1f \n"
" sc %0, %2 \n" " sc %0, %2 \n"
" .set noreorder \n" " .set noreorder \n"
" beqz %0, 1b \n" " beqz %0, 2f \n"
" subu %0, %1, %3 \n" " subu %0, %1, %3 \n"
" .set reorder \n" " .set reorder \n"
"1: \n" "1: \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
" .set mips0 \n" " .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter) : "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter) : "Ir" (i), "m" (v->counter)
...@@ -429,7 +444,10 @@ static __inline__ void atomic64_add(long i, atomic64_t * v) ...@@ -429,7 +444,10 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
"1: lld %0, %1 # atomic64_add \n" "1: lld %0, %1 # atomic64_add \n"
" addu %0, %2 \n" " addu %0, %2 \n"
" scd %0, %1 \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" " .set mips0 \n"
: "=&r" (temp), "=m" (v->counter) : "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter)); : "Ir" (i), "m" (v->counter));
...@@ -471,7 +489,10 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v) ...@@ -471,7 +489,10 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
"1: lld %0, %1 # atomic64_sub \n" "1: lld %0, %1 # atomic64_sub \n"
" subu %0, %2 \n" " subu %0, %2 \n"
" scd %0, %1 \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" " .set mips0 \n"
: "=&r" (temp), "=m" (v->counter) : "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter)); : "Ir" (i), "m" (v->counter));
...@@ -515,8 +536,11 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v) ...@@ -515,8 +536,11 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
"1: lld %1, %2 # atomic64_add_return \n" "1: lld %1, %2 # atomic64_add_return \n"
" addu %0, %1, %3 \n" " addu %0, %1, %3 \n"
" scd %0, %2 \n" " scd %0, %2 \n"
" beqz %0, 1b \n" " beqz %0, 2f \n"
" addu %0, %1, %3 \n" " addu %0, %1, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
" .set mips0 \n" " .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter) : "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter) : "Ir" (i), "m" (v->counter)
...@@ -564,8 +588,11 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v) ...@@ -564,8 +588,11 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
"1: lld %1, %2 # atomic64_sub_return \n" "1: lld %1, %2 # atomic64_sub_return \n"
" subu %0, %1, %3 \n" " subu %0, %1, %3 \n"
" scd %0, %2 \n" " scd %0, %2 \n"
" beqz %0, 1b \n" " beqz %0, 2f \n"
" subu %0, %1, %3 \n" " subu %0, %1, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
" .set mips0 \n" " .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter) : "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter) : "Ir" (i), "m" (v->counter)
...@@ -627,10 +654,13 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) ...@@ -627,10 +654,13 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
" bltz %0, 1f \n" " bltz %0, 1f \n"
" scd %0, %2 \n" " scd %0, %2 \n"
" .set noreorder \n" " .set noreorder \n"
" beqz %0, 1b \n" " beqz %0, 2f \n"
" dsubu %0, %1, %3 \n" " dsubu %0, %1, %3 \n"
" .set reorder \n" " .set reorder \n"
"1: \n" "1: \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
" .set mips0 \n" " .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter) : "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter) : "Ir" (i), "m" (v->counter)
......
...@@ -68,7 +68,10 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) ...@@ -68,7 +68,10 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
"1: " __LL "%0, %1 # set_bit \n" "1: " __LL "%0, %1 # set_bit \n"
" or %0, %2 \n" " or %0, %2 \n"
" " __SC "%0, %1 \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" " .set mips0 \n"
: "=&r" (temp), "=m" (*m) : "=&r" (temp), "=m" (*m)
: "ir" (1UL << (nr & SZLONG_MASK)), "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) ...@@ -116,7 +119,10 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
"1: " __LL "%0, %1 # clear_bit \n" "1: " __LL "%0, %1 # clear_bit \n"
" and %0, %2 \n" " and %0, %2 \n"
" " __SC "%0, %1 \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" " .set mips0 \n"
: "=&r" (temp), "=m" (*m) : "=&r" (temp), "=m" (*m)
: "ir" (~(1UL << (nr & SZLONG_MASK))), "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) ...@@ -166,7 +172,10 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
"1: " __LL "%0, %1 # change_bit \n" "1: " __LL "%0, %1 # change_bit \n"
" xor %0, %2 \n" " xor %0, %2 \n"
" " __SC "%0, %1 \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" " .set mips0 \n"
: "=&r" (temp), "=m" (*m) : "=&r" (temp), "=m" (*m)
: "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m)); : "ir" (1UL << (nr & SZLONG_MASK)), "m" (*m));
...@@ -222,8 +231,12 @@ static inline int test_and_set_bit(unsigned long nr, ...@@ -222,8 +231,12 @@ static inline int test_and_set_bit(unsigned long nr,
"1: " __LL "%0, %1 # test_and_set_bit \n" "1: " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n" " or %2, %0, %3 \n"
" " __SC "%2, %1 \n" " " __SC "%2, %1 \n"
" beqz %2, 1b \n" " beqz %2, 2f \n"
" and %2, %0, %3 \n" " and %2, %0, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" nop \n"
" .previous \n"
" .set pop \n" " .set pop \n"
: "=&r" (temp), "=m" (*m), "=&r" (res) : "=&r" (temp), "=m" (*m), "=&r" (res)
: "r" (1UL << (nr & SZLONG_MASK)), "m" (*m) : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
...@@ -290,8 +303,12 @@ static inline int test_and_clear_bit(unsigned long nr, ...@@ -290,8 +303,12 @@ static inline int test_and_clear_bit(unsigned long nr,
" or %2, %0, %3 \n" " or %2, %0, %3 \n"
" xor %2, %3 \n" " xor %2, %3 \n"
" " __SC "%2, %1 \n" " " __SC "%2, %1 \n"
" beqz %2, 1b \n" " beqz %2, 2f \n"
" and %2, %0, %3 \n" " and %2, %0, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" nop \n"
" .previous \n"
" .set pop \n" " .set pop \n"
: "=&r" (temp), "=m" (*m), "=&r" (res) : "=&r" (temp), "=m" (*m), "=&r" (res)
: "r" (1UL << (nr & SZLONG_MASK)), "m" (*m) : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
...@@ -356,8 +373,12 @@ static inline int test_and_change_bit(unsigned long nr, ...@@ -356,8 +373,12 @@ static inline int test_and_change_bit(unsigned long nr,
"1: " __LL "%0, %1 # test_and_change_bit \n" "1: " __LL "%0, %1 # test_and_change_bit \n"
" xor %2, %0, %3 \n" " xor %2, %0, %3 \n"
" " __SC "\t%2, %1 \n" " " __SC "\t%2, %1 \n"
" beqz %2, 1b \n" " beqz %2, 2f \n"
" and %2, %0, %3 \n" " and %2, %0, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" nop \n"
" .previous \n"
" .set pop \n" " .set pop \n"
: "=&r" (temp), "=m" (*m), "=&r" (res) : "=&r" (temp), "=m" (*m), "=&r" (res)
: "r" (1UL << (nr & SZLONG_MASK)), "m" (*m) : "r" (1UL << (nr & SZLONG_MASK)), "m" (*m)
......
#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 */
...@@ -68,6 +68,7 @@ extern int dma_is_consistent(struct device *dev, dma_addr_t dma_addr); ...@@ -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, extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction); enum dma_data_direction direction);
#if 0
#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY #define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
extern int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, 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, ...@@ -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_release_declared_memory(struct device *dev);
extern void * dma_mark_declared_memory_occupied(struct device *dev, extern void * dma_mark_declared_memory_occupied(struct device *dev,
dma_addr_t device_addr, size_t size); dma_addr_t device_addr, size_t size);
#endif
#endif /* _ASM_DMA_MAPPING_H */ #endif /* _ASM_DMA_MAPPING_H */
/*
* 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 */
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CONFIG_DMA_COHERENT #ifndef CONFIG_DMA_COHERENT
/* /*
* Total overkill for most systems but need as a safe default. * 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 #define ARCH_KMALLOC_MINALIGN 128
#endif #endif
......
/*
* 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 */
/*
* 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 */
/*
* 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 */
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * 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. * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/ */
#ifndef _ASM_SPINLOCK_H #ifndef _ASM_SPINLOCK_H
...@@ -49,11 +49,18 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) ...@@ -49,11 +49,18 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
__asm__ __volatile__( __asm__ __volatile__(
" .set noreorder # __raw_spin_lock \n" " .set noreorder # __raw_spin_lock \n"
"1: ll %1, %2 \n" "1: ll %1, %2 \n"
" bnez %1, 1b \n" " bnez %1, 2f \n"
" li %1, 1 \n" " li %1, 1 \n"
" sc %1, %0 \n" " sc %1, %0 \n"
" beqz %1, 1b \n" " beqz %1, 2f \n"
" nop \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" " .set reorder \n"
: "=m" (lock->lock), "=&r" (tmp) : "=m" (lock->lock), "=&r" (tmp)
: "m" (lock->lock) : "m" (lock->lock)
...@@ -99,8 +106,12 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock) ...@@ -99,8 +106,12 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
"1: ll %0, %3 \n" "1: ll %0, %3 \n"
" ori %2, %0, 1 \n" " ori %2, %0, 1 \n"
" sc %2, %1 \n" " sc %2, %1 \n"
" beqz %2, 1b \n" " beqz %2, 2f \n"
" andi %2, %0, 1 \n" " andi %2, %0, 1 \n"
" .subsection 2 \n"
"2: b 1b \n"
" nop \n"
" .previous \n"
" .set reorder" " .set reorder"
: "=&r" (temp), "=m" (lock->lock), "=&r" (res) : "=&r" (temp), "=m" (lock->lock), "=&r" (res)
: "m" (lock->lock) : "m" (lock->lock)
...@@ -154,11 +165,18 @@ static inline void __raw_read_lock(raw_rwlock_t *rw) ...@@ -154,11 +165,18 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
__asm__ __volatile__( __asm__ __volatile__(
" .set noreorder # __raw_read_lock \n" " .set noreorder # __raw_read_lock \n"
"1: ll %1, %2 \n" "1: ll %1, %2 \n"
" bltz %1, 1b \n" " bltz %1, 2f \n"
" addu %1, 1 \n" " addu %1, 1 \n"
" sc %1, %0 \n" " sc %1, %0 \n"
" beqz %1, 1b \n" " beqz %1, 1b \n"
" nop \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" " .set reorder \n"
: "=m" (rw->lock), "=&r" (tmp) : "=m" (rw->lock), "=&r" (tmp)
: "m" (rw->lock) : "m" (rw->lock)
...@@ -192,8 +210,12 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw) ...@@ -192,8 +210,12 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
"1: ll %1, %2 \n" "1: ll %1, %2 \n"
" sub %1, 1 \n" " sub %1, 1 \n"
" sc %1, %0 \n" " sc %1, %0 \n"
" beqz %1, 1b \n" " beqz %1, 2f \n"
" nop \n"
" .subsection 2 \n"
"2: b 1b \n"
" nop \n" " nop \n"
" .previous \n"
" .set reorder \n" " .set reorder \n"
: "=m" (rw->lock), "=&r" (tmp) : "=m" (rw->lock), "=&r" (tmp)
: "m" (rw->lock) : "m" (rw->lock)
...@@ -222,11 +244,18 @@ static inline void __raw_write_lock(raw_rwlock_t *rw) ...@@ -222,11 +244,18 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
__asm__ __volatile__( __asm__ __volatile__(
" .set noreorder # __raw_write_lock \n" " .set noreorder # __raw_write_lock \n"
"1: ll %1, %2 \n" "1: ll %1, %2 \n"
" bnez %1, 1b \n" " bnez %1, 2f \n"
" lui %1, 0x8000 \n" " lui %1, 0x8000 \n"
" sc %1, %0 \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" " nop \n"
" .previous \n"
" .set reorder \n" " .set reorder \n"
: "=m" (rw->lock), "=&r" (tmp) : "=m" (rw->lock), "=&r" (tmp)
: "m" (rw->lock) : "m" (rw->lock)
...@@ -322,12 +351,15 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw) ...@@ -322,12 +351,15 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
" bnez %1, 2f \n" " bnez %1, 2f \n"
" lui %1, 0x8000 \n" " lui %1, 0x8000 \n"
" sc %1, %0 \n" " sc %1, %0 \n"
" beqz %1, 1b \n" " beqz %1, 3f \n"
" nop \n"
__WEAK_ORDERING_MB
" li %2, 1 \n" " li %2, 1 \n"
" .set reorder \n"
"2: \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), "=&r" (tmp), "=&r" (ret)
: "m" (rw->lock) : "m" (rw->lock)
: "memory"); : "memory");
......
...@@ -110,7 +110,10 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val) ...@@ -110,7 +110,10 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
" move %2, %z4 \n" " move %2, %z4 \n"
" .set mips3 \n" " .set mips3 \n"
" sc %2, %1 \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" " .set mips0 \n"
: "=&r" (retval), "=m" (*m), "=&r" (dummy) : "=&r" (retval), "=m" (*m), "=&r" (dummy)
: "R" (*m), "Jr" (val) : "R" (*m), "Jr" (val)
...@@ -155,7 +158,10 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val) ...@@ -155,7 +158,10 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
"1: lld %0, %3 # xchg_u64 \n" "1: lld %0, %3 # xchg_u64 \n"
" move %2, %z4 \n" " move %2, %z4 \n"
" scd %2, %1 \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" " .set mips0 \n"
: "=&r" (retval), "=m" (*m), "=&r" (dummy) : "=&r" (retval), "=m" (*m), "=&r" (dummy)
: "R" (*m), "Jr" (val) : "R" (*m), "Jr" (val)
...@@ -232,8 +238,11 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old, ...@@ -232,8 +238,11 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
" move $1, %z4 \n" " move $1, %z4 \n"
" .set mips3 \n" " .set mips3 \n"
" sc $1, %1 \n" " sc $1, %1 \n"
" beqz $1, 1b \n" " beqz $1, 3f \n"
"2: \n" "2: \n"
" .subsection 2 \n"
"3: b 1b \n"
" .previous \n"
" .set pop \n" " .set pop \n"
: "=&r" (retval), "=R" (*m) : "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new) : "R" (*m), "Jr" (old), "Jr" (new)
...@@ -283,8 +292,11 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old, ...@@ -283,8 +292,11 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
" bne %0, %z3, 2f \n" " bne %0, %z3, 2f \n"
" move $1, %z4 \n" " move $1, %z4 \n"
" scd $1, %1 \n" " scd $1, %1 \n"
" beqz $1, 1b \n" " beqz $1, 3f \n"
"2: \n" "2: \n"
" .subsection 2 \n"
"3: b 1b \n"
" .previous \n"
" .set pop \n" " .set pop \n"
: "=&r" (retval), "=R" (*m) : "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new) : "R" (*m), "Jr" (old), "Jr" (new)
......
...@@ -265,10 +265,14 @@ do { \ ...@@ -265,10 +265,14 @@ do { \
*/ */
#define __get_user_asm_ll32(val, addr) \ #define __get_user_asm_ll32(val, addr) \
{ \ { \
union { \
unsigned long long l; \
__typeof__(*(addr)) t; \
} __gu_tmp; \
\
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: lw %1, (%3) \n" \ "1: lw %1, (%3) \n" \
"2: lw %D1, 4(%3) \n" \ "2: lw %D1, 4(%3) \n" \
" move %0, $0 \n" \
"3: .section .fixup,\"ax\" \n" \ "3: .section .fixup,\"ax\" \n" \
"4: li %0, %4 \n" \ "4: li %0, %4 \n" \
" move %1, $0 \n" \ " move %1, $0 \n" \
...@@ -279,8 +283,10 @@ do { \ ...@@ -279,8 +283,10 @@ do { \
" " __UA_ADDR " 1b, 4b \n" \ " " __UA_ADDR " 1b, 4b \n" \
" " __UA_ADDR " 2b, 4b \n" \ " " __UA_ADDR " 2b, 4b \n" \
" .previous \n" \ " .previous \n" \
: "=r" (__gu_err), "=&r" (val) \ : "=r" (__gu_err), "=&r" (__gu_tmp.l) \
: "0" (0), "r" (addr), "i" (-EFAULT)); \ : "0" (0), "r" (addr), "i" (-EFAULT)); \
\
(val) = __gu_tmp.t; \
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment