support for the J-Core J2 processor, an open source synthesizable reimplementation of the SH-2 ISA, resolve a longstanding sigcontext ABI mismatch issue, and fix various bugs including nommu-specific issues and minor regressions introduced in 4.6. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQEcBAABAgAGBQJXpQweAAoJELcQ+SIFb8Ha2vgH/Rm3YTHEgGeQhRvBle8DTPNv l9xBCQ6UMVb9T8C5nyP0jdioAVDQr7gh7sv2c7inIjN8hQh16DXFtNV8X6G3b0jv OC0+rBmcYjpO7gGC/L2sRE8ghuNpoIBJFojZy6bwOIvpF6EDMAZ9bAU/VFbY28so nCUdEo0gAmrdqGyHRfEJke7D7AKPvpAnN/cmRcvNQPhkkzKjRSNg5rHLthmvAKyp 1ChASb3YYPTgOY09izD8JUp4rk7v7q2smpgfeZfGQhIN/w6QKpv5OIqe+vrm1iKU B6q5gBHS7Y2VYilp1zKQedLM9ZthH6rnpkB25RzyH655uTwf//6ihyP3kEwlPkc= =wwNa -----END PGP SIGNATURE----- Merge tag 'sh-for-4.8' of git://git.libc.org/linux-sh Pull arch/sh updates from Rich Felker: "These changes improve device tree support (including builtin DTB), add support for the J-Core J2 processor, an open source synthesizable reimplementation of the SH-2 ISA, resolve a longstanding sigcontext ABI mismatch issue, and fix various bugs including nommu-specific issues and minor regressions introduced in 4.6. The J-Core arch support is included here but to be usable it needs drivers that are waiting on approval/inclusion from their subsystem maintainers" * tag 'sh-for-4.8' of git://git.libc.org/linux-sh: (23 commits) sh: add device tree source for J2 FPGA on Mimas v2 board sh: add defconfig for J-Core J2 sh: use common clock framework with device tree boards sh: system call wire up sh: Delete unnecessary checks before the function call "mempool_destroy" sh: do not perform IPI-based cache flush except on boards that need it sh: add SMP support for J2 sh: SMP support for SH2 entry.S sh: add working futex atomic ops on userspace addresses for smp sh: add J2 atomics using the cas.l instruction sh: add AT_HWCAP flag for J-Core cas.l instruction sh: add support for J-Core J2 processor sh: fix build regression with CONFIG_OF && !CONFIG_OF_FLATTREE sh: allow clocksource drivers to register sched_clock backends sh: make heartbeat driver explicitly non-modular sh: make board-secureedge5410 explicitly non-modular sh: make mm/asids-debugfs explicitly non-modular sh: make time.c explicitly non-modular sh: fix futex/robust_list on nommu models sh: disable aliased page logic on NOMMU models ...tirimbino
commit
1630e843e1
@ -0,0 +1,3 @@ |
||||
obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
|
||||
|
||||
clean-files := *.dtb.S
|
@ -0,0 +1,96 @@ |
||||
/dts-v1/; |
||||
|
||||
/ { |
||||
compatible = "jcore,j2-soc"; |
||||
model = "J2 FPGA SoC on Mimas v2 board"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
interrupt-parent = <&aic>; |
||||
|
||||
cpus { |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
|
||||
cpu@0 { |
||||
device_type = "cpu"; |
||||
compatible = "jcore,j2"; |
||||
reg = <0>; |
||||
clock-frequency = <50000000>; |
||||
d-cache-size = <8192>; |
||||
i-cache-size = <8192>; |
||||
d-cache-block-size = <16>; |
||||
i-cache-block-size = <16>; |
||||
}; |
||||
}; |
||||
|
||||
memory@10000000 { |
||||
device_type = "memory"; |
||||
reg = <0x10000000 0x4000000>; |
||||
}; |
||||
|
||||
aliases { |
||||
serial0 = &uart0; |
||||
spi0 = &spi0; |
||||
}; |
||||
|
||||
chosen { |
||||
stdout-path = "serial0"; |
||||
}; |
||||
|
||||
soc@abcd0000 { |
||||
compatible = "simple-bus"; |
||||
ranges = <0 0xabcd0000 0x100000>; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
aic: interrupt-controller@200 { |
||||
compatible = "jcore,aic1"; |
||||
reg = <0x200 0x10>; |
||||
interrupt-controller; |
||||
#interrupt-cells = <1>; |
||||
}; |
||||
|
||||
cache-controller@c0 { |
||||
compatible = "jcore,cache"; |
||||
reg = <0xc0 4>; |
||||
}; |
||||
|
||||
timer@200 { |
||||
compatible = "jcore,pit"; |
||||
reg = <0x200 0x30>; |
||||
interrupts = <0x48>; |
||||
}; |
||||
|
||||
spi0: spi@40 { |
||||
compatible = "jcore,spi2"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
|
||||
spi-max-frequency = <25000000>; |
||||
|
||||
reg = <0x40 0x8>; |
||||
|
||||
sdcard@0 { |
||||
compatible = "mmc-spi-slot"; |
||||
reg = <0>; |
||||
spi-max-frequency = <25000000>; |
||||
voltage-ranges = <3200 3400>; |
||||
mode = <0>; |
||||
}; |
||||
}; |
||||
|
||||
uart0: serial@100 { |
||||
clock-frequency = <125000000>; |
||||
compatible = "xlnx,xps-uartlite-1.00.a"; |
||||
current-speed = <19200>; |
||||
device_type = "serial"; |
||||
interrupts = <0x12>; |
||||
port-number = <0>; |
||||
reg = <0x100 0x10>; |
||||
}; |
||||
}; |
||||
}; |
@ -0,0 +1,40 @@ |
||||
CONFIG_SMP=y |
||||
CONFIG_SYSVIPC=y |
||||
CONFIG_POSIX_MQUEUE=y |
||||
CONFIG_NO_HZ=y |
||||
CONFIG_HIGH_RES_TIMERS=y |
||||
CONFIG_CPU_SUBTYPE_J2=y |
||||
CONFIG_MEMORY_START=0x10000000 |
||||
CONFIG_MEMORY_SIZE=0x04000000 |
||||
CONFIG_CPU_BIG_ENDIAN=y |
||||
CONFIG_SH_DEVICE_TREE=y |
||||
CONFIG_HZ_100=y |
||||
CONFIG_CMDLINE_OVERWRITE=y |
||||
CONFIG_CMDLINE="console=ttyUL0 earlycon" |
||||
CONFIG_BINFMT_ELF_FDPIC=y |
||||
CONFIG_BINFMT_FLAT=y |
||||
CONFIG_NET=y |
||||
CONFIG_PACKET=y |
||||
CONFIG_UNIX=y |
||||
CONFIG_INET=y |
||||
CONFIG_DEVTMPFS=y |
||||
CONFIG_DEVTMPFS_MOUNT=y |
||||
CONFIG_NETDEVICES=y |
||||
CONFIG_SERIAL_UARTLITE=y |
||||
CONFIG_SERIAL_UARTLITE_CONSOLE=y |
||||
CONFIG_I2C=y |
||||
CONFIG_SPI=y |
||||
CONFIG_SPI_JCORE=y |
||||
CONFIG_WATCHDOG=y |
||||
CONFIG_MMC=y |
||||
CONFIG_MMC_SPI=y |
||||
CONFIG_CLKSRC_JCORE_PIT=y |
||||
CONFIG_JCORE_AIC=y |
||||
CONFIG_EXT4_FS=y |
||||
CONFIG_VFAT_FS=y |
||||
CONFIG_FAT_DEFAULT_IOCHARSET="ascii" |
||||
CONFIG_FAT_DEFAULT_UTF8=y |
||||
CONFIG_NLS_DEFAULT="utf8" |
||||
CONFIG_NLS_CODEPAGE_437=y |
||||
CONFIG_NLS_ASCII=y |
||||
CONFIG_NLS_UTF8=y |
@ -0,0 +1,93 @@ |
||||
#ifndef __ASM_SH_BITOPS_CAS_H |
||||
#define __ASM_SH_BITOPS_CAS_H |
||||
|
||||
static inline unsigned __bo_cas(volatile unsigned *p, unsigned old, unsigned new) |
||||
{ |
||||
__asm__ __volatile__("cas.l %1,%0,@r0" |
||||
: "+r"(new) |
||||
: "r"(old), "z"(p) |
||||
: "t", "memory" ); |
||||
return new; |
||||
} |
||||
|
||||
static inline void set_bit(int nr, volatile void *addr) |
||||
{ |
||||
unsigned mask, old; |
||||
volatile unsigned *a = addr; |
||||
|
||||
a += nr >> 5; |
||||
mask = 1U << (nr & 0x1f); |
||||
|
||||
do old = *a; |
||||
while (__bo_cas(a, old, old|mask) != old); |
||||
} |
||||
|
||||
static inline void clear_bit(int nr, volatile void *addr) |
||||
{ |
||||
unsigned mask, old; |
||||
volatile unsigned *a = addr; |
||||
|
||||
a += nr >> 5; |
||||
mask = 1U << (nr & 0x1f); |
||||
|
||||
do old = *a; |
||||
while (__bo_cas(a, old, old&~mask) != old); |
||||
} |
||||
|
||||
static inline void change_bit(int nr, volatile void *addr) |
||||
{ |
||||
unsigned mask, old; |
||||
volatile unsigned *a = addr; |
||||
|
||||
a += nr >> 5; |
||||
mask = 1U << (nr & 0x1f); |
||||
|
||||
do old = *a; |
||||
while (__bo_cas(a, old, old^mask) != old); |
||||
} |
||||
|
||||
static inline int test_and_set_bit(int nr, volatile void *addr) |
||||
{ |
||||
unsigned mask, old; |
||||
volatile unsigned *a = addr; |
||||
|
||||
a += nr >> 5; |
||||
mask = 1U << (nr & 0x1f); |
||||
|
||||
do old = *a; |
||||
while (__bo_cas(a, old, old|mask) != old); |
||||
|
||||
return !!(old & mask); |
||||
} |
||||
|
||||
static inline int test_and_clear_bit(int nr, volatile void *addr) |
||||
{ |
||||
unsigned mask, old; |
||||
volatile unsigned *a = addr; |
||||
|
||||
a += nr >> 5; |
||||
mask = 1U << (nr & 0x1f); |
||||
|
||||
do old = *a; |
||||
while (__bo_cas(a, old, old&~mask) != old); |
||||
|
||||
return !!(old & mask); |
||||
} |
||||
|
||||
static inline int test_and_change_bit(int nr, volatile void *addr) |
||||
{ |
||||
unsigned mask, old; |
||||
volatile unsigned *a = addr; |
||||
|
||||
a += nr >> 5; |
||||
mask = 1U << (nr & 0x1f); |
||||
|
||||
do old = *a; |
||||
while (__bo_cas(a, old, old^mask) != old); |
||||
|
||||
return !!(old & mask); |
||||
} |
||||
|
||||
#include <asm-generic/bitops/non-atomic.h> |
||||
|
||||
#endif /* __ASM_SH_BITOPS_CAS_H */ |
@ -0,0 +1,24 @@ |
||||
#ifndef __ASM_SH_CMPXCHG_CAS_H |
||||
#define __ASM_SH_CMPXCHG_CAS_H |
||||
|
||||
static inline unsigned long |
||||
__cmpxchg_u32(volatile u32 *m, unsigned long old, unsigned long new) |
||||
{ |
||||
__asm__ __volatile__("cas.l %1,%0,@r0" |
||||
: "+r"(new) |
||||
: "r"(old), "z"(m) |
||||
: "t", "memory" ); |
||||
return new; |
||||
} |
||||
|
||||
static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) |
||||
{ |
||||
unsigned long old; |
||||
do old = *m; |
||||
while (__cmpxchg_u32(m, old, val) != old); |
||||
return old; |
||||
} |
||||
|
||||
#include <asm/cmpxchg-xchg.h> |
||||
|
||||
#endif /* __ASM_SH_CMPXCHG_CAS_H */ |
@ -0,0 +1,34 @@ |
||||
#ifndef __ASM_SH_FUTEX_CAS_H |
||||
#define __ASM_SH_FUTEX_CAS_H |
||||
|
||||
static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, |
||||
u32 __user *uaddr, |
||||
u32 oldval, u32 newval) |
||||
{ |
||||
int err = 0; |
||||
__asm__ __volatile__( |
||||
"1:\n\t" |
||||
"cas.l %2, %1, @r0\n" |
||||
"2:\n\t" |
||||
#ifdef CONFIG_MMU |
||||
".section .fixup,\"ax\"\n" |
||||
"3:\n\t" |
||||
"mov.l 4f, %0\n\t" |
||||
"jmp @%0\n\t" |
||||
" mov %3, %0\n\t" |
||||
".balign 4\n" |
||||
"4: .long 2b\n\t" |
||||
".previous\n" |
||||
".section __ex_table,\"a\"\n\t" |
||||
".long 1b, 3b\n\t" |
||||
".previous" |
||||
#endif |
||||
:"+r" (err), "+r" (newval) |
||||
:"r" (oldval), "i" (-EFAULT), "z" (uaddr) |
||||
:"t", "memory"); |
||||
if (err) return err; |
||||
*uval = newval; |
||||
return 0; |
||||
} |
||||
|
||||
#endif /* __ASM_SH_FUTEX_CAS_H */ |
@ -0,0 +1,41 @@ |
||||
#ifndef __ASM_SH_FUTEX_LLSC_H |
||||
#define __ASM_SH_FUTEX_LLSC_H |
||||
|
||||
static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, |
||||
u32 __user *uaddr, |
||||
u32 oldval, u32 newval) |
||||
{ |
||||
int err = 0; |
||||
__asm__ __volatile__( |
||||
"synco\n" |
||||
"1:\n\t" |
||||
"movli.l @%2, r0\n\t" |
||||
"mov r0, %1\n\t" |
||||
"cmp/eq %1, %4\n\t" |
||||
"bf 2f\n\t" |
||||
"mov %5, r0\n\t" |
||||
"movco.l r0, @%2\n\t" |
||||
"bf 1b\n" |
||||
"2:\n\t" |
||||
"synco\n\t" |
||||
#ifdef CONFIG_MMU |
||||
".section .fixup,\"ax\"\n" |
||||
"3:\n\t" |
||||
"mov.l 4f, %0\n\t" |
||||
"jmp @%0\n\t" |
||||
" mov %3, %0\n\t" |
||||
".balign 4\n" |
||||
"4: .long 2b\n\t" |
||||
".previous\n" |
||||
".section __ex_table,\"a\"\n\t" |
||||
".long 1b, 3b\n\t" |
||||
".previous" |
||||
#endif |
||||
:"+r" (err), "=&r" (*uval) |
||||
:"r" (uaddr), "i" (-EFAULT), "r" (oldval), "r" (newval) |
||||
:"t", "memory", "r0"); |
||||
if (err) return err; |
||||
return 0; |
||||
} |
||||
|
||||
#endif /* __ASM_SH_FUTEX_LLSC_H */ |
@ -0,0 +1,117 @@ |
||||
/*
|
||||
* include/asm-sh/spinlock-cas.h |
||||
* |
||||
* Copyright (C) 2015 SEI |
||||
* |
||||
* 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. |
||||
*/ |
||||
#ifndef __ASM_SH_SPINLOCK_CAS_H |
||||
#define __ASM_SH_SPINLOCK_CAS_H |
||||
|
||||
#include <asm/barrier.h> |
||||
#include <asm/processor.h> |
||||
|
||||
static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new) |
||||
{ |
||||
__asm__ __volatile__("cas.l %1,%0,@r0" |
||||
: "+r"(new) |
||||
: "r"(old), "z"(p) |
||||
: "t", "memory" ); |
||||
return new; |
||||
} |
||||
|
||||
/*
|
||||
* Your basic SMP spinlocks, allowing only a single CPU anywhere |
||||
*/ |
||||
|
||||
#define arch_spin_is_locked(x) ((x)->lock <= 0) |
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) |
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) |
||||
{ |
||||
smp_cond_load_acquire(&lock->lock, VAL > 0); |
||||
} |
||||
|
||||
static inline void arch_spin_lock(arch_spinlock_t *lock) |
||||
{ |
||||
while (!__sl_cas(&lock->lock, 1, 0)); |
||||
} |
||||
|
||||
static inline void arch_spin_unlock(arch_spinlock_t *lock) |
||||
{ |
||||
__sl_cas(&lock->lock, 0, 1); |
||||
} |
||||
|
||||
static inline int arch_spin_trylock(arch_spinlock_t *lock) |
||||
{ |
||||
return __sl_cas(&lock->lock, 1, 0); |
||||
} |
||||
|
||||
/*
|
||||
* Read-write spinlocks, allowing multiple readers but only one writer. |
||||
* |
||||
* NOTE! it is quite common to have readers in interrupts but no interrupt |
||||
* writers. For those circumstances we can "mix" irq-safe locks - any writer |
||||
* needs to get a irq-safe write-lock, but readers can get non-irqsafe |
||||
* read-locks. |
||||
*/ |
||||
|
||||
/**
|
||||
* read_can_lock - would read_trylock() succeed? |
||||
* @lock: the rwlock in question. |
||||
*/ |
||||
#define arch_read_can_lock(x) ((x)->lock > 0) |
||||
|
||||
/**
|
||||
* write_can_lock - would write_trylock() succeed? |
||||
* @lock: the rwlock in question. |
||||
*/ |
||||
#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) |
||||
|
||||
static inline void arch_read_lock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned old; |
||||
do old = rw->lock; |
||||
while (!old || __sl_cas(&rw->lock, old, old-1) != old); |
||||
} |
||||
|
||||
static inline void arch_read_unlock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned old; |
||||
do old = rw->lock; |
||||
while (__sl_cas(&rw->lock, old, old+1) != old); |
||||
} |
||||
|
||||
static inline void arch_write_lock(arch_rwlock_t *rw) |
||||
{ |
||||
while (__sl_cas(&rw->lock, RW_LOCK_BIAS, 0) != RW_LOCK_BIAS); |
||||
} |
||||
|
||||
static inline void arch_write_unlock(arch_rwlock_t *rw) |
||||
{ |
||||
__sl_cas(&rw->lock, 0, RW_LOCK_BIAS); |
||||
} |
||||
|
||||
static inline int arch_read_trylock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned old; |
||||
do old = rw->lock; |
||||
while (old && __sl_cas(&rw->lock, old, old-1) != old); |
||||
return !!old; |
||||
} |
||||
|
||||
static inline int arch_write_trylock(arch_rwlock_t *rw) |
||||
{ |
||||
return __sl_cas(&rw->lock, RW_LOCK_BIAS, 0) == RW_LOCK_BIAS; |
||||
} |
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock) |
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) |
||||
|
||||
#define arch_spin_relax(lock) cpu_relax() |
||||
#define arch_read_relax(lock) cpu_relax() |
||||
#define arch_write_relax(lock) cpu_relax() |
||||
|
||||
#endif /* __ASM_SH_SPINLOCK_CAS_H */ |
@ -0,0 +1,224 @@ |
||||
/*
|
||||
* include/asm-sh/spinlock-llsc.h |
||||
* |
||||
* Copyright (C) 2002, 2003 Paul Mundt |
||||
* Copyright (C) 2006, 2007 Akio Idehara |
||||
* |
||||
* 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. |
||||
*/ |
||||
#ifndef __ASM_SH_SPINLOCK_LLSC_H |
||||
#define __ASM_SH_SPINLOCK_LLSC_H |
||||
|
||||
#include <asm/barrier.h> |
||||
#include <asm/processor.h> |
||||
|
||||
/*
|
||||
* Your basic SMP spinlocks, allowing only a single CPU anywhere |
||||
*/ |
||||
|
||||
#define arch_spin_is_locked(x) ((x)->lock <= 0) |
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) |
||||
|
||||
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) |
||||
{ |
||||
smp_cond_load_acquire(&lock->lock, VAL > 0); |
||||
} |
||||
|
||||
/*
|
||||
* Simple spin lock operations. There are two variants, one clears IRQ's |
||||
* on the local processor, one does not. |
||||
* |
||||
* We make no fairness assumptions. They have a cost. |
||||
*/ |
||||
static inline void arch_spin_lock(arch_spinlock_t *lock) |
||||
{ |
||||
unsigned long tmp; |
||||
unsigned long oldval; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"1: \n\t" |
||||
"movli.l @%2, %0 ! arch_spin_lock \n\t" |
||||
"mov %0, %1 \n\t" |
||||
"mov #0, %0 \n\t" |
||||
"movco.l %0, @%2 \n\t" |
||||
"bf 1b \n\t" |
||||
"cmp/pl %1 \n\t" |
||||
"bf 1b \n\t" |
||||
: "=&z" (tmp), "=&r" (oldval) |
||||
: "r" (&lock->lock) |
||||
: "t", "memory" |
||||
); |
||||
} |
||||
|
||||
static inline void arch_spin_unlock(arch_spinlock_t *lock) |
||||
{ |
||||
unsigned long tmp; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"mov #1, %0 ! arch_spin_unlock \n\t" |
||||
"mov.l %0, @%1 \n\t" |
||||
: "=&z" (tmp) |
||||
: "r" (&lock->lock) |
||||
: "t", "memory" |
||||
); |
||||
} |
||||
|
||||
static inline int arch_spin_trylock(arch_spinlock_t *lock) |
||||
{ |
||||
unsigned long tmp, oldval; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"1: \n\t" |
||||
"movli.l @%2, %0 ! arch_spin_trylock \n\t" |
||||
"mov %0, %1 \n\t" |
||||
"mov #0, %0 \n\t" |
||||
"movco.l %0, @%2 \n\t" |
||||
"bf 1b \n\t" |
||||
"synco \n\t" |
||||
: "=&z" (tmp), "=&r" (oldval) |
||||
: "r" (&lock->lock) |
||||
: "t", "memory" |
||||
); |
||||
|
||||
return oldval; |
||||
} |
||||
|
||||
/*
|
||||
* Read-write spinlocks, allowing multiple readers but only one writer. |
||||
* |
||||
* NOTE! it is quite common to have readers in interrupts but no interrupt |
||||
* writers. For those circumstances we can "mix" irq-safe locks - any writer |
||||
* needs to get a irq-safe write-lock, but readers can get non-irqsafe |
||||
* read-locks. |
||||
*/ |
||||
|
||||
/**
|
||||
* read_can_lock - would read_trylock() succeed? |
||||
* @lock: the rwlock in question. |
||||
*/ |
||||
#define arch_read_can_lock(x) ((x)->lock > 0) |
||||
|
||||
/**
|
||||
* write_can_lock - would write_trylock() succeed? |
||||
* @lock: the rwlock in question. |
||||
*/ |
||||
#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) |
||||
|
||||
static inline void arch_read_lock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned long tmp; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"1: \n\t" |
||||
"movli.l @%1, %0 ! arch_read_lock \n\t" |
||||
"cmp/pl %0 \n\t" |
||||
"bf 1b \n\t" |
||||
"add #-1, %0 \n\t" |
||||
"movco.l %0, @%1 \n\t" |
||||
"bf 1b \n\t" |
||||
: "=&z" (tmp) |
||||
: "r" (&rw->lock) |
||||
: "t", "memory" |
||||
); |
||||
} |
||||
|
||||
static inline void arch_read_unlock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned long tmp; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"1: \n\t" |
||||
"movli.l @%1, %0 ! arch_read_unlock \n\t" |
||||
"add #1, %0 \n\t" |
||||
"movco.l %0, @%1 \n\t" |
||||
"bf 1b \n\t" |
||||
: "=&z" (tmp) |
||||
: "r" (&rw->lock) |
||||
: "t", "memory" |
||||
); |
||||
} |
||||
|
||||
static inline void arch_write_lock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned long tmp; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"1: \n\t" |
||||
"movli.l @%1, %0 ! arch_write_lock \n\t" |
||||
"cmp/hs %2, %0 \n\t" |
||||
"bf 1b \n\t" |
||||
"sub %2, %0 \n\t" |
||||
"movco.l %0, @%1 \n\t" |
||||
"bf 1b \n\t" |
||||
: "=&z" (tmp) |
||||
: "r" (&rw->lock), "r" (RW_LOCK_BIAS) |
||||
: "t", "memory" |
||||
); |
||||
} |
||||
|
||||
static inline void arch_write_unlock(arch_rwlock_t *rw) |
||||
{ |
||||
__asm__ __volatile__ ( |
||||
"mov.l %1, @%0 ! arch_write_unlock \n\t" |
||||
: |
||||
: "r" (&rw->lock), "r" (RW_LOCK_BIAS) |
||||
: "t", "memory" |
||||
); |
||||
} |
||||
|
||||
static inline int arch_read_trylock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned long tmp, oldval; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"1: \n\t" |
||||
"movli.l @%2, %0 ! arch_read_trylock \n\t" |
||||
"mov %0, %1 \n\t" |
||||
"cmp/pl %0 \n\t" |
||||
"bf 2f \n\t" |
||||
"add #-1, %0 \n\t" |
||||
"movco.l %0, @%2 \n\t" |
||||
"bf 1b \n\t" |
||||
"2: \n\t" |
||||
"synco \n\t" |
||||
: "=&z" (tmp), "=&r" (oldval) |
||||
: "r" (&rw->lock) |
||||
: "t", "memory" |
||||
); |
||||
|
||||
return (oldval > 0); |
||||
} |
||||
|
||||
static inline int arch_write_trylock(arch_rwlock_t *rw) |
||||
{ |
||||
unsigned long tmp, oldval; |
||||
|
||||
__asm__ __volatile__ ( |
||||
"1: \n\t" |
||||
"movli.l @%2, %0 ! arch_write_trylock \n\t" |
||||
"mov %0, %1 \n\t" |
||||
"cmp/hs %3, %0 \n\t" |
||||
"bf 2f \n\t" |
||||
"sub %3, %0 \n\t" |
||||
"2: \n\t" |
||||
"movco.l %0, @%2 \n\t" |
||||
"bf 1b \n\t" |
||||
"synco \n\t" |
||||
: "=&z" (tmp), "=&r" (oldval) |
||||
: "r" (&rw->lock), "r" (RW_LOCK_BIAS) |
||||
: "t", "memory" |
||||
); |
||||
|
||||
return (oldval > (RW_LOCK_BIAS - 1)); |
||||
} |
||||
|
||||
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock) |
||||
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) |
||||
|
||||
#define arch_spin_relax(lock) cpu_relax() |
||||
#define arch_read_relax(lock) cpu_relax() |
||||
#define arch_write_relax(lock) cpu_relax() |
||||
|
||||
#endif /* __ASM_SH_SPINLOCK_LLSC_H */ |
@ -0,0 +1,139 @@ |
||||
/*
|
||||
* SMP support for J2 processor |
||||
* |
||||
* Copyright (C) 2015-2016 Smart Energy Instruments, Inc. |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
#include <linux/smp.h> |
||||
#include <linux/interrupt.h> |
||||
#include <linux/io.h> |
||||
#include <linux/of_address.h> |
||||
#include <linux/of_irq.h> |
||||
#include <asm/cmpxchg.h> |
||||
|
||||
DEFINE_PER_CPU(unsigned, j2_ipi_messages); |
||||
|
||||
extern u32 *sh2_cpuid_addr; |
||||
static u32 *j2_ipi_trigger; |
||||
static int j2_ipi_irq; |
||||
|
||||
static irqreturn_t j2_ipi_interrupt_handler(int irq, void *arg) |
||||
{ |
||||
unsigned cpu = hard_smp_processor_id(); |
||||
volatile unsigned *pmsg = &per_cpu(j2_ipi_messages, cpu); |
||||
unsigned messages, i; |
||||
|
||||
do messages = *pmsg; |
||||
while (cmpxchg(pmsg, messages, 0) != messages); |
||||
|
||||
if (!messages) return IRQ_NONE; |
||||
|
||||
for (i=0; i<SMP_MSG_NR; i++) |
||||
if (messages & (1U<<i)) |
||||
smp_message_recv(i); |
||||
|
||||
return IRQ_HANDLED; |
||||
} |
||||
|
||||
static void j2_smp_setup(void) |
||||
{ |
||||
} |
||||
|
||||
static void j2_prepare_cpus(unsigned int max_cpus) |
||||
{ |
||||
struct device_node *np; |
||||
unsigned i, max = 1; |
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "jcore,ipi-controller"); |
||||
if (!np) |
||||
goto out; |
||||
|
||||
j2_ipi_irq = irq_of_parse_and_map(np, 0); |
||||
j2_ipi_trigger = of_iomap(np, 0); |
||||
if (!j2_ipi_irq || !j2_ipi_trigger) |
||||
goto out; |
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "jcore,cpuid-mmio"); |
||||
if (!np) |
||||
goto out; |
||||
|
||||
sh2_cpuid_addr = of_iomap(np, 0); |
||||
if (!sh2_cpuid_addr) |
||||
goto out; |
||||
|
||||
if (request_irq(j2_ipi_irq, j2_ipi_interrupt_handler, IRQF_PERCPU, |
||||
"ipi", (void *)j2_ipi_interrupt_handler) != 0) |
||||
goto out; |
||||
|
||||
max = max_cpus; |
||||
out: |
||||
/* Disable any cpus past max_cpus, or all secondaries if we didn't
|
||||
* get the necessary resources to support SMP. */ |
||||
for (i=max; i<NR_CPUS; i++) { |
||||
set_cpu_possible(i, false); |
||||
set_cpu_present(i, false); |
||||
} |
||||
} |
||||
|
||||
static void j2_start_cpu(unsigned int cpu, unsigned long entry_point) |
||||
{ |
||||
struct device_node *np; |
||||
u32 regs[2]; |
||||
void __iomem *release, *initpc; |
||||
|
||||
if (!cpu) return; |
||||
|
||||
np = of_get_cpu_node(cpu, NULL); |
||||
if (!np) return; |
||||
|
||||
if (of_property_read_u32_array(np, "cpu-release-addr", regs, 2)) return; |
||||
release = ioremap_nocache(regs[0], sizeof(u32)); |
||||
initpc = ioremap_nocache(regs[1], sizeof(u32)); |
||||
|
||||
__raw_writel(entry_point, initpc); |
||||
__raw_writel(1, release); |
||||
|
||||
iounmap(initpc); |
||||
iounmap(release); |
||||
|
||||
pr_info("J2 SMP: requested start of cpu %u\n", cpu); |
||||
} |
||||
|
||||
static unsigned int j2_smp_processor_id(void) |
||||
{ |
||||
return __raw_readl(sh2_cpuid_addr); |
||||
} |
||||
|
||||
static void j2_send_ipi(unsigned int cpu, unsigned int message) |
||||
{ |
||||
volatile unsigned *pmsg; |
||||
unsigned old; |
||||
unsigned long val; |
||||
|
||||
/* There is only one IPI interrupt shared by all messages, so
|
||||
* we keep a separate interrupt flag per message type in sw. */ |
||||
pmsg = &per_cpu(j2_ipi_messages, cpu); |
||||
do old = *pmsg; |
||||
while (cmpxchg(pmsg, old, old|(1U<<message)) != old); |
||||
|
||||
/* Generate the actual interrupt by writing to CCRn bit 28. */ |
||||
val = __raw_readl(j2_ipi_trigger + cpu); |
||||
__raw_writel(val | (1U<<28), j2_ipi_trigger + cpu); |
||||
} |
||||
|
||||
static struct plat_smp_ops j2_smp_ops = { |
||||
.smp_setup = j2_smp_setup, |
||||
.prepare_cpus = j2_prepare_cpus, |
||||
.start_cpu = j2_start_cpu, |
||||
.smp_processor_id = j2_smp_processor_id, |
||||
.send_ipi = j2_send_ipi, |
||||
.cpu_die = native_cpu_die, |
||||
.cpu_disable = native_cpu_disable, |
||||
.play_dead = native_play_dead, |
||||
}; |
||||
|
||||
CPU_METHOD_OF_DECLARE(j2_cpu_method, "jcore,spin-table", &j2_smp_ops); |
@ -0,0 +1,65 @@ |
||||
/*
|
||||
* arch/sh/mm/cache-j2.c |
||||
* |
||||
* Copyright (C) 2015-2016 Smart Energy Instruments, Inc. |
||||
* |
||||
* Released under the terms of the GNU GPL v2.0. |
||||
*/ |
||||
|
||||
#include <linux/init.h> |
||||
#include <linux/mm.h> |
||||
#include <linux/cpumask.h> |
||||
|
||||
#include <asm/cache.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/processor.h> |
||||
#include <asm/cacheflush.h> |
||||
#include <asm/io.h> |
||||
|
||||
#define ICACHE_ENABLE 0x1 |
||||
#define DCACHE_ENABLE 0x2 |
||||
#define CACHE_ENABLE (ICACHE_ENABLE | DCACHE_ENABLE) |
||||
#define ICACHE_FLUSH 0x100 |
||||
#define DCACHE_FLUSH 0x200 |
||||
#define CACHE_FLUSH (ICACHE_FLUSH | DCACHE_FLUSH) |
||||
|
||||
u32 __iomem *j2_ccr_base; |
||||
|
||||
static void j2_flush_icache(void *args) |
||||
{ |
||||
unsigned cpu; |
||||
for_each_possible_cpu(cpu) |
||||
__raw_writel(CACHE_ENABLE | ICACHE_FLUSH, j2_ccr_base + cpu); |
||||
} |
||||
|
||||
static void j2_flush_dcache(void *args) |
||||
{ |
||||
unsigned cpu; |
||||
for_each_possible_cpu(cpu) |
||||
__raw_writel(CACHE_ENABLE | DCACHE_FLUSH, j2_ccr_base + cpu); |
||||
} |
||||
|
||||
static void j2_flush_both(void *args) |
||||
{ |
||||
unsigned cpu; |
||||
for_each_possible_cpu(cpu) |
||||
__raw_writel(CACHE_ENABLE | CACHE_FLUSH, j2_ccr_base + cpu); |
||||
} |
||||
|
||||
void __init j2_cache_init(void) |
||||
{ |
||||
if (!j2_ccr_base) |
||||
return; |
||||
|
||||
local_flush_cache_all = j2_flush_both; |
||||
local_flush_cache_mm = j2_flush_both; |
||||
local_flush_cache_dup_mm = j2_flush_both; |
||||
local_flush_cache_page = j2_flush_both; |
||||
local_flush_cache_range = j2_flush_both; |
||||
local_flush_dcache_page = j2_flush_dcache; |
||||
local_flush_icache_range = j2_flush_icache; |
||||
local_flush_icache_page = j2_flush_icache; |
||||
local_flush_cache_sigtramp = j2_flush_icache; |
||||
|
||||
pr_info("Initial J2 CCR is %.8x\n", __raw_readl(j2_ccr_base)); |
||||
} |
Loading…
Reference in new issue