From 8b93b4a9e1be78930eb9d640f75818993f70e065 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Wed, 24 May 2017 17:55:09 -0600 Subject: arch/sparc: Remove the check #ifndef __LINUX_SPINLOCK_TYPES_H Saw these compile errors on SPARC when queued rwlock feature is enabled. CC kernel/locking/qrwlock.o In file included from ./include/asm-generic/qrwlock_types.h:5, from ./arch/sparc/include/asm/qrwlock.h:4, from kernel/locking/qrwlock.c:24: ./arch/sparc/include/asm/spinlock_types.h:5:3: error: #error "please don't include this file directly" SPARC has this guard which causes compile error when spinlock_types.h is included directly. @ifndef __LINUX_SPINLOCK_TYPES_H @ error "please don't include this file directly" @endif Remove this un-necessary "ifndef __LINUX_SPINLOCK_TYPES_H" stanza from SPARC. Signed-off-by: Babu Moger Suggested-by: David Miller Signed-off-by: David S. Miller --- arch/sparc/include/asm/spinlock_types.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/spinlock_types.h b/arch/sparc/include/asm/spinlock_types.h index 9c454fdeaad8..019c0855bf8b 100644 --- a/arch/sparc/include/asm/spinlock_types.h +++ b/arch/sparc/include/asm/spinlock_types.h @@ -1,10 +1,6 @@ #ifndef __SPARC_SPINLOCK_TYPES_H #define __SPARC_SPINLOCK_TYPES_H -#ifndef __LINUX_SPINLOCK_TYPES_H -# error "please don't include this file directly" -#endif - typedef struct { volatile unsigned char lock; } arch_spinlock_t; -- cgit v1.2.1 From 97d9f969161d79e6a4bba247e67ce731ff861f79 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Wed, 24 May 2017 17:55:11 -0600 Subject: arch/sparc: Define config parameter CPU_BIG_ENDIAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found this problem while enabling queued rwlock on SPARC. The parameter CONFIG_CPU_BIG_ENDIAN is used to clear the specific byte in qrwlock structure. Without this parameter, we clear the wrong byte. Here is the code. static inline u8 *__qrwlock_write_byte(struct qrwlock *lock) { return (u8 *)lock + 3 * IS_BUILTIN(CONFIG_CPU_BIG_ENDIAN); } Define CPU_BIG_ENDIAN for SPARC to fix it. Signed-off-by: Babu Moger Reviewed-by: Håkon Bugge Reviewed-by: Jane Chu Reviewed-by: Shannon Nelson Reviewed-by: Vijay Kumar Signed-off-by: David S. Miller --- arch/sparc/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/sparc') diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 58243b0d21c0..eb213b5000c8 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -92,6 +92,9 @@ config ARCH_DEFCONFIG config ARCH_PROC_KCORE_TEXT def_bool y +config CPU_BIG_ENDIAN + def_bool y + config ARCH_ATU bool default y if SPARC64 -- cgit v1.2.1 From a12ee2349312d7112b9b7c6ac2e70c5ec2ca334e Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Wed, 24 May 2017 17:55:12 -0600 Subject: arch/sparc: Introduce cmpxchg_u8 SPARC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPARC supports 32 bit and 64 bit cmpxchg right now. Add support for 8 bit (1 byte) cmpxchg. This is required to support queued rwlocks feature which uses 1 byte cmpxchg. The function __cmpxchg_u8 here uses the 4 byte cas instruction with a byte manipulation to achieve 1 byte cmpxchg. Signed-off-by: Babu Moger Reviewed-by: Håkon Bugge Reviewed-by: Steve Sistare Reviewed-by: Shannon Nelson Reviewed-by: Jane Chu Reviewed-by: Vijay Kumar Signed-off-by: David S. Miller --- arch/sparc/include/asm/cmpxchg_64.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h index faa2f61058c2..000f7d7a2d4a 100644 --- a/arch/sparc/include/asm/cmpxchg_64.h +++ b/arch/sparc/include/asm/cmpxchg_64.h @@ -87,6 +87,33 @@ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) return new; } +/* + * Use 4 byte cas instruction to achieve 1 byte cmpxchg. Main logic + * here is to get the bit shift of the byte we are interested in. + * The XOR is handy for reversing the bits for big-endian byte order + */ +static inline unsigned long +__cmpxchg_u8(volatile unsigned char *m, unsigned char old, unsigned char new) +{ + unsigned long maddr = (unsigned long)m; + int bit_shift = (((unsigned long)m & 3) ^ 3) << 3; + unsigned int mask = 0xff << bit_shift; + unsigned int *ptr = (unsigned int *) (maddr & ~3); + unsigned int old32, new32, load; + unsigned int load32 = *ptr; + + do { + new32 = (load32 & ~mask) | (new << bit_shift); + old32 = (load32 & ~mask) | (old << bit_shift); + load32 = __cmpxchg_u32(ptr, old32, new32); + if (load32 == old32) + return old; + load = (load32 & mask) >> bit_shift; + } while (load == old); + + return load; +} + /* This function doesn't exist, so you'll get a linker error if something tries to do an invalid cmpxchg(). */ void __cmpxchg_called_with_bad_pointer(void); @@ -95,6 +122,8 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) { switch (size) { + case 1: + return __cmpxchg_u8(ptr, old, new); case 4: return __cmpxchg_u32(ptr, old, new); case 8: -- cgit v1.2.1 From a37594f198363fd9321ece54440336fd4b2a9c8e Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Wed, 24 May 2017 17:55:13 -0600 Subject: arch/sparc: Enable queued rwlocks for SPARC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable queued rwlocks for SPARC. Here are the discussions on this feature when this was introduced. https://lwn.net/Articles/572765/ https://lwn.net/Articles/582200/ Cleaned-up the arch_read_xxx and arch_write_xxx definitions in spinlock_64.h. These routines are replaced by the functions in include/asm-generic/qrwlock.h Signed-off-by: Babu Moger Reviewed-by: Håkon Bugge Reviewed-by: Jane Chu Reviewed-by: Shannon Nelson Reviewed-by: Vijay Kumar Signed-off-by: David S. Miller --- arch/sparc/Kconfig | 1 + arch/sparc/include/asm/qrwlock.h | 7 ++ arch/sparc/include/asm/spinlock_64.h | 124 +------------------------------- arch/sparc/include/asm/spinlock_types.h | 5 +- 4 files changed, 13 insertions(+), 124 deletions(-) create mode 100644 arch/sparc/include/asm/qrwlock.h (limited to 'arch/sparc') diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index eb213b5000c8..0e8065207596 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -83,6 +83,7 @@ config SPARC64 select ARCH_SUPPORTS_ATOMIC_RMW select HAVE_NMI select HAVE_REGS_AND_STACK_ACCESS_API + select ARCH_USE_QUEUED_RWLOCKS config ARCH_DEFCONFIG string diff --git a/arch/sparc/include/asm/qrwlock.h b/arch/sparc/include/asm/qrwlock.h new file mode 100644 index 000000000000..d68a4b102100 --- /dev/null +++ b/arch/sparc/include/asm/qrwlock.h @@ -0,0 +1,7 @@ +#ifndef _ASM_SPARC_QRWLOCK_H +#define _ASM_SPARC_QRWLOCK_H + +#include +#include + +#endif /* _ASM_SPARC_QRWLOCK_H */ diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h index 07c9f2e9bf57..8901c2d4ada9 100644 --- a/arch/sparc/include/asm/spinlock_64.h +++ b/arch/sparc/include/asm/spinlock_64.h @@ -10,6 +10,7 @@ #include #include +#include /* To get debugging spinlocks which detect and catch * deadlock situations, set CONFIG_DEBUG_SPINLOCK @@ -94,132 +95,9 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long fla : "memory"); } -/* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ - -static inline void arch_read_lock(arch_rwlock_t *lock) -{ - unsigned long tmp1, tmp2; - - __asm__ __volatile__ ( -"1: ldsw [%2], %0\n" -" brlz,pn %0, 2f\n" -"4: add %0, 1, %1\n" -" cas [%2], %0, %1\n" -" cmp %0, %1\n" -" bne,pn %%icc, 1b\n" -" nop\n" -" .subsection 2\n" -"2: ldsw [%2], %0\n" -" brlz,pt %0, 2b\n" -" nop\n" -" ba,a,pt %%xcc, 4b\n" -" .previous" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (lock) - : "memory"); -} - -static inline int arch_read_trylock(arch_rwlock_t *lock) -{ - int tmp1, tmp2; - - __asm__ __volatile__ ( -"1: ldsw [%2], %0\n" -" brlz,a,pn %0, 2f\n" -" mov 0, %0\n" -" add %0, 1, %1\n" -" cas [%2], %0, %1\n" -" cmp %0, %1\n" -" bne,pn %%icc, 1b\n" -" mov 1, %0\n" -"2:" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (lock) - : "memory"); - - return tmp1; -} - -static inline void arch_read_unlock(arch_rwlock_t *lock) -{ - unsigned long tmp1, tmp2; - - __asm__ __volatile__( -"1: lduw [%2], %0\n" -" sub %0, 1, %1\n" -" cas [%2], %0, %1\n" -" cmp %0, %1\n" -" bne,pn %%xcc, 1b\n" -" nop" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (lock) - : "memory"); -} - -static inline void arch_write_lock(arch_rwlock_t *lock) -{ - unsigned long mask, tmp1, tmp2; - - mask = 0x80000000UL; - - __asm__ __volatile__( -"1: lduw [%2], %0\n" -" brnz,pn %0, 2f\n" -"4: or %0, %3, %1\n" -" cas [%2], %0, %1\n" -" cmp %0, %1\n" -" bne,pn %%icc, 1b\n" -" nop\n" -" .subsection 2\n" -"2: lduw [%2], %0\n" -" brnz,pt %0, 2b\n" -" nop\n" -" ba,a,pt %%xcc, 4b\n" -" .previous" - : "=&r" (tmp1), "=&r" (tmp2) - : "r" (lock), "r" (mask) - : "memory"); -} - -static inline void arch_write_unlock(arch_rwlock_t *lock) -{ - __asm__ __volatile__( -" stw %%g0, [%0]" - : /* no outputs */ - : "r" (lock) - : "memory"); -} - -static inline int arch_write_trylock(arch_rwlock_t *lock) -{ - unsigned long mask, tmp1, tmp2, result; - - mask = 0x80000000UL; - - __asm__ __volatile__( -" mov 0, %2\n" -"1: lduw [%3], %0\n" -" brnz,pn %0, 2f\n" -" or %0, %4, %1\n" -" cas [%3], %0, %1\n" -" cmp %0, %1\n" -" bne,pn %%icc, 1b\n" -" nop\n" -" mov 1, %2\n" -"2:" - : "=&r" (tmp1), "=&r" (tmp2), "=&r" (result) - : "r" (lock), "r" (mask) - : "memory"); - - return result; -} - #define arch_read_lock_flags(p, f) arch_read_lock(p) #define arch_write_lock_flags(p, f) arch_write_lock(p) -#define arch_read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) -#define arch_write_can_lock(rw) (!(rw)->lock) - #define arch_spin_relax(lock) cpu_relax() #define arch_read_relax(lock) cpu_relax() #define arch_write_relax(lock) cpu_relax() diff --git a/arch/sparc/include/asm/spinlock_types.h b/arch/sparc/include/asm/spinlock_types.h index 019c0855bf8b..64fce21b23df 100644 --- a/arch/sparc/include/asm/spinlock_types.h +++ b/arch/sparc/include/asm/spinlock_types.h @@ -7,10 +7,13 @@ typedef struct { #define __ARCH_SPIN_LOCK_UNLOCKED { 0 } +#ifdef CONFIG_QUEUED_RWLOCKS +#include +#else typedef struct { volatile unsigned int lock; } arch_rwlock_t; #define __ARCH_RW_LOCK_UNLOCKED { 0 } - +#endif /* CONFIG_QUEUED_RWLOCKS */ #endif -- cgit v1.2.1 From 79d39e2bab60d18a68a5abc00be4506864397efc Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Wed, 24 May 2017 17:55:14 -0600 Subject: arch/sparc: Introduce xchg16 for SPARC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPARC supports 32 bit and 64 bit xchg right now. Add the support for 16 bit (2 byte) xchg. This is required to support queued spinlock feature which uses 2 byte xchg. This is achieved using 4 byte cas instructions with byte manipulations. Also re-arranged the code to call __cmpxchg_u32 inside xchg16. Signed-off-by: Babu Moger Reviewed-by: Håkon Bugge Reviewed-by: Steven Sistare Reviewed-by: Shannon Nelson Reviewed-by: Jane Chu Reviewed-by: Vijay Kumar Signed-off-by: David S. Miller --- arch/sparc/include/asm/cmpxchg_64.h | 49 +++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h index 000f7d7a2d4a..4028f4f1e561 100644 --- a/arch/sparc/include/asm/cmpxchg_64.h +++ b/arch/sparc/include/asm/cmpxchg_64.h @@ -6,6 +6,17 @@ #ifndef __ARCH_SPARC64_CMPXCHG__ #define __ARCH_SPARC64_CMPXCHG__ +static inline unsigned long +__cmpxchg_u32(volatile int *m, int old, int new) +{ + __asm__ __volatile__("cas [%2], %3, %0" + : "=&r" (new) + : "0" (new), "r" (m), "r" (old) + : "memory"); + + return new; +} + static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val) { unsigned long tmp1, tmp2; @@ -44,10 +55,38 @@ static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long void __xchg_called_with_bad_pointer(void); +/* + * Use 4 byte cas instruction to achieve 2 byte xchg. Main logic + * here is to get the bit shift of the byte we are interested in. + * The XOR is handy for reversing the bits for big-endian byte order. + */ +static inline unsigned long +xchg16(__volatile__ unsigned short *m, unsigned short val) +{ + unsigned long maddr = (unsigned long)m; + int bit_shift = (((unsigned long)m & 2) ^ 2) << 3; + unsigned int mask = 0xffff << bit_shift; + unsigned int *ptr = (unsigned int *) (maddr & ~2); + unsigned int old32, new32, load32; + + /* Read the old value */ + load32 = *ptr; + + do { + old32 = load32; + new32 = (load32 & (~mask)) | val << bit_shift; + load32 = __cmpxchg_u32(ptr, old32, new32); + } while (load32 != old32); + + return (load32 & mask) >> bit_shift; +} + static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) { switch (size) { + case 2: + return xchg16(ptr, x); case 4: return xchg32(ptr, x); case 8: @@ -65,16 +104,6 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, #include -static inline unsigned long -__cmpxchg_u32(volatile int *m, int old, int new) -{ - __asm__ __volatile__("cas [%2], %3, %0" - : "=&r" (new) - : "0" (new), "r" (m), "r" (old) - : "memory"); - - return new; -} static inline unsigned long __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) -- cgit v1.2.1 From 145d978585977438ebb55079487827006c604e39 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Wed, 24 May 2017 17:55:15 -0600 Subject: arch/sparc: Enable queued spinlock support for SPARC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch makes the necessary changes in SPARC architecture to enable queued spinlock support. Here are some of the earlier discussions about this feature. https://lwn.net/Articles/561775/ https://lwn.net/Articles/590243/ Cleaned-up the spinlock_64.h. The definitions of arch_spin_xxx are replaced by the function in Signed-off-by: Babu Moger Reviewed-by: Håkon Bugge Reviewed-by: Jane Chu Reviewed-by: Shannon Nelson Reviewed-by: Vijay Kumar Signed-off-by: David S. Miller --- arch/sparc/Kconfig | 1 + arch/sparc/include/asm/qspinlock.h | 7 +++ arch/sparc/include/asm/spinlock_64.h | 84 +-------------------------------- arch/sparc/include/asm/spinlock_types.h | 5 ++ 4 files changed, 14 insertions(+), 83 deletions(-) create mode 100644 arch/sparc/include/asm/qspinlock.h (limited to 'arch/sparc') diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 0e8065207596..78af684f63b9 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -84,6 +84,7 @@ config SPARC64 select HAVE_NMI select HAVE_REGS_AND_STACK_ACCESS_API select ARCH_USE_QUEUED_RWLOCKS + select ARCH_USE_QUEUED_SPINLOCKS config ARCH_DEFCONFIG string diff --git a/arch/sparc/include/asm/qspinlock.h b/arch/sparc/include/asm/qspinlock.h new file mode 100644 index 000000000000..5ae9a2802846 --- /dev/null +++ b/arch/sparc/include/asm/qspinlock.h @@ -0,0 +1,7 @@ +#ifndef _ASM_SPARC_QSPINLOCK_H +#define _ASM_SPARC_QSPINLOCK_H + +#include +#include + +#endif /* _ASM_SPARC_QSPINLOCK_H */ diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h index 8901c2d4ada9..f7028f5e1a5a 100644 --- a/arch/sparc/include/asm/spinlock_64.h +++ b/arch/sparc/include/asm/spinlock_64.h @@ -11,89 +11,7 @@ #include #include #include - -/* To get debugging spinlocks which detect and catch - * deadlock situations, set CONFIG_DEBUG_SPINLOCK - * and rebuild your kernel. - */ - -/* Because we play games to save cycles in the non-contention case, we - * need to be extra careful about branch targets into the "spinning" - * code. They live in their own section, but the newer V9 branches - * have a shorter range than the traditional 32-bit sparc branch - * variants. The rule is that the branches that go into and out of - * the spinner sections must be pre-V9 branches. - */ - -#define arch_spin_is_locked(lp) ((lp)->lock != 0) - -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) -{ - smp_cond_load_acquire(&lock->lock, !VAL); -} - -static inline void arch_spin_lock(arch_spinlock_t *lock) -{ - unsigned long tmp; - - __asm__ __volatile__( -"1: ldstub [%1], %0\n" -" brnz,pn %0, 2f\n" -" nop\n" -" .subsection 2\n" -"2: ldub [%1], %0\n" -" brnz,pt %0, 2b\n" -" nop\n" -" ba,a,pt %%xcc, 1b\n" -" .previous" - : "=&r" (tmp) - : "r" (lock) - : "memory"); -} - -static inline int arch_spin_trylock(arch_spinlock_t *lock) -{ - unsigned long result; - - __asm__ __volatile__( -" ldstub [%1], %0\n" - : "=r" (result) - : "r" (lock) - : "memory"); - - return (result == 0UL); -} - -static inline void arch_spin_unlock(arch_spinlock_t *lock) -{ - __asm__ __volatile__( -" stb %%g0, [%0]" - : /* No outputs */ - : "r" (lock) - : "memory"); -} - -static inline void arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags) -{ - unsigned long tmp1, tmp2; - - __asm__ __volatile__( -"1: ldstub [%2], %0\n" -" brnz,pn %0, 2f\n" -" nop\n" -" .subsection 2\n" -"2: rdpr %%pil, %1\n" -" wrpr %3, %%pil\n" -"3: ldub [%2], %0\n" -" brnz,pt %0, 3b\n" -" nop\n" -" ba,pt %%xcc, 1b\n" -" wrpr %1, %%pil\n" -" .previous" - : "=&r" (tmp1), "=&r" (tmp2) - : "r"(lock), "r"(flags) - : "memory"); -} +#include #define arch_read_lock_flags(p, f) arch_read_lock(p) #define arch_write_lock_flags(p, f) arch_write_lock(p) diff --git a/arch/sparc/include/asm/spinlock_types.h b/arch/sparc/include/asm/spinlock_types.h index 64fce21b23df..bce8ef44dfa9 100644 --- a/arch/sparc/include/asm/spinlock_types.h +++ b/arch/sparc/include/asm/spinlock_types.h @@ -1,11 +1,16 @@ #ifndef __SPARC_SPINLOCK_TYPES_H #define __SPARC_SPINLOCK_TYPES_H +#ifdef CONFIG_QUEUED_SPINLOCKS +#include +#else + typedef struct { volatile unsigned char lock; } arch_spinlock_t; #define __ARCH_SPIN_LOCK_UNLOCKED { 0 } +#endif /* CONFIG_QUEUED_SPINLOCKS */ #ifdef CONFIG_QUEUED_RWLOCKS #include -- cgit v1.2.1 From 85762a65c1106daa0930bc2ed0d7792511647168 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 9 Jun 2017 12:29:28 -0400 Subject: sparc64: expand LDC interface Add the following LDC APIs which are planned to be used by LDC clients in the future: - ldc_set_state: Sets given LDC channel to given state - ldc_mode: Returns the mode of given LDC channel - ldc_print: Prints info about given LDC channel - ldc_rx_reset: Reset the RX queue of given LDC channel Signed-off-by: Jagannathan Raman Reviewed-by: Aaron Young Reviewed-by: Alexandre Chartre Reviewed-by: Bijan Mottahedeh Reviewed-by: Liam Merwick Signed-off-by: David S. Miller --- arch/sparc/include/asm/ldc.h | 8 ++++++++ arch/sparc/kernel/ldc.c | 46 ++++++++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 12 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/ldc.h b/arch/sparc/include/asm/ldc.h index 6e9004aa6f25..698738a10414 100644 --- a/arch/sparc/include/asm/ldc.h +++ b/arch/sparc/include/asm/ldc.h @@ -48,6 +48,8 @@ struct ldc_channel_config { #define LDC_STATE_READY 0x03 #define LDC_STATE_CONNECTED 0x04 +#define LDC_PACKET_SIZE 64 + struct ldc_channel; /* Allocate state for a channel. */ @@ -72,6 +74,12 @@ int ldc_connect(struct ldc_channel *lp); int ldc_disconnect(struct ldc_channel *lp); int ldc_state(struct ldc_channel *lp); +void ldc_set_state(struct ldc_channel *lp, u8 state); +int ldc_mode(struct ldc_channel *lp); +void __ldc_print(struct ldc_channel *lp, const char *caller); +int ldc_rx_reset(struct ldc_channel *lp); + +#define ldc_print(chan) __ldc_print(chan, __func__) /* Read and write operations. Only valid when the link is up. */ int ldc_write(struct ldc_channel *lp, const void *buf, diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 59d503866431..77c34b00eccc 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -34,7 +34,6 @@ static char version[] = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; -#define LDC_PACKET_SIZE 64 /* Packet header layout for unreliable and reliable mode frames. * When in RAW mode, packets are simply straight 64-byte payloads @@ -196,15 +195,6 @@ static const char *state_to_str(u8 state) } } -static void ldc_set_state(struct ldc_channel *lp, u8 state) -{ - ldcdbg(STATE, "STATE (%s) --> (%s)\n", - state_to_str(lp->state), - state_to_str(state)); - - lp->state = state; -} - static unsigned long __advance(unsigned long off, unsigned long num_entries) { off += LDC_PACKET_SIZE; @@ -829,7 +819,7 @@ static irqreturn_t ldc_rx(int irq, void *dev_id) * everything. */ if (lp->flags & LDC_FLAG_RESET) { - (void) __set_rx_head(lp, lp->rx_tail); + (void) ldc_rx_reset(lp); goto out; } @@ -1447,6 +1437,38 @@ int ldc_state(struct ldc_channel *lp) } EXPORT_SYMBOL(ldc_state); +void ldc_set_state(struct ldc_channel *lp, u8 state) +{ + ldcdbg(STATE, "STATE (%s) --> (%s)\n", + state_to_str(lp->state), + state_to_str(state)); + + lp->state = state; +} + +int ldc_mode(struct ldc_channel *lp) +{ + return lp->cfg.mode; +} + +int ldc_rx_reset(struct ldc_channel *lp) +{ + return __set_rx_head(lp, lp->rx_tail); +} + +void __ldc_print(struct ldc_channel *lp, const char *caller) +{ + pr_info("%s: id=0x%lx flags=0x%x state=%s cstate=0x%lx hsstate=0x%x\n" + "\trx_h=0x%lx rx_t=0x%lx rx_n=%ld\n" + "\ttx_h=0x%lx tx_t=0x%lx tx_n=%ld\n" + "\trcv_nxt=%u snd_nxt=%u\n", + caller, lp->id, lp->flags, state_to_str(lp->state), + lp->chan_state, lp->hs_state, + lp->rx_head, lp->rx_tail, lp->rx_num_entries, + lp->tx_head, lp->tx_tail, lp->tx_num_entries, + lp->rcv_nxt, lp->snd_nxt); +} + static int write_raw(struct ldc_channel *lp, const void *buf, unsigned int size) { struct ldc_packet *p; @@ -1592,7 +1614,7 @@ static int rx_bad_seq(struct ldc_channel *lp, struct ldc_packet *p, if (err) return err; - err = __set_rx_head(lp, lp->rx_tail); + err = ldc_rx_reset(lp); if (err < 0) return ldc_abort(lp); -- cgit v1.2.1 From 29693e75a823131a789b519150027e2d69fecab7 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 9 Jun 2017 12:29:29 -0400 Subject: sparc64: enhance ldc_abort to print message Enhance ldc_abort to accept a message to be printed when it is called. Add a macro, LDC_ABORT, to print info. about the function that calls ldc_abort. Signed-off-by: Jagannathan Raman Reviewed-by: Aaron Young Reviewed-by: Alexandre Chartre Reviewed-by: Bijan Mottahedeh Reviewed-by: Liam Merwick Signed-off-by: David S. Miller --- arch/sparc/kernel/ldc.c | 53 ++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 25 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 77c34b00eccc..902cbf4fa007 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -177,6 +177,8 @@ do { if (lp->cfg.debug & LDC_DEBUG_##TYPE) \ printk(KERN_INFO PFX "ID[%lu] " f, lp->id, ## a); \ } while (0) +#define LDC_ABORT(lp) ldc_abort((lp), __func__) + static const char *state_to_str(u8 state) { switch (state) { @@ -506,11 +508,12 @@ static int send_data_nack(struct ldc_channel *lp, struct ldc_packet *data_pkt) return err; } -static int ldc_abort(struct ldc_channel *lp) +static int ldc_abort(struct ldc_channel *lp, const char *msg) { unsigned long hv_err; - ldcdbg(STATE, "ABORT\n"); + ldcdbg(STATE, "ABORT[%s]\n", msg); + ldc_print(lp); /* We report but do not act upon the hypervisor errors because * there really isn't much we can do if they fail at this point. @@ -595,7 +598,7 @@ static int process_ver_info(struct ldc_channel *lp, struct ldc_version *vp) } } if (err) - return ldc_abort(lp); + return LDC_ABORT(lp); return 0; } @@ -608,13 +611,13 @@ static int process_ver_ack(struct ldc_channel *lp, struct ldc_version *vp) if (lp->hs_state == LDC_HS_GOTVERS) { if (lp->ver.major != vp->major || lp->ver.minor != vp->minor) - return ldc_abort(lp); + return LDC_ABORT(lp); } else { lp->ver = *vp; lp->hs_state = LDC_HS_GOTVERS; } if (send_rts(lp)) - return ldc_abort(lp); + return LDC_ABORT(lp); return 0; } @@ -625,17 +628,17 @@ static int process_ver_nack(struct ldc_channel *lp, struct ldc_version *vp) unsigned long new_tail; if (vp->major == 0 && vp->minor == 0) - return ldc_abort(lp); + return LDC_ABORT(lp); vap = find_by_major(vp->major); if (!vap) - return ldc_abort(lp); + return LDC_ABORT(lp); p = handshake_compose_ctrl(lp, LDC_INFO, LDC_VERS, vap, sizeof(*vap), &new_tail); if (!p) - return ldc_abort(lp); + return LDC_ABORT(lp); return send_tx_packet(lp, p, new_tail); } @@ -658,7 +661,7 @@ static int process_version(struct ldc_channel *lp, return process_ver_nack(lp, vp); default: - return ldc_abort(lp); + return LDC_ABORT(lp); } } @@ -671,13 +674,13 @@ static int process_rts(struct ldc_channel *lp, if (p->stype != LDC_INFO || lp->hs_state != LDC_HS_GOTVERS || p->env != lp->cfg.mode) - return ldc_abort(lp); + return LDC_ABORT(lp); lp->snd_nxt = p->seqid; lp->rcv_nxt = p->seqid; lp->hs_state = LDC_HS_SENTRTR; if (send_rtr(lp)) - return ldc_abort(lp); + return LDC_ABORT(lp); return 0; } @@ -690,7 +693,7 @@ static int process_rtr(struct ldc_channel *lp, if (p->stype != LDC_INFO || p->env != lp->cfg.mode) - return ldc_abort(lp); + return LDC_ABORT(lp); lp->snd_nxt = p->seqid; lp->hs_state = LDC_HS_COMPLETE; @@ -713,7 +716,7 @@ static int process_rdx(struct ldc_channel *lp, if (p->stype != LDC_INFO || !(rx_seq_ok(lp, p->seqid))) - return ldc_abort(lp); + return LDC_ABORT(lp); lp->rcv_nxt = p->seqid; @@ -740,14 +743,14 @@ static int process_control_frame(struct ldc_channel *lp, return process_rdx(lp, p); default: - return ldc_abort(lp); + return LDC_ABORT(lp); } } static int process_error_frame(struct ldc_channel *lp, struct ldc_packet *p) { - return ldc_abort(lp); + return LDC_ABORT(lp); } static int process_data_ack(struct ldc_channel *lp, @@ -766,7 +769,7 @@ static int process_data_ack(struct ldc_channel *lp, return 0; } if (head == lp->tx_tail) - return ldc_abort(lp); + return LDC_ABORT(lp); } return 0; @@ -870,7 +873,7 @@ handshake_complete: break; default: - err = ldc_abort(lp); + err = LDC_ABORT(lp); break; } @@ -885,7 +888,7 @@ handshake_complete: err = __set_rx_head(lp, new); if (err < 0) { - (void) ldc_abort(lp); + (void) LDC_ABORT(lp); break; } if (lp->hs_state == LDC_HS_COMPLETE) @@ -1505,7 +1508,7 @@ static int read_raw(struct ldc_channel *lp, void *buf, unsigned int size) &lp->rx_tail, &lp->chan_state); if (hv_err) - return ldc_abort(lp); + return LDC_ABORT(lp); if (lp->chan_state == LDC_CHANNEL_DOWN || lp->chan_state == LDC_CHANNEL_RESETTING) @@ -1548,7 +1551,7 @@ static int write_nonraw(struct ldc_channel *lp, const void *buf, return -EBUSY; if (unlikely(lp->chan_state != LDC_CHANNEL_UP)) - return ldc_abort(lp); + return LDC_ABORT(lp); if (!tx_has_space_for(lp, size)) return -EAGAIN; @@ -1616,7 +1619,7 @@ static int rx_bad_seq(struct ldc_channel *lp, struct ldc_packet *p, err = ldc_rx_reset(lp); if (err < 0) - return ldc_abort(lp); + return LDC_ABORT(lp); return 0; } @@ -1629,7 +1632,7 @@ static int data_ack_nack(struct ldc_channel *lp, struct ldc_packet *p) return err; } if (p->stype & LDC_NACK) - return ldc_abort(lp); + return LDC_ABORT(lp); return 0; } @@ -1649,7 +1652,7 @@ static int rx_data_wait(struct ldc_channel *lp, unsigned long cur_head) &lp->rx_tail, &lp->chan_state); if (hv_err) - return ldc_abort(lp); + return LDC_ABORT(lp); if (lp->chan_state == LDC_CHANNEL_DOWN || lp->chan_state == LDC_CHANNEL_RESETTING) @@ -1672,7 +1675,7 @@ static int rx_set_head(struct ldc_channel *lp, unsigned long head) int err = __set_rx_head(lp, head); if (err < 0) - return ldc_abort(lp); + return LDC_ABORT(lp); lp->rx_head = head; return 0; @@ -1711,7 +1714,7 @@ static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size) &lp->rx_tail, &lp->chan_state); if (hv_err) - return ldc_abort(lp); + return LDC_ABORT(lp); if (lp->chan_state == LDC_CHANNEL_DOWN || lp->chan_state == LDC_CHANNEL_RESETTING) -- cgit v1.2.1 From fc43b978a02985aad7540d77de6b3aa0579a678c Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 9 Jun 2017 12:29:30 -0400 Subject: sparc64: ensure LDC channel is ready before communication Ensure that LDC channel is up before writing to it, in RAW mode. Generate event to bring the LDC channel up, if it's not up already. Signed-off-by: Jagannathan Raman Reviewed-by: Aaron Young Reviewed-by: Alexandre Chartre Reviewed-by: Bijan Mottahedeh Reviewed-by: Liam Merwick Signed-off-by: David S. Miller --- arch/sparc/kernel/ldc.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 902cbf4fa007..639da7b53e83 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -813,9 +813,14 @@ static irqreturn_t ldc_rx(int irq, void *dev_id) lp->hs_state = LDC_HS_COMPLETE; ldc_set_state(lp, LDC_STATE_CONNECTED); - event_mask |= LDC_EVENT_UP; - - orig_state = lp->chan_state; + /* + * Generate an LDC_EVENT_UP event if the channel + * was not already up. + */ + if (orig_state != LDC_CHANNEL_UP) { + event_mask |= LDC_EVENT_UP; + orig_state = lp->chan_state; + } } /* If we are in reset state, flush the RX queue and ignore @@ -929,7 +934,14 @@ static irqreturn_t ldc_tx(int irq, void *dev_id) lp->hs_state = LDC_HS_COMPLETE; ldc_set_state(lp, LDC_STATE_CONNECTED); - event_mask |= LDC_EVENT_UP; + /* + * Generate an LDC_EVENT_UP event if the channel + * was not already up. + */ + if (orig_state != LDC_CHANNEL_UP) { + event_mask |= LDC_EVENT_UP; + orig_state = lp->chan_state; + } } spin_unlock_irqrestore(&lp->lock, flags); @@ -1475,9 +1487,17 @@ void __ldc_print(struct ldc_channel *lp, const char *caller) static int write_raw(struct ldc_channel *lp, const void *buf, unsigned int size) { struct ldc_packet *p; - unsigned long new_tail; + unsigned long new_tail, hv_err; int err; + hv_err = sun4v_ldc_tx_get_state(lp->id, &lp->tx_head, &lp->tx_tail, + &lp->chan_state); + if (unlikely(hv_err)) + return -EBUSY; + + if (unlikely(lp->chan_state != LDC_CHANNEL_UP)) + return LDC_ABORT(lp); + if (size > LDC_PACKET_SIZE) return -EMSGSIZE; -- cgit v1.2.1 From 6c95483b768c62f8ee933ae08a1bdbcb78b5410f Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 9 Jun 2017 12:29:31 -0400 Subject: sparc64: ldc abort during vds iso boot Orabug: 20902628 When an ldc control-only packet is received during data exchange in read_nonraw(), a new rx head is calculated but the rx queue head is not actually advanced (rx_set_head() is not called) and a branch is taken to 'no_data' at which point two things can happen depending on the value of the newly calculated rx head and the current rx tail: - If the rx queue is determined to be not empty, then the wrong packet is picked up. - If the rx queue is determined to be empty, then a read error (EAGAIN) is eventually returned since it is falsely assumed that more data was expected. The fix is to update the rx head and return in case of a control only packet during data exchange. Signed-off-by: Jagannathan Raman Reviewed-by: Aaron Young Reviewed-by: Alexandre Chartre Reviewed-by: Bijan Mottahedeh Reviewed-by: Liam Merwick Signed-off-by: David S. Miller --- arch/sparc/kernel/ldc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 639da7b53e83..47817b78ebfc 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1778,9 +1778,14 @@ static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size) lp->rcv_nxt = p->seqid; + /* + * If this is a control-only packet, there is nothing + * else to do but advance the rx queue since the packet + * was already processed above. + */ if (!(p->type & LDC_DATA)) { new = rx_advance(lp, new); - goto no_data; + break; } if (p->stype & (LDC_ACK | LDC_NACK)) { err = data_ack_nack(lp, p); -- cgit v1.2.1 From 93ec4a828e6d777a61f497bc6e0cf9239fde35c7 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 9 Jun 2017 12:29:32 -0400 Subject: sparc64: print debug messages when reading from LDC channel Print debug messages when reading from given LDC channel. Signed-off-by: Jagannathan Raman Reviewed-by: Aaron Young Reviewed-by: Alexandre Chartre Reviewed-by: Bijan Mottahedeh Reviewed-by: Liam Merwick Signed-off-by: David S. Miller --- arch/sparc/kernel/ldc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 47817b78ebfc..97a5743b04e2 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1950,6 +1950,8 @@ int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size) unsigned long flags; int err; + ldcdbg(RX, "%s: entered size=%d\n", __func__, size); + if (!buf) return -EINVAL; @@ -1965,6 +1967,9 @@ int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size) spin_unlock_irqrestore(&lp->lock, flags); + ldcdbg(RX, "%s: mode=%d, head=%lu, tail=%lu rv=%d\n", __func__, + lp->cfg.mode, lp->rx_head, lp->rx_tail, err); + return err; } EXPORT_SYMBOL(ldc_read); -- cgit v1.2.1 From 68a792174d7f67c7d2108bf1cc55ab8a63fc4678 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:41 -0400 Subject: sparc64: remove trailing white spaces A few changes that were reported by checkpatch, removed all trailing white spaces in these two files. Signed-off-by: Pavel Tatashin Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/include/asm/setup.h | 2 +- arch/sparc/kernel/setup_64.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h index 3fae200dd251..8b32538084f7 100644 --- a/arch/sparc/include/asm/setup.h +++ b/arch/sparc/include/asm/setup.h @@ -1,5 +1,5 @@ /* - * Just a place holder. + * Just a place holder. */ #ifndef _SPARC_SETUP_H #define _SPARC_SETUP_H diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 422b17880955..4a85f9241a2a 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -95,7 +95,7 @@ static struct console prom_early_console = { .index = -1, }; -/* +/* * Process kernel command line switches that are specific to the * SPARC or that require special low-level processing. */ @@ -639,7 +639,7 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_BLK_DEV_RAM rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); - rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); + rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif task_thread_info(&init_task)->kregs = &fake_swapper_regs; @@ -648,7 +648,7 @@ void __init setup_arch(char **cmdline_p) if (!ic_set_manually) { phandle chosen = prom_finddevice("/chosen"); u32 cl, sv, gw; - + cl = prom_getintdefault (chosen, "client-ip", 0); sv = prom_getintdefault (chosen, "server-ip", 0); gw = prom_getintdefault (chosen, "gateway-ip", 0); -- cgit v1.2.1 From b8a83fcb78c859b99807af4c8b0ab09f0f827a40 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:42 -0400 Subject: sparc64: access tick function from variable In timer_64.c tick functions are access via pointer (tick_ops), every time clock is read, there is one extra load to get to the function. This patch optimizes it, by accessing functions pointer from value. Current ched_clock(): sethi %hi(0xb9b400), %g1 ldx [ %g1 + 0x250 ], %g1 ! ldx [ %g1 ], %g1 call %g1 nop sethi %hi(0xb9b400), %g1 ldx [ %g1 + 0x300 ], %g1 ! mulx %o0, %g1, %g1 rett %i7 + 8 srlx %g1, 0xa, %o0 New sched_clock(): sethi %hi(0xb9b400), %g1 ldx [ %g1 + 0x340 ], %g1 call %g1 nop sethi %hi(0xb9b400), %g1 ldx [ %g1 + 0x378 ], %g1 mulx %o0, %g1, %g1 rett %i7 + 8 srlx %g1, 0xa, %o0 Before three loads, now two loads. Signed-off-by: Pavel Tatashin Reviewed-by: Shannon Nelson Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/kernel/time_64.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 98d05de8da66..6724bcbc3526 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -585,6 +585,7 @@ fs_initcall(clock_init); /* This is gets the master TICK_INT timer going. */ static unsigned long sparc64_init_timers(void) { + struct sparc64_tick_ops *ops = NULL; struct device_node *dp; unsigned long freq; @@ -598,16 +599,17 @@ static unsigned long sparc64_init_timers(void) impl = ((ver >> 32) & 0xffff); if (manuf == 0x17 && impl == 0x13) { /* Hummingbird, aka Ultra-IIe */ - tick_ops = &hbtick_operations; + ops = &hbtick_operations; freq = of_getintprop_default(dp, "stick-frequency", 0); } else { - tick_ops = &tick_operations; freq = local_cpu_data().clock_tick; } } else { - tick_ops = &stick_operations; + ops = &stick_operations; freq = of_getintprop_default(dp, "stick-frequency", 0); } + if (ops) + memcpy(&tick_operations, ops, sizeof(struct sparc64_tick_ops)); return freq; } @@ -671,12 +673,12 @@ core_initcall(register_sparc64_cpufreq_notifier); static int sparc64_next_event(unsigned long delta, struct clock_event_device *evt) { - return tick_ops->add_compare(delta) ? -ETIME : 0; + return tick_operations.add_compare(delta) ? -ETIME : 0; } static int sparc64_timer_shutdown(struct clock_event_device *evt) { - tick_ops->disable_irq(); + tick_operations.disable_irq(); return 0; } @@ -693,7 +695,7 @@ static DEFINE_PER_CPU(struct clock_event_device, sparc64_events); void __irq_entry timer_interrupt(int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - unsigned long tick_mask = tick_ops->softint_mask; + unsigned long tick_mask = tick_operations.softint_mask; int cpu = smp_processor_id(); struct clock_event_device *evt = &per_cpu(sparc64_events, cpu); @@ -728,7 +730,7 @@ void setup_sparc64_timer(void) : "=r" (pstate) : "i" (PSTATE_IE)); - tick_ops->init_tick(); + tick_operations.init_tick(); /* Restore PSTATE_IE. */ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" @@ -757,9 +759,9 @@ void __delay(unsigned long loops) { unsigned long bclock, now; - bclock = tick_ops->get_tick(); + bclock = tick_operations.get_tick(); do { - now = tick_ops->get_tick(); + now = tick_operations.get_tick(); } while ((now-bclock) < loops); } EXPORT_SYMBOL(__delay); @@ -772,7 +774,7 @@ EXPORT_SYMBOL(udelay); static u64 clocksource_tick_read(struct clocksource *cs) { - return tick_ops->get_tick(); + return tick_operations.get_tick(); } void __init time_init(void) @@ -784,14 +786,14 @@ void __init time_init(void) timer_ticks_per_nsec_quotient = clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); - clocksource_tick.name = tick_ops->name; + clocksource_tick.name = tick_operations.name; clocksource_tick.read = clocksource_tick_read; clocksource_register_hz(&clocksource_tick, freq); printk("clocksource: mult[%x] shift[%d]\n", clocksource_tick.mult, clocksource_tick.shift); - sparc64_clockevent.name = tick_ops->name; + sparc64_clockevent.name = tick_operations.name; clockevents_calc_mult_shift(&sparc64_clockevent, freq, 4); sparc64_clockevent.max_delta_ns = @@ -809,7 +811,7 @@ void __init time_init(void) unsigned long long sched_clock(void) { - unsigned long ticks = tick_ops->get_tick(); + unsigned long ticks = tick_operations.get_tick(); return (ticks * timer_ticks_per_nsec_quotient) >> SPARC64_NSEC_PER_CYC_SHIFT; @@ -817,6 +819,6 @@ unsigned long long sched_clock(void) int read_current_timer(unsigned long *timer_val) { - *timer_val = tick_ops->get_tick(); + *timer_val = tick_operations.get_tick(); return 0; } -- cgit v1.2.1 From b5dd4d807f0fe7da67c5cc67b2ec681b60e4994b Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:43 -0400 Subject: sparc64: show time stamps from zero On most platforms, time is shown from the beginning of boot. This patch is adding offset to sched_clock() for SPARC, to also show time from 0. This means we will have one more load, but we saved one in an ealier patch. Signed-off-by: Pavel Tatashin Reviewed-by: Bob Picco Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/kernel/time_64.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 6724bcbc3526..5f53b74dd493 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -392,6 +392,7 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = { }; static unsigned long timer_ticks_per_nsec_quotient __read_mostly; +static unsigned long timer_offset __read_mostly; unsigned long cmos_regs; EXPORT_SYMBOL(cmos_regs); @@ -786,6 +787,10 @@ void __init time_init(void) timer_ticks_per_nsec_quotient = clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); + timer_offset = (tick_operations.get_tick() + * timer_ticks_per_nsec_quotient) + >> SPARC64_NSEC_PER_CYC_SHIFT; + clocksource_tick.name = tick_operations.name; clocksource_tick.read = clocksource_tick_read; @@ -813,8 +818,9 @@ unsigned long long sched_clock(void) { unsigned long ticks = tick_operations.get_tick(); - return (ticks * timer_ticks_per_nsec_quotient) - >> SPARC64_NSEC_PER_CYC_SHIFT; + return ((ticks * timer_ticks_per_nsec_quotient) + >> SPARC64_NSEC_PER_CYC_SHIFT) + - timer_offset; } int read_current_timer(unsigned long *timer_val) -- cgit v1.2.1 From 178bf2b9a20e866677bbca5cb521b09a8498c1d7 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:44 -0400 Subject: sparc64: optimize loads in clock_sched() In clock sched we now have three loads: - Function pointer - quotient for multiplication - offset However, it is possible to improve performance substantially, by guaranteeing that all three loads are from the same cacheline. By moving these three values first in sparc64_tick_ops, and by having tick_operations 64-byte aligned we guarantee this. Signed-off-by: Pavel Tatashin Reviewed-by: Shannon Nelson Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/include/asm/timer_64.h | 5 +++++ arch/sparc/kernel/time_64.c | 17 +++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/timer_64.h b/arch/sparc/include/asm/timer_64.h index fce415034000..bde2cc40ae02 100644 --- a/arch/sparc/include/asm/timer_64.h +++ b/arch/sparc/include/asm/timer_64.h @@ -9,7 +9,12 @@ #include #include +/* The most frequently accessed fields should be first, + * to fit into the same cacheline. + */ struct sparc64_tick_ops { + unsigned long ticks_per_nsec_quotient; + unsigned long offset; unsigned long long (*get_tick)(void); int (*add_compare)(unsigned long); unsigned long softint_mask; diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 5f53b74dd493..44e37e9f8428 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -164,7 +164,7 @@ static unsigned long tick_add_tick(unsigned long adj) return new_tick; } -static struct sparc64_tick_ops tick_operations __read_mostly = { +static struct sparc64_tick_ops tick_operations __cacheline_aligned = { .name = "tick", .init_tick = tick_init_tick, .disable_irq = tick_disable_irq, @@ -391,9 +391,6 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = { .softint_mask = 1UL << 0, }; -static unsigned long timer_ticks_per_nsec_quotient __read_mostly; -static unsigned long timer_offset __read_mostly; - unsigned long cmos_regs; EXPORT_SYMBOL(cmos_regs); @@ -784,11 +781,11 @@ void __init time_init(void) tb_ticks_per_usec = freq / USEC_PER_SEC; - timer_ticks_per_nsec_quotient = + tick_operations.ticks_per_nsec_quotient = clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); - timer_offset = (tick_operations.get_tick() - * timer_ticks_per_nsec_quotient) + tick_operations.offset = (tick_operations.get_tick() + * tick_operations.ticks_per_nsec_quotient) >> SPARC64_NSEC_PER_CYC_SHIFT; clocksource_tick.name = tick_operations.name; @@ -816,11 +813,11 @@ void __init time_init(void) unsigned long long sched_clock(void) { + unsigned long quotient = tick_operations.ticks_per_nsec_quotient; + unsigned long offset = tick_operations.offset; unsigned long ticks = tick_operations.get_tick(); - return ((ticks * timer_ticks_per_nsec_quotient) - >> SPARC64_NSEC_PER_CYC_SHIFT) - - timer_offset; + return ((ticks * quotient) >> SPARC64_NSEC_PER_CYC_SHIFT) - offset; } int read_current_timer(unsigned long *timer_val) -- cgit v1.2.1 From 89108c3423e8047cd0da73182ea09b9da190b57e Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:45 -0400 Subject: sparc64: improve modularity tick options This patch prepares the code for early boot time stamps by making it more modular. - init_tick_ops() to initialize struct sparc64_tick_ops - new sparc64_tick_ops operation get_frequency() which returns a frequency Signed-off-by: Pavel Tatashin Reviewed-by: Bob Picco Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/include/asm/timer_64.h | 2 + arch/sparc/kernel/time_64.c | 83 ++++++++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 28 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/timer_64.h b/arch/sparc/include/asm/timer_64.h index bde2cc40ae02..61d07251792c 100644 --- a/arch/sparc/include/asm/timer_64.h +++ b/arch/sparc/include/asm/timer_64.h @@ -22,6 +22,8 @@ struct sparc64_tick_ops { void (*init_tick)(void); unsigned long (*add_tick)(unsigned long); + unsigned long (*get_frequency)(void); + unsigned long frequency; char *name; }; diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 44e37e9f8428..3bd9e499755b 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -164,6 +164,11 @@ static unsigned long tick_add_tick(unsigned long adj) return new_tick; } +static unsigned long tick_get_frequency(void) +{ + return local_cpu_data().clock_tick; +} + static struct sparc64_tick_ops tick_operations __cacheline_aligned = { .name = "tick", .init_tick = tick_init_tick, @@ -171,6 +176,7 @@ static struct sparc64_tick_ops tick_operations __cacheline_aligned = { .get_tick = tick_get_tick, .add_tick = tick_add_tick, .add_compare = tick_add_compare, + .get_frequency = tick_get_frequency, .softint_mask = 1UL << 0, }; @@ -250,6 +256,13 @@ static int stick_add_compare(unsigned long adj) return ((long)(new_tick - (orig_tick+adj))) > 0L; } +static unsigned long stick_get_frequency(void) +{ + struct device_node *dp = of_find_node_by_path("/"); + + return of_getintprop_default(dp, "stick-frequency", 0); +} + static struct sparc64_tick_ops stick_operations __read_mostly = { .name = "stick", .init_tick = stick_init_tick, @@ -257,6 +270,7 @@ static struct sparc64_tick_ops stick_operations __read_mostly = { .get_tick = stick_get_tick, .add_tick = stick_add_tick, .add_compare = stick_add_compare, + .get_frequency = stick_get_frequency, .softint_mask = 1UL << 16, }; @@ -381,6 +395,13 @@ static int hbtick_add_compare(unsigned long adj) return ((long)(val2 - val)) > 0L; } +static unsigned long hbtick_get_frequency(void) +{ + struct device_node *dp = of_find_node_by_path("/"); + + return of_getintprop_default(dp, "stick-frequency", 0); +} + static struct sparc64_tick_ops hbtick_operations __read_mostly = { .name = "hbtick", .init_tick = hbtick_init_tick, @@ -388,6 +409,7 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = { .get_tick = hbtick_get_tick, .add_tick = hbtick_add_tick, .add_compare = hbtick_add_compare, + .get_frequency = hbtick_get_frequency, .softint_mask = 1UL << 0, }; @@ -580,36 +602,17 @@ static int __init clock_init(void) */ fs_initcall(clock_init); -/* This is gets the master TICK_INT timer going. */ -static unsigned long sparc64_init_timers(void) +/* Return true if this is Hummingbird, aka Ultra-IIe */ +static bool is_hummingbird(void) { - struct sparc64_tick_ops *ops = NULL; - struct device_node *dp; - unsigned long freq; + unsigned long ver, manuf, impl; - dp = of_find_node_by_path("/"); - if (tlb_type == spitfire) { - unsigned long ver, manuf, impl; - - __asm__ __volatile__ ("rdpr %%ver, %0" - : "=&r" (ver)); - manuf = ((ver >> 48) & 0xffff); - impl = ((ver >> 32) & 0xffff); - if (manuf == 0x17 && impl == 0x13) { - /* Hummingbird, aka Ultra-IIe */ - ops = &hbtick_operations; - freq = of_getintprop_default(dp, "stick-frequency", 0); - } else { - freq = local_cpu_data().clock_tick; - } - } else { - ops = &stick_operations; - freq = of_getintprop_default(dp, "stick-frequency", 0); - } - if (ops) - memcpy(&tick_operations, ops, sizeof(struct sparc64_tick_ops)); + __asm__ __volatile__ ("rdpr %%ver, %0" + : "=&r" (ver)); + manuf = ((ver >> 48) & 0xffff); + impl = ((ver >> 32) & 0xffff); - return freq; + return (manuf == 0x17 && impl == 0x13); } struct freq_table { @@ -775,10 +778,34 @@ static u64 clocksource_tick_read(struct clocksource *cs) return tick_operations.get_tick(); } +static void init_tick_ops(struct sparc64_tick_ops *ops) +{ + unsigned long freq, quotient, tick; + + freq = ops->get_frequency(); + quotient = clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); + tick = ops->get_tick(); + + ops->offset = (tick * quotient) >> SPARC64_NSEC_PER_CYC_SHIFT; + ops->ticks_per_nsec_quotient = quotient; + ops->frequency = freq; + tick_operations = *ops; +} + void __init time_init(void) { - unsigned long freq = sparc64_init_timers(); + unsigned long freq; + + if (tlb_type == spitfire) { + if (is_hummingbird()) + init_tick_ops(&hbtick_operations); + else + init_tick_ops(&tick_operations); + } else { + init_tick_ops(&stick_operations); + } + freq = tick_operations.frequency; tb_ticks_per_usec = freq / USEC_PER_SEC; tick_operations.ticks_per_nsec_quotient = -- cgit v1.2.1 From 83e8eb99d908da78e6eff7dd141f26626fe01d12 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:46 -0400 Subject: sparc64: initialize time early In Linux it is possible to configure printk() to output timestamp next to every line. This is very useful to determine the slow parts of the boot process, and also to avoid regressions, as boot time is visiable to everyone. Also, there are scripts that change these time stamps to intervals. However, on larger machines these timestamps start appearing many seconds, and even minutes into the boot process. This patch gets stick-frequency property early from OpenBoot, and uses its value to initialize time stamps before the first printk() messages are printed. Signed-off-by: Pavel Tatashin Reviewed-by: Shannon Nelson Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/kernel/kernel.h | 3 +++ arch/sparc/kernel/setup_64.c | 1 + arch/sparc/kernel/time_64.c | 21 ++++++++------------- 3 files changed, 12 insertions(+), 13 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index 6ae1e77be0bf..b625db4cfb78 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -52,6 +52,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs); void do_signal32(struct pt_regs * regs); asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp); +/* time_64.c */ +void __init time_init_early(void); + /* compat_audit.c */ extern unsigned int sparc32_dir_class[]; extern unsigned int sparc32_chattr_class[]; diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 4a85f9241a2a..4d9c3e13c150 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -365,6 +365,7 @@ void __init start_early_boot(void) } current_thread_info()->cpu = cpu; + time_init_early(); prom_init_report(); start_kernel(); } diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 3bd9e499755b..d149276ddd80 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -49,6 +49,7 @@ #include #include "entry.h" +#include "kernel.h" DEFINE_SPINLOCK(rtc_lock); @@ -258,9 +259,7 @@ static int stick_add_compare(unsigned long adj) static unsigned long stick_get_frequency(void) { - struct device_node *dp = of_find_node_by_path("/"); - - return of_getintprop_default(dp, "stick-frequency", 0); + return prom_getint(prom_root_node, "stick-frequency"); } static struct sparc64_tick_ops stick_operations __read_mostly = { @@ -792,10 +791,8 @@ static void init_tick_ops(struct sparc64_tick_ops *ops) tick_operations = *ops; } -void __init time_init(void) +void __init time_init_early(void) { - unsigned long freq; - if (tlb_type == spitfire) { if (is_hummingbird()) init_tick_ops(&hbtick_operations); @@ -804,17 +801,15 @@ void __init time_init(void) } else { init_tick_ops(&stick_operations); } +} + +void __init time_init(void) +{ + unsigned long freq; freq = tick_operations.frequency; tb_ticks_per_usec = freq / USEC_PER_SEC; - tick_operations.ticks_per_nsec_quotient = - clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); - - tick_operations.offset = (tick_operations.get_tick() - * tick_operations.ticks_per_nsec_quotient) - >> SPARC64_NSEC_PER_CYC_SHIFT; - clocksource_tick.name = tick_operations.name; clocksource_tick.read = clocksource_tick_read; -- cgit v1.2.1 From 4929c83a6ce6584cb64381bf1407c487f67d588a Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:47 -0400 Subject: sparc64: add hot-patched and inlined get_tick() Add the new get_tick() function that is hot-patched during boot based on processor we are booting on. Signed-off-by: Pavel Tatashin Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/include/asm/timer_64.h | 60 +++++++++++++++++++++++++++++++++++++++ arch/sparc/kernel/time_64.c | 28 ++++++++++++++---- arch/sparc/kernel/vmlinux.lds.S | 5 ++++ 3 files changed, 87 insertions(+), 6 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/timer_64.h b/arch/sparc/include/asm/timer_64.h index 61d07251792c..51bc3bc54bfe 100644 --- a/arch/sparc/include/asm/timer_64.h +++ b/arch/sparc/include/asm/timer_64.h @@ -34,4 +34,64 @@ unsigned long sparc64_get_clock_tick(unsigned int cpu); void setup_sparc64_timer(void); void __init time_init(void); +#define TICK_PRIV_BIT BIT(63) +#define TICKCMP_IRQ_BIT BIT(63) + +#define HBIRD_STICKCMP_ADDR 0x1fe0000f060UL +#define HBIRD_STICK_ADDR 0x1fe0000f070UL + +#define GET_TICK_NINSTR 13 +struct get_tick_patch { + unsigned int addr; + unsigned int tick[GET_TICK_NINSTR]; + unsigned int stick[GET_TICK_NINSTR]; +}; + +extern struct get_tick_patch __get_tick_patch; +extern struct get_tick_patch __get_tick_patch_end; + +static inline unsigned long get_tick(void) +{ + unsigned long tick, tmp1, tmp2; + + __asm__ __volatile__( + /* read hbtick 13 instructions */ + "661:\n" + " mov 0x1fe, %1\n" + " sllx %1, 0x20, %1\n" + " sethi %%hi(0xf000), %2\n" + " or %2, 0x70, %2\n" + " or %1, %2, %1\n" /* %1 = HBIRD_STICK_ADDR */ + " add %1, 8, %2\n" + " ldxa [%2]%3, %0\n" + " ldxa [%1]%3, %1\n" + " ldxa [%2]%3, %2\n" + " sub %2, %0, %0\n" /* don't modify %xcc */ + " brnz,pn %0, 661b\n" /* restart to save one register */ + " sllx %2, 32, %2\n" + " or %2, %1, %0\n" + /* Common/not patched code */ + " sllx %0, 1, %0\n" + " srlx %0, 1, %0\n" /* Clear TICK_PRIV_BIT */ + /* Beginning of patch section */ + " .section .get_tick_patch, \"ax\"\n" + " .word 661b\n" + /* read tick 2 instructions and 11 skipped */ + " ba 1f\n" + " rd %%tick, %0\n" + " .skip 4 * (%4 - 2)\n" + "1:\n" + /* read stick 2 instructions and 11 skipped */ + " ba 1f\n" + " rd %%asr24, %0\n" + " .skip 4 * (%4 - 2)\n" + "1:\n" + /* End of patch section */ + " .previous\n" + : "=&r" (tick), "=&r" (tmp1), "=&r" (tmp2) + : "i" (ASI_PHYS_BYPASS_EC_E), "i" (GET_TICK_NINSTR)); + + return tick; +} + #endif /* _SPARC64_TIMER_H */ diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index d149276ddd80..ca27415c393a 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -47,15 +47,13 @@ #include #include #include +#include #include "entry.h" #include "kernel.h" DEFINE_SPINLOCK(rtc_lock); -#define TICK_PRIV_BIT (1UL << 63) -#define TICKCMP_IRQ_BIT (1UL << 63) - #ifdef CONFIG_SMP unsigned long profile_pc(struct pt_regs *regs) { @@ -290,9 +288,6 @@ static struct sparc64_tick_ops stick_operations __read_mostly = { * 2) write high * 3) write low */ -#define HBIRD_STICKCMP_ADDR 0x1fe0000f060UL -#define HBIRD_STICK_ADDR 0x1fe0000f070UL - static unsigned long __hbird_read_stick(void) { unsigned long ret, tmp1, tmp2, tmp3; @@ -777,6 +772,26 @@ static u64 clocksource_tick_read(struct clocksource *cs) return tick_operations.get_tick(); } +static void __init get_tick_patch(void) +{ + unsigned int *addr, *instr, i; + struct get_tick_patch *p; + + if (tlb_type == spitfire && is_hummingbird()) + return; + + for (p = &__get_tick_patch; p < &__get_tick_patch_end; p++) { + instr = (tlb_type == spitfire) ? p->tick : p->stick; + addr = (unsigned int *)(unsigned long)p->addr; + for (i = 0; i < GET_TICK_NINSTR; i++) { + addr[i] = instr[i]; + /* ensure that address is modified before flush */ + wmb(); + flushi(&addr[i]); + } + } +} + static void init_tick_ops(struct sparc64_tick_ops *ops) { unsigned long freq, quotient, tick; @@ -789,6 +804,7 @@ static void init_tick_ops(struct sparc64_tick_ops *ops) ops->ticks_per_nsec_quotient = quotient; ops->frequency = freq; tick_operations = *ops; + get_tick_patch(); } void __init time_init_early(void) diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index 572db686f845..03b3d65d1266 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -149,6 +149,11 @@ SECTIONS *(.sun_m7_2insn_patch) __sun_m7_2insn_patch_end = .; } + .get_tick_patch : { + __get_tick_patch = .; + *(.get_tick_patch) + __get_tick_patch_end = .; + } PERCPU_SECTION(SMP_CACHE_BYTES) #ifdef CONFIG_JUMP_LABEL -- cgit v1.2.1 From eae3fc9871111e9bbc77dad5481a3e805e02ac46 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Mon, 12 Jun 2017 16:41:48 -0400 Subject: sparc64: optimize functions that access tick Replace read tick function pointers with the new hot-patched get_tick(). This optimizes the performance of functions such as: sched_clock() Signed-off-by: Pavel Tatashin Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/kernel/time_64.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index ca27415c393a..a612a91cb9cd 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -752,12 +752,10 @@ static unsigned long tb_ticks_per_usec __read_mostly; void __delay(unsigned long loops) { - unsigned long bclock, now; + unsigned long bclock = get_tick(); - bclock = tick_operations.get_tick(); - do { - now = tick_operations.get_tick(); - } while ((now-bclock) < loops); + while ((get_tick() - bclock) < loops) + ; } EXPORT_SYMBOL(__delay); @@ -769,7 +767,7 @@ EXPORT_SYMBOL(udelay); static u64 clocksource_tick_read(struct clocksource *cs) { - return tick_operations.get_tick(); + return get_tick(); } static void __init get_tick_patch(void) @@ -853,13 +851,19 @@ unsigned long long sched_clock(void) { unsigned long quotient = tick_operations.ticks_per_nsec_quotient; unsigned long offset = tick_operations.offset; - unsigned long ticks = tick_operations.get_tick(); - return ((ticks * quotient) >> SPARC64_NSEC_PER_CYC_SHIFT) - offset; + /* Use barrier so the compiler emits the loads first and overlaps load + * latency with reading tick, because reading %tick/%stick is a + * post-sync instruction that will flush and restart subsequent + * instructions after it commits. + */ + barrier(); + + return ((get_tick() * quotient) >> SPARC64_NSEC_PER_CYC_SHIFT) - offset; } int read_current_timer(unsigned long *timer_val) { - *timer_val = tick_operations.get_tick(); + *timer_val = get_tick(); return 0; } -- cgit v1.2.1 From fca4afe400cb68fe5a7f0a97fb1ba5cfdcb81675 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Thu, 15 Jun 2017 10:40:58 -0400 Subject: sparc64: use prom interface to get %stick frequency We initialize time early, we must use prom interface instead of open firmware driver, which is not yet initialized. Also, use prom_getintdefault() instead of prom_getint() to be compatible with the code before early boot timestamps project. Signed-off-by: Pavel Tatashin Signed-off-by: David S. Miller --- arch/sparc/kernel/time_64.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index a612a91cb9cd..a62758ce9e19 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -257,7 +256,7 @@ static int stick_add_compare(unsigned long adj) static unsigned long stick_get_frequency(void) { - return prom_getint(prom_root_node, "stick-frequency"); + return prom_getintdefault(prom_root_node, "stick-frequency", 0); } static struct sparc64_tick_ops stick_operations __read_mostly = { @@ -391,9 +390,7 @@ static int hbtick_add_compare(unsigned long adj) static unsigned long hbtick_get_frequency(void) { - struct device_node *dp = of_find_node_by_path("/"); - - return of_getintprop_default(dp, "stick-frequency", 0); + return prom_getintdefault(prom_root_node, "stick-frequency", 0); } static struct sparc64_tick_ops hbtick_operations __read_mostly = { -- cgit v1.2.1 From eea9833453bd39e2f35325abb985d00486c8aa69 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Thu, 15 Jun 2017 10:40:59 -0400 Subject: sparc64: broken %tick frequency on spitfire cpus After early boot time stamps project the %tick frequency is detected incorrectly on spittfire cpus. We must use cpuid of boot cpu to find corresponding cpu node in OpenBoot, and extract clock-frequency property from there. Signed-off-by: Pavel Tatashin Signed-off-by: David S. Miller --- arch/sparc/kernel/time_64.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index a62758ce9e19..f584c53e769a 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -162,9 +162,34 @@ static unsigned long tick_add_tick(unsigned long adj) return new_tick; } +/* Searches for cpu clock frequency with given cpuid in OpenBoot tree */ +static unsigned long cpuid_to_freq(phandle node, int cpuid) +{ + bool is_cpu_node = false; + unsigned long freq = 0; + char type[128]; + + if (!node) + return freq; + + if (prom_getproperty(node, "device_type", type, sizeof(type)) != -1) + is_cpu_node = (strcmp(type, "cpu") == 0); + + /* try upa-portis then cpuid to get cpuid, see prom_64.c */ + if (is_cpu_node && (prom_getint(node, "upa-portis") == cpuid || + prom_getint(node, "cpuid") == cpuid)) + freq = prom_getintdefault(node, "clock-frequency", 0); + if (!freq) + freq = cpuid_to_freq(prom_getchild(node), cpuid); + if (!freq) + freq = cpuid_to_freq(prom_getsibling(node), cpuid); + + return freq; +} + static unsigned long tick_get_frequency(void) { - return local_cpu_data().clock_tick; + return cpuid_to_freq(prom_root_node, hard_smp_processor_id()); } static struct sparc64_tick_ops tick_operations __cacheline_aligned = { -- cgit v1.2.1 From c55c5ddedba0c393683910eeeb760903d0d1f827 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 15 Jun 2017 16:30:20 +0530 Subject: sparc/time: make of_device_ids const of_device_ids are not supposed to change at runtime. All functions working with of_device_ids provided by work with const of_device_ids. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: David S. Miller --- arch/sparc/kernel/time_32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index 9f575dfc2e41..2ce2e7b2abbb 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c @@ -298,7 +298,7 @@ static int clock_probe(struct platform_device *op) return 0; } -static struct of_device_id clock_match[] = { +static const struct of_device_id clock_match[] = { { .name = "eeprom", }, -- cgit v1.2.1 From 69f579786d2935989ab7005c7b5cdf9f06177689 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 23 Jun 2017 14:51:35 +0530 Subject: sparc: kernel: apc: make of_device_ids const of_device_ids are not supposed to change at runtime. All functions working with of_device_ids provided by work with const of_device_ids. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: David S. Miller --- arch/sparc/kernel/apc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index 9ebc37e7d64c..c988e7fa069b 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -167,7 +167,7 @@ static int apc_probe(struct platform_device *op) return 0; } -static struct of_device_id apc_match[] = { +static const struct of_device_id apc_match[] = { { .name = APC_OBPNAME, }, -- cgit v1.2.1 From 7b6e04a3edc140a82f5e0e29e59d6dc90a629d34 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:29 -0400 Subject: sparc64: ensure VIO operations are defined while being used It's possible that VIO operations are not defined for some VIO clients. In that case, VIO ops pointer should be checked for NULL before being used Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/kernel/viohs.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/viohs.c b/arch/sparc/kernel/viohs.c index b30b30ab3ddd..ea28cb7118bd 100644 --- a/arch/sparc/kernel/viohs.c +++ b/arch/sparc/kernel/viohs.c @@ -223,6 +223,9 @@ static int send_rdx(struct vio_driver_state *vio) static int send_attr(struct vio_driver_state *vio) { + if (!vio->ops) + return -EINVAL; + return vio->ops->send_attr(vio); } @@ -374,6 +377,9 @@ static int process_attr(struct vio_driver_state *vio, void *pkt) if (!(vio->hs_state & VIO_HS_GOTVERS)) return handshake_failure(vio); + if (!vio->ops) + return 0; + err = vio->ops->handle_attr(vio, pkt); if (err < 0) { return handshake_failure(vio); @@ -388,6 +394,7 @@ static int process_attr(struct vio_driver_state *vio, void *pkt) vio->hs_state |= VIO_HS_SENT_DREG; } } + return 0; } @@ -647,10 +654,13 @@ int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt) err = process_unknown(vio, pkt); break; } + if (!err && vio->hs_state != prev_state && - (vio->hs_state & VIO_HS_COMPLETE)) - vio->ops->handshake_complete(vio); + (vio->hs_state & VIO_HS_COMPLETE)) { + if (vio->ops) + vio->ops->handshake_complete(vio); + } return err; } @@ -805,8 +815,7 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev, return -EINVAL; } - if (!ops->send_attr || - !ops->handle_attr || + if (!ops || !ops->send_attr || !ops->handle_attr || !ops->handshake_complete) return -EINVAL; -- cgit v1.2.1 From ac6bb0255430f701ea3723aac5dd06f528078567 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:30 -0400 Subject: sparc64: specify the device class in VIO version info. packet Specify the class of VIO device in the version info. packet. The device's class identifies the type of VIO device, whether it's DISK, CONSOLE, NETWORK, etc... This packet is used in the handshake between the client and server for this device. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/kernel/viohs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/viohs.c b/arch/sparc/kernel/viohs.c index ea28cb7118bd..68e952a7bcdb 100644 --- a/arch/sparc/kernel/viohs.c +++ b/arch/sparc/kernel/viohs.c @@ -286,6 +286,7 @@ static int process_ver_info(struct vio_driver_state *vio, ver.minor = vap->minor; pkt->minor = ver.minor; pkt->tag.stype = VIO_SUBTYPE_ACK; + pkt->dev_class = vio->dev_class; viodbg(HS, "SEND VERSION ACK maj[%u] min[%u]\n", pkt->major, pkt->minor); err = send_ctrl(vio, &pkt->tag, sizeof(*pkt)); -- cgit v1.2.1 From 01b7a471382c529f60f5965ecfed9a14bfccf1ab Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:31 -0400 Subject: sparc64: skip handshake for LDC channels in RAW mode LDC channels in RAW mode does not provide any session management. No handshake protocol is defined for LDC channels in RAW mode. It's therefore skipped. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/kernel/ldc.c | 10 ++++++++++ arch/sparc/kernel/viohs.c | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 97a5743b04e2..840e0b21bfe3 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1347,6 +1347,14 @@ int ldc_bind(struct ldc_channel *lp) lp->hs_state = LDC_HS_OPEN; ldc_set_state(lp, LDC_STATE_BOUND); + if (lp->cfg.mode == LDC_MODE_RAW) { + /* + * There is no handshake in RAW mode, so handshake + * is completed. + */ + lp->hs_state = LDC_HS_COMPLETE; + } + spin_unlock_irqrestore(&lp->lock, flags); return 0; @@ -1460,11 +1468,13 @@ void ldc_set_state(struct ldc_channel *lp, u8 state) lp->state = state; } +EXPORT_SYMBOL(ldc_set_state); int ldc_mode(struct ldc_channel *lp) { return lp->cfg.mode; } +EXPORT_SYMBOL(ldc_mode); int ldc_rx_reset(struct ldc_channel *lp) { diff --git a/arch/sparc/kernel/viohs.c b/arch/sparc/kernel/viohs.c index 68e952a7bcdb..d4f13c037a40 100644 --- a/arch/sparc/kernel/viohs.c +++ b/arch/sparc/kernel/viohs.c @@ -776,7 +776,11 @@ void vio_port_up(struct vio_driver_state *vio) } if (!err) { - err = ldc_connect(vio->lp); + if (ldc_mode(vio->lp) == LDC_MODE_RAW) + ldc_set_state(vio->lp, LDC_STATE_CONNECTED); + else + err = ldc_connect(vio->lp); + if (err) printk(KERN_WARNING "%s: Port %lu connect failed, " "err=%d\n", -- cgit v1.2.1 From 411cb4a0b3b12833731abc71059a7eeb04dc8477 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:32 -0400 Subject: sparc64: expand MDESC interface Add the following two APIs to Machine Description (MDESC) - mdesc_get_node: Searches for a node in the Machine Description tree based on given information about that node. - mdesc_get_node_info: Retrieves information about a given node. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/include/asm/mdesc.h | 17 ++++ arch/sparc/kernel/mdesc.c | 216 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/mdesc.h b/arch/sparc/include/asm/mdesc.h index aebeb88f70db..68d19909d1cd 100644 --- a/arch/sparc/include/asm/mdesc.h +++ b/arch/sparc/include/asm/mdesc.h @@ -16,6 +16,7 @@ struct mdesc_handle *mdesc_grab(void); void mdesc_release(struct mdesc_handle *); #define MDESC_NODE_NULL (~(u64)0) +#define MDESC_MAX_STR_LEN 256 u64 mdesc_node_by_name(struct mdesc_handle *handle, u64 from_node, const char *name); @@ -71,6 +72,22 @@ struct mdesc_notifier_client { void mdesc_register_notifier(struct mdesc_notifier_client *client); +union md_node_info { + struct vdev_port { + u64 id; /* id */ + u64 parent_cfg_hdl; /* parent config handle */ + const char *name; /* name (property) */ + } vdev_port; + struct ds_port { + u64 id; /* id */ + } ds_port; +}; + +u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name, + union md_node_info *node_info); +int mdesc_get_node_info(struct mdesc_handle *hp, u64 node, + const char *node_name, union md_node_info *node_info); + void mdesc_fill_in_cpu_data(cpumask_t *mask); void mdesc_populate_present_mask(cpumask_t *mask); void mdesc_get_page_sizes(cpumask_t *mask, unsigned long *pgsz_mask); diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index c0765bbf60ea..72aca731657f 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -75,6 +75,74 @@ struct mdesc_handle { struct mdesc_hdr mdesc; }; +typedef int (*mdesc_node_info_get_f)(struct mdesc_handle *, u64, + union md_node_info *); +typedef void (*mdesc_node_info_rel_f)(union md_node_info *); +typedef bool (*mdesc_node_match_f)(union md_node_info *, union md_node_info *); + +struct md_node_ops { + char *name; + mdesc_node_info_get_f get_info; + mdesc_node_info_rel_f rel_info; + mdesc_node_match_f node_match; +}; + +static int get_vdev_port_node_info(struct mdesc_handle *md, u64 node, + union md_node_info *node_info); +static void rel_vdev_port_node_info(union md_node_info *node_info); +static bool vdev_port_node_match(union md_node_info *a_node_info, + union md_node_info *b_node_info); + +static int get_ds_port_node_info(struct mdesc_handle *md, u64 node, + union md_node_info *node_info); +static void rel_ds_port_node_info(union md_node_info *node_info); +static bool ds_port_node_match(union md_node_info *a_node_info, + union md_node_info *b_node_info); + +/* supported node types which can be registered */ +static struct md_node_ops md_node_ops_table[] = { + {"virtual-device-port", get_vdev_port_node_info, + rel_vdev_port_node_info, vdev_port_node_match}, + {"domain-services-port", get_ds_port_node_info, + rel_ds_port_node_info, ds_port_node_match}, + {NULL, NULL, NULL, NULL} +}; + +static void mdesc_get_node_ops(const char *node_name, + mdesc_node_info_get_f *get_info_f, + mdesc_node_info_rel_f *rel_info_f, + mdesc_node_match_f *match_f) +{ + int i; + + if (get_info_f) + *get_info_f = NULL; + + if (rel_info_f) + *rel_info_f = NULL; + + if (match_f) + *match_f = NULL; + + if (!node_name) + return; + + for (i = 0; md_node_ops_table[i].name != NULL; i++) { + if (strcmp(md_node_ops_table[i].name, node_name) == 0) { + if (get_info_f) + *get_info_f = md_node_ops_table[i].get_info; + + if (rel_info_f) + *rel_info_f = md_node_ops_table[i].rel_info; + + if (match_f) + *match_f = md_node_ops_table[i].node_match; + + break; + } + } +} + static void mdesc_handle_init(struct mdesc_handle *hp, unsigned int handle_size, void *base) @@ -249,6 +317,86 @@ static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node) return id; } +static int get_vdev_port_node_info(struct mdesc_handle *md, u64 node, + union md_node_info *node_info) +{ + const u64 *parent_cfg_hdlp; + const char *name; + const u64 *idp; + + /* + * Virtual device nodes are distinguished by: + * 1. "id" property + * 2. "name" property + * 3. parent node "cfg-handle" property + */ + idp = mdesc_get_property(md, node, "id", NULL); + name = mdesc_get_property(md, node, "name", NULL); + parent_cfg_hdlp = parent_cfg_handle(md, node); + + if (!idp || !name || !parent_cfg_hdlp) + return -1; + + node_info->vdev_port.id = *idp; + node_info->vdev_port.name = kstrdup_const(name, GFP_KERNEL); + node_info->vdev_port.parent_cfg_hdl = *parent_cfg_hdlp; + + return 0; +} + +static void rel_vdev_port_node_info(union md_node_info *node_info) +{ + if (node_info && node_info->vdev_port.name) { + kfree_const(node_info->vdev_port.name); + node_info->vdev_port.name = NULL; + } +} + +static bool vdev_port_node_match(union md_node_info *a_node_info, + union md_node_info *b_node_info) +{ + if (a_node_info->vdev_port.id != b_node_info->vdev_port.id) + return false; + + if (a_node_info->vdev_port.parent_cfg_hdl != + b_node_info->vdev_port.parent_cfg_hdl) + return false; + + if (strncmp(a_node_info->vdev_port.name, + b_node_info->vdev_port.name, MDESC_MAX_STR_LEN) != 0) + return false; + + return true; +} + +static int get_ds_port_node_info(struct mdesc_handle *md, u64 node, + union md_node_info *node_info) +{ + const u64 *idp; + + /* DS port nodes use the "id" property to distinguish them */ + idp = mdesc_get_property(md, node, "id", NULL); + if (!idp) + return -1; + + node_info->ds_port.id = *idp; + + return 0; +} + +static void rel_ds_port_node_info(union md_node_info *node_info) +{ +} + +static bool ds_port_node_match(union md_node_info *a_node_info, + union md_node_info *b_node_info) +{ + if (a_node_info->ds_port.id != b_node_info->ds_port.id) + return false; + + return true; +} + /* Run 'func' on nodes which are in A but not in B. */ static void invoke_on_missing(const char *name, struct mdesc_handle *a, @@ -367,6 +515,74 @@ out: mutex_unlock(&mdesc_mutex); } +u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name, + union md_node_info *node_info) +{ + mdesc_node_info_get_f get_info_func; + mdesc_node_info_rel_f rel_info_func; + mdesc_node_match_f node_match_func; + union md_node_info hp_node_info; + u64 hp_node; + int rv; + + if (hp == NULL || node_name == NULL || node_info == NULL) + return MDESC_NODE_NULL; + + /* Find the ops for the given node name */ + mdesc_get_node_ops(node_name, &get_info_func, &rel_info_func, + &node_match_func); + + /* If we didn't find ops for the given node name, it is not supported */ + if (!get_info_func || !rel_info_func || !node_match_func) { + pr_err("MD: %s node is not supported\n", node_name); + return -EINVAL; + } + + mdesc_for_each_node_by_name(hp, hp_node, node_name) { + rv = get_info_func(hp, hp_node, &hp_node_info); + if (rv != 0) + continue; + + if (node_match_func(node_info, &hp_node_info)) + break; + + rel_info_func(&hp_node_info); + } + + rel_info_func(&hp_node_info); + + return hp_node; +} + +int mdesc_get_node_info(struct mdesc_handle *hp, u64 node, + const char *node_name, union md_node_info *node_info) +{ + mdesc_node_info_get_f get_info_func; + int rv; + + if (hp == NULL || node == MDESC_NODE_NULL || + node_name == NULL || node_info == NULL) + return -EINVAL; + + /* Find the get_info op for the given node name */ + mdesc_get_node_ops(node_name, &get_info_func, NULL, NULL); + + /* If we didn't find a get_info_func, the node name is not supported */ + if (get_info_func == NULL) { + pr_err("MD: %s node is not supported\n", node_name); + return -EINVAL; + } + + rv = get_info_func(hp, node, node_info); + if (rv != 0) { + pr_err("MD: Cannot find 1 or more required match properties for %s node.\n", + node_name); + return -1; + } + + return 0; +} + static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) { return (struct mdesc_elem *) (mdesc + 1); -- cgit v1.2.1 From 0ab2fcd69dbf1dad27a7cee0f608b48690134ced Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:33 -0400 Subject: sparc64: mdesc: use __GFP_REPEAT action modifier for VM allocation During MDESC handle allocation, use the __GFP_REPEAT flag instead of __GFP_NOFAIL. If memory is not available, the caller expects a NULL pointer instead of waiting until memory is allocated. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/kernel/mdesc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 72aca731657f..f0249691d000 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -205,12 +205,10 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size) handle_size = (sizeof(struct mdesc_handle) - sizeof(struct mdesc_hdr) + mdesc_size); + base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_REPEAT); + if (!base) + return NULL; - /* - * Allocation has to succeed because mdesc update would be missed - * and such events are not retransmitted. - */ - base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL); addr = (unsigned long)base; addr = (addr + 15UL) & ~15UL; hp = (struct mdesc_handle *) addr; -- cgit v1.2.1 From 06f3c3ac60111a2ebffdc6f6acf16847153c0589 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:34 -0400 Subject: sparc64: add MDESC node name property to VIO device metadata Add the MDESC node name of MDESC client to VIO device metadata. It is later used to uniquely identify a node in the MDESC. VIO & MDESC APIs are updated to handle this node name. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/include/asm/mdesc.h | 7 ++-- arch/sparc/include/asm/vio.h | 2 + arch/sparc/kernel/mdesc.c | 88 ++++++++++++++++++++++-------------------- arch/sparc/kernel/vio.c | 22 +++++++---- 4 files changed, 68 insertions(+), 51 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/mdesc.h b/arch/sparc/include/asm/mdesc.h index 68d19909d1cd..e8a4c413a1c7 100644 --- a/arch/sparc/include/asm/mdesc.h +++ b/arch/sparc/include/asm/mdesc.h @@ -63,9 +63,10 @@ u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc); void mdesc_update(void); struct mdesc_notifier_client { - void (*add)(struct mdesc_handle *handle, u64 node); - void (*remove)(struct mdesc_handle *handle, u64 node); - + void (*add)(struct mdesc_handle *handle, u64 node, + const char *node_name); + void (*remove)(struct mdesc_handle *handle, u64 node, + const char *node_name); const char *node_name; struct mdesc_notifier_client *next; }; diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 9dca7a892978..69cb3a5ff8cf 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -316,12 +316,14 @@ static inline u32 vio_dring_prev(struct vio_dring_state *dr, u32 index) } #define VIO_MAX_TYPE_LEN 32 +#define VIO_MAX_NAME_LEN 32 #define VIO_MAX_COMPAT_LEN 64 struct vio_dev { u64 mp; struct device_node *dp; + char node_name[VIO_MAX_NAME_LEN]; char type[VIO_MAX_TYPE_LEN]; char compat[VIO_MAX_COMPAT_LEN]; int compat_len; diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index f0249691d000..04b76267ddfa 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -291,7 +291,7 @@ void mdesc_register_notifier(struct mdesc_notifier_client *client) client_list = client; mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name) - client->add(cur_mdesc, node); + client->add(cur_mdesc, node, client->node_name); mutex_unlock(&mdesc_mutex); } @@ -399,55 +399,61 @@ static bool ds_port_node_match(union md_node_info *a_node_info, static void invoke_on_missing(const char *name, struct mdesc_handle *a, struct mdesc_handle *b, - void (*func)(struct mdesc_handle *, u64)) + void (*func)(struct mdesc_handle *, u64, + const char *node_name)) { - u64 node; + mdesc_node_info_get_f get_info_func; + mdesc_node_info_rel_f rel_info_func; + mdesc_node_match_f node_match_func; + union md_node_info a_node_info; + union md_node_info b_node_info; + bool found; + u64 a_node; + u64 b_node; + int rv; - mdesc_for_each_node_by_name(a, node, name) { - int found = 0, is_vdc_port = 0; - const char *name_prop; - const u64 *id; - u64 fnode; - - name_prop = mdesc_get_property(a, node, "name", NULL); - if (name_prop && !strcmp(name_prop, "vdc-port")) { - is_vdc_port = 1; - id = parent_cfg_handle(a, node); - } else - id = mdesc_get_property(a, node, "id", NULL); - - if (!id) { - printk(KERN_ERR "MD: Cannot find ID for %s node.\n", - (name_prop ? name_prop : name)); + /* + * Find the get_info, rel_info and node_match ops for the given + * node name + */ + mdesc_get_node_ops(name, &get_info_func, &rel_info_func, + &node_match_func); + + /* If we didn't find a match, the node type is not supported */ + if (!get_info_func || !rel_info_func || !node_match_func) { + pr_err("MD: %s node type is not supported\n", name); + return; + } + + mdesc_for_each_node_by_name(a, a_node, name) { + found = false; + + rv = get_info_func(a, a_node, &a_node_info); + if (rv != 0) { + pr_err("MD: Cannot find 1 or more required match properties for %s node.\n", + name); continue; } - mdesc_for_each_node_by_name(b, fnode, name) { - const u64 *fid; - - if (is_vdc_port) { - name_prop = mdesc_get_property(b, fnode, - "name", NULL); - if (!name_prop || - strcmp(name_prop, "vdc-port")) - continue; - fid = parent_cfg_handle(b, fnode); - if (!fid) { - printk(KERN_ERR "MD: Cannot find ID " - "for vdc-port node.\n"); - continue; - } - } else - fid = mdesc_get_property(b, fnode, - "id", NULL); - - if (*id == *fid) { - found = 1; + /* Check each node in B for node matching a_node */ + mdesc_for_each_node_by_name(b, b_node, name) { + rv = get_info_func(b, b_node, &b_node_info); + if (rv != 0) + continue; + + if (node_match_func(&a_node_info, &b_node_info)) { + found = true; + rel_info_func(&b_node_info); break; } + + rel_info_func(&b_node_info); } + + rel_info_func(&a_node_info); + if (!found) - func(a, node); + func(a, a_node, name); } } diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 075d38980dee..f37937b95dbf 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -219,6 +219,7 @@ int vio_set_intr(unsigned long dev_ino, int state) EXPORT_SYMBOL(vio_set_intr); static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, + const char *node_name, struct device *parent) { const char *type, *compat, *bus_id_name; @@ -236,7 +237,7 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, tlen = strlen(type) + 1; } } - if (tlen > VIO_MAX_TYPE_LEN) { + if (tlen > VIO_MAX_TYPE_LEN || strlen(type) >= VIO_MAX_TYPE_LEN) { printk(KERN_ERR "VIO: Type string [%s] is too long.\n", type); return NULL; @@ -335,6 +336,11 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, printk(KERN_INFO "VIO: Adding device %s\n", dev_name(&vdev->dev)); + /* node_name is NULL for the parent/channel-devices node */ + if (node_name != NULL) + (void) snprintf(vdev->node_name, VIO_MAX_NAME_LEN, "%s", + node_name); + err = device_register(&vdev->dev); if (err) { printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", @@ -349,9 +355,10 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, return vdev; } -static void vio_add(struct mdesc_handle *hp, u64 node) +static void vio_add(struct mdesc_handle *hp, u64 node, + const char *node_name) { - (void) vio_create_one(hp, node, &root_vdev->dev); + (void) vio_create_one(hp, node, node_name, &root_vdev->dev); } struct vio_md_node_query { @@ -375,7 +382,7 @@ static int vio_md_node_match(struct device *dev, void *arg) return 1; } -static void vio_remove(struct mdesc_handle *hp, u64 node) +static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name) { const char *type; const u64 *id, *cfg_handle; @@ -446,7 +453,8 @@ static struct mdesc_notifier_client vio_device_notifier = { * under "openboot" that we should not mess with as aparently that is * reserved exclusively for OBP use. */ -static void vio_add_ds(struct mdesc_handle *hp, u64 node) +static void vio_add_ds(struct mdesc_handle *hp, u64 node, + const char *node_name) { int found; u64 a; @@ -463,7 +471,7 @@ static void vio_add_ds(struct mdesc_handle *hp, u64 node) } if (found) - (void) vio_create_one(hp, node, &root_vdev->dev); + (void) vio_create_one(hp, node, node_name, &root_vdev->dev); } static struct mdesc_notifier_client vio_ds_notifier = { @@ -530,7 +538,7 @@ static int __init vio_init(void) cdev_cfg_handle = *cfg_handle; - root_vdev = vio_create_one(hp, root, NULL); + root_vdev = vio_create_one(hp, root, NULL, NULL); err = -ENODEV; if (!root_vdev) { printk(KERN_ERR "VIO: Could not create root device.\n"); -- cgit v1.2.1 From e2169a32b4f03b926905be029169a8b9f0750a67 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:35 -0400 Subject: sparc64: refactor code to obtain cfg_handle property from MDESC Refactors code to get the cfg_handle property of a node from Machine Description (MDESC) Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/kernel/vio.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index f37937b95dbf..1ac5da12ac2b 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -181,6 +181,24 @@ static struct device_node *cdev_node; static struct vio_dev *root_vdev; static u64 cdev_cfg_handle; +static const u64 *vio_cfg_handle(struct mdesc_handle *hp, u64 node) +{ + const u64 *cfg_handle = NULL; + u64 a; + + mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) { + u64 target; + + target = mdesc_arc_target(hp, a); + cfg_handle = mdesc_get_property(hp, target, + "cfg-handle", NULL); + if (cfg_handle) + break; + } + + return cfg_handle; +} + static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, struct vio_dev *vdev) { @@ -227,7 +245,6 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, struct vio_dev *vdev; int err, tlen, clen; const u64 *id, *cfg_handle; - u64 a; type = mdesc_get_property(hp, mp, "device-type", &tlen); if (!type) { @@ -245,16 +262,7 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, id = mdesc_get_property(hp, mp, "id", NULL); - cfg_handle = NULL; - mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) { - u64 target; - - target = mdesc_arc_target(hp, a); - cfg_handle = mdesc_get_property(hp, target, - "cfg-handle", NULL); - if (cfg_handle) - break; - } + cfg_handle = vio_cfg_handle(hp, mp); bus_id_name = type; if (!strcmp(type, "domain-services-port")) -- cgit v1.2.1 From 0542eb7de7d5244d159f827a0c9bd8c01792bd13 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:36 -0400 Subject: sparc64: remove restriction on VIO device name size Removes restriction on VIO device's size limit. Since KOBJ_NAME_LEN has been dropped from kobject, there doesn't seem to be a restriction on the device name anymore. This limit therefore doesn't make sense. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/kernel/vio.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 1ac5da12ac2b..0890a25b30a4 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -240,7 +240,7 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, const char *node_name, struct device *parent) { - const char *type, *compat, *bus_id_name; + const char *type, *compat; struct device_node *dp; struct vio_dev *vdev; int err, tlen, clen; @@ -264,21 +264,6 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, cfg_handle = vio_cfg_handle(hp, mp); - bus_id_name = type; - if (!strcmp(type, "domain-services-port")) - bus_id_name = "ds"; - - /* - * 20 char is the old driver-core name size limit, which is no more. - * This check can probably be removed after review and possible - * adaption of the vio users name length handling. - */ - if (strlen(bus_id_name) >= 20 - 4) { - printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n", - bus_id_name); - return NULL; - } - compat = mdesc_get_property(hp, mp, "device-type", &clen); if (!compat) { clen = 0; @@ -309,15 +294,15 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, vio_fill_channel_info(hp, mp, vdev); if (!id) { - dev_set_name(&vdev->dev, "%s", bus_id_name); + dev_set_name(&vdev->dev, "%s", type); vdev->dev_no = ~(u64)0; vdev->id = ~(u64)0; } else if (!cfg_handle) { - dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id); + dev_set_name(&vdev->dev, "%s-%llu", type, *id); vdev->dev_no = *id; vdev->id = ~(u64)0; } else { - dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name, + dev_set_name(&vdev->dev, "%s-%llu-%llu", type, *cfg_handle, *id); vdev->dev_no = *cfg_handle; vdev->id = *id; -- cgit v1.2.1 From 110f2264b37674e99057acd249a930040fad55b1 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:37 -0400 Subject: sparc64: check if a client is allowed to register for MDESC notifications Check if a client is supported, by comparing against a whitelist, to register for notifications from Machine Description (MDESC) Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/kernel/mdesc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 04b76267ddfa..f795ee015738 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -284,9 +284,26 @@ static struct mdesc_notifier_client *client_list; void mdesc_register_notifier(struct mdesc_notifier_client *client) { + bool supported = false; u64 node; + int i; mutex_lock(&mdesc_mutex); + + /* check to see if the node is supported for registration */ + for (i = 0; md_node_ops_table[i].name != NULL; i++) { + if (strcmp(md_node_ops_table[i].name, client->node_name) == 0) { + supported = true; + break; + } + } + + if (!supported) { + pr_err("MD: %s node not supported\n", client->node_name); + mutex_unlock(&mdesc_mutex); + return; + } + client->next = client_list; client_list = client; -- cgit v1.2.1 From aa512d5edeab267d612c6be93eb6a2368ee7a6d6 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:38 -0400 Subject: sparc64: enhance VIO device probing - Allocate IRQs for VIO devices during probing. - Allow clients to specify if IRQs would be allocated for a given VIO device. - Cache the device handle of the root node of channel-devices sub-tree in Machine Description (MDESC). Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/include/asm/vio.h | 5 +++++ arch/sparc/kernel/vio.c | 53 +++++++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 16 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 69cb3a5ff8cf..d8eb195b69e3 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -336,6 +336,10 @@ struct vio_dev { unsigned int tx_irq; unsigned int rx_irq; u64 rx_ino; + u64 tx_ino; + + /* Handle to the root of "channel-devices" sub-tree in MDESC */ + u64 cdev_handle; struct device dev; }; @@ -349,6 +353,7 @@ struct vio_driver { void (*shutdown)(struct vio_dev *dev); unsigned long driver_data; struct device_driver driver; + bool no_irq; }; struct vio_version { diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 0890a25b30a4..ea63f02cab3f 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -70,15 +70,26 @@ static int vio_device_probe(struct device *dev) struct vio_dev *vdev = to_vio_dev(dev); struct vio_driver *drv = to_vio_driver(dev->driver); const struct vio_device_id *id; - int error = -ENODEV; - if (drv->probe) { - id = vio_match_device(drv->id_table, vdev); - if (id) - error = drv->probe(vdev, id); + if (!drv->probe) + return -ENODEV; + + id = vio_match_device(drv->id_table, vdev); + if (!id) + return -ENODEV; + + /* alloc irqs (unless the driver specified not to) */ + if (!drv->no_irq) { + if (vdev->tx_irq == 0 && vdev->tx_ino != ~0UL) + vdev->tx_irq = sun4v_build_virq(vdev->cdev_handle, + vdev->tx_ino); + + if (vdev->rx_irq == 0 && vdev->rx_ino != ~0UL) + vdev->rx_irq = sun4v_build_virq(vdev->cdev_handle, + vdev->rx_ino); } - return error; + return drv->probe(vdev, id); } static int vio_device_remove(struct device *dev) @@ -86,8 +97,15 @@ static int vio_device_remove(struct device *dev) struct vio_dev *vdev = to_vio_dev(dev); struct vio_driver *drv = to_vio_driver(dev->driver); - if (drv->remove) + if (drv->remove) { + /* + * Ideally, we would remove/deallocate tx/rx virqs + * here - however, there are currently no support + * routines to do so at the moment. TBD + */ + return drv->remove(vdev); + } return 1; } @@ -204,6 +222,9 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, { u64 a; + vdev->tx_ino = ~0UL; + vdev->rx_ino = ~0UL; + vdev->channel_id = ~0UL; mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { const u64 *chan_id; const u64 *irq; @@ -213,18 +234,18 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, irq = mdesc_get_property(hp, target, "tx-ino", NULL); if (irq) - vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq); + vdev->tx_ino = *irq; irq = mdesc_get_property(hp, target, "rx-ino", NULL); - if (irq) { - vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq); + if (irq) vdev->rx_ino = *irq; - } chan_id = mdesc_get_property(hp, target, "id", NULL); if (chan_id) vdev->channel_id = *chan_id; } + + vdev->cdev_handle = cdev_cfg_handle; } int vio_set_intr(unsigned long dev_ino, int state) @@ -287,9 +308,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, memset(vdev->compat, 0, sizeof(vdev->compat)); vdev->compat_len = clen; - vdev->channel_id = ~0UL; - vdev->tx_irq = ~0; - vdev->rx_irq = ~0; + vdev->tx_irq = 0; + vdev->rx_irq = 0; vio_fill_channel_info(hp, mp, vdev); @@ -327,13 +347,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, } vdev->dp = dp; - printk(KERN_INFO "VIO: Adding device %s\n", dev_name(&vdev->dev)); - /* node_name is NULL for the parent/channel-devices node */ if (node_name != NULL) (void) snprintf(vdev->node_name, VIO_MAX_NAME_LEN, "%s", node_name); + pr_info("VIO: Adding device %s (tx_ino = %llx, rx_ino = %llx)\n", + dev_name(&vdev->dev), vdev->tx_ino, vdev->rx_ino); + err = device_register(&vdev->dev); if (err) { printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", -- cgit v1.2.1 From f4d29ca7defdec9c8010a20a9ce10a71462a9978 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:39 -0400 Subject: sparc64: Enhance search for VIO device in MDESC Enhances search for VIO device in MDESC by leveraging already existing MDESC APIs. Enhances changes in earlier patch, "sparc: Machine description indices can vary", by using existing MD search functions. It also specifies a match function, thereby enabling device_find_child() to use it for the purpose of matching device nodes in MDESC. An API to find VDEV node in MDESC based on its md_node_info is also added. It is planned to be used by VIO device clients in the future. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/include/asm/vio.h | 5 +- arch/sparc/kernel/mdesc.c | 2 + arch/sparc/kernel/vio.c | 120 +++++++++++++++++++++---------------------- 3 files changed, 64 insertions(+), 63 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index d8eb195b69e3..25ede61c0386 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -329,7 +329,6 @@ struct vio_dev { int compat_len; u64 dev_no; - u64 id; unsigned long channel_id; @@ -341,6 +340,9 @@ struct vio_dev { /* Handle to the root of "channel-devices" sub-tree in MDESC */ u64 cdev_handle; + /* MD specific data used to identify the vdev in MD */ + union md_node_info md_node_info; + struct device dev; }; @@ -497,5 +499,6 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev, void vio_port_up(struct vio_driver_state *vio); int vio_set_intr(unsigned long dev_ino, int state); +u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev); #endif /* _SPARC64_VIO_H */ diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index f795ee015738..e4b4e790bf89 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -574,6 +574,7 @@ u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name, return hp_node; } +EXPORT_SYMBOL(mdesc_get_node); int mdesc_get_node_info(struct mdesc_handle *hp, u64 node, const char *node_name, union md_node_info *node_info) @@ -603,6 +604,7 @@ int mdesc_get_node_info(struct mdesc_handle *hp, u64 node, return 0; } +EXPORT_SYMBOL(mdesc_get_node_info); static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) { diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index ea63f02cab3f..624f0a98edfe 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -217,6 +217,32 @@ static const u64 *vio_cfg_handle(struct mdesc_handle *hp, u64 node) return cfg_handle; } +/** + * vio_vdev_node() - Find VDEV node in MD + * @hp: Handle to the MD + * @vdev: Pointer to VDEV + * + * Find the node in the current MD which matches the given vio_dev. This + * must be done dynamically since the node value can change if the MD + * is updated. + * + * NOTE: the MD must be locked, using mdesc_grab(), when calling this routine + * + * Return: The VDEV node in MDESC + */ +u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev) +{ + u64 node; + + if (vdev == NULL) + return MDESC_NODE_NULL; + + node = mdesc_get_node(hp, (const char *)vdev->node_name, + &vdev->md_node_info); + + return node; +} + static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, struct vio_dev *vdev) { @@ -316,16 +342,13 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, if (!id) { dev_set_name(&vdev->dev, "%s", type); vdev->dev_no = ~(u64)0; - vdev->id = ~(u64)0; } else if (!cfg_handle) { dev_set_name(&vdev->dev, "%s-%llu", type, *id); vdev->dev_no = *id; - vdev->id = ~(u64)0; } else { dev_set_name(&vdev->dev, "%s-%llu-%llu", type, *cfg_handle, *id); vdev->dev_no = *cfg_handle; - vdev->id = *id; } vdev->dev.parent = parent; @@ -347,11 +370,24 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, } vdev->dp = dp; - /* node_name is NULL for the parent/channel-devices node */ - if (node_name != NULL) + /* + * node_name is NULL for the parent/channel-devices node and + * the parent doesn't require the MD node info. + */ + if (node_name != NULL) { (void) snprintf(vdev->node_name, VIO_MAX_NAME_LEN, "%s", node_name); + err = mdesc_get_node_info(hp, mp, node_name, + &vdev->md_node_info); + if (err) { + pr_err("VIO: Could not get MD node info %s, err=%d\n", + dev_name(&vdev->dev), err); + kfree(vdev); + return NULL; + } + } + pr_info("VIO: Adding device %s (tx_ino = %llx, rx_ino = %llx)\n", dev_name(&vdev->dev), vdev->tx_ino, vdev->rx_ino); @@ -375,68 +411,36 @@ static void vio_add(struct mdesc_handle *hp, u64 node, (void) vio_create_one(hp, node, node_name, &root_vdev->dev); } -struct vio_md_node_query { - const char *type; - u64 dev_no; - u64 id; +struct vio_remove_node_data { + struct mdesc_handle *hp; + u64 node; }; static int vio_md_node_match(struct device *dev, void *arg) { - struct vio_md_node_query *query = (struct vio_md_node_query *) arg; struct vio_dev *vdev = to_vio_dev(dev); + struct vio_remove_node_data *node_data; + u64 node; - if (vdev->dev_no != query->dev_no) - return 0; - if (vdev->id != query->id) - return 0; - if (strcmp(vdev->type, query->type)) - return 0; + node_data = (struct vio_remove_node_data *)arg; - return 1; + node = vio_vdev_node(node_data->hp, vdev); + + if (node == node_data->node) + return 1; + else + return 0; } static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name) { - const char *type; - const u64 *id, *cfg_handle; - u64 a; - struct vio_md_node_query query; + struct vio_remove_node_data node_data; struct device *dev; - type = mdesc_get_property(hp, node, "device-type", NULL); - if (!type) { - type = mdesc_get_property(hp, node, "name", NULL); - if (!type) - type = mdesc_node_name(hp, node); - } - - query.type = type; - - id = mdesc_get_property(hp, node, "id", NULL); - cfg_handle = NULL; - mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) { - u64 target; - - target = mdesc_arc_target(hp, a); - cfg_handle = mdesc_get_property(hp, target, - "cfg-handle", NULL); - if (cfg_handle) - break; - } - - if (!id) { - query.dev_no = ~(u64)0; - query.id = ~(u64)0; - } else if (!cfg_handle) { - query.dev_no = *id; - query.id = ~(u64)0; - } else { - query.dev_no = *cfg_handle; - query.id = *id; - } + node_data.hp = hp; + node_data.node = node; - dev = device_find_child(&root_vdev->dev, &query, + dev = device_find_child(&root_vdev->dev, (void *)&node_data, vio_md_node_match); if (dev) { printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev)); @@ -444,15 +448,7 @@ static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name) device_unregister(dev); put_device(dev); } else { - if (!id) - printk(KERN_ERR "VIO: Removed unknown %s node.\n", - type); - else if (!cfg_handle) - printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n", - type, *id); - else - printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n", - type, *cfg_handle, *id); + pr_err("VIO: %s node not found in MDESC\n", node_name); } } -- cgit v1.2.1 From 15c35e4ebbe16a205856e033627e50936ab7cd99 Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 23 Jun 2017 14:58:40 -0400 Subject: sparc64: add port_id to VIO device metadata Add port_id field to VIO device metadata to identify the port of VIO device. Signed-off-by: Jagannathan Raman Reviewed-by: Liam Merwick Reviewed-by: Shannon Nelson Signed-off-by: David S. Miller --- arch/sparc/include/asm/vio.h | 1 + arch/sparc/kernel/vio.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'arch/sparc') diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 25ede61c0386..d1c47e9f0090 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -330,6 +330,7 @@ struct vio_dev { u64 dev_no; + unsigned long port_id; unsigned long channel_id; unsigned int tx_irq; diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 624f0a98edfe..6715fc36e0e9 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -334,6 +334,7 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, memset(vdev->compat, 0, sizeof(vdev->compat)); vdev->compat_len = clen; + vdev->port_id = ~0UL; vdev->tx_irq = 0; vdev->rx_irq = 0; @@ -349,6 +350,7 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, dev_set_name(&vdev->dev, "%s-%llu-%llu", type, *cfg_handle, *id); vdev->dev_no = *cfg_handle; + vdev->port_id = *id; } vdev->dev.parent = parent; -- cgit v1.2.1 From a718d1392700bb7420ba26051ec35c20107ac981 Mon Sep 17 00:00:00 2001 From: Pavel Tatashin Date: Sun, 25 Jun 2017 19:27:06 -0400 Subject: sparc64: fix typo in property There is a typo in a comment that propagated into code: upa-portis instead of upa-portid This problem was detected by code inspection. Fixes: eea9833453bd ("sparc64: broken %tick frequency on spitfire cpus" Signed-off-by: Pavel Tatashin Reported-by: Steven Sistare Reviewed-by: Steven Sistare Signed-off-by: David S. Miller --- arch/sparc/kernel/prom_64.c | 2 +- arch/sparc/kernel/time_64.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c index 20cc5d80a471..baeaeed64993 100644 --- a/arch/sparc/kernel/prom_64.c +++ b/arch/sparc/kernel/prom_64.c @@ -381,7 +381,7 @@ bool arch_find_n_match_cpu_physical_id(struct device_node *cpun, int this_cpu_id; /* On hypervisor based platforms we interrogate the 'reg' - * property. On everything else we look for a 'upa-portis', + * property. On everything else we look for a 'upa-portid', * 'portid', or 'cpuid' property. */ diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index f584c53e769a..564f0e46ffd4 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -175,8 +175,8 @@ static unsigned long cpuid_to_freq(phandle node, int cpuid) if (prom_getproperty(node, "device_type", type, sizeof(type)) != -1) is_cpu_node = (strcmp(type, "cpu") == 0); - /* try upa-portis then cpuid to get cpuid, see prom_64.c */ - if (is_cpu_node && (prom_getint(node, "upa-portis") == cpuid || + /* try upa-portid then cpuid to get cpuid, see prom_64.c */ + if (is_cpu_node && (prom_getint(node, "upa-portid") == cpuid || prom_getint(node, "cpuid") == cpuid)) freq = prom_getintdefault(node, "clock-frequency", 0); if (!freq) -- cgit v1.2.1 From 0cd52df8a782be2e6592d331094a313d8947683a Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 27 Jun 2017 14:39:58 +0530 Subject: sparc: kernel: pmc: make of_device_ids const. of_device_ids are not supposed to change at runtime. All functions working with of_device_ids provided by work with const of_device_ids. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: David S. Miller --- arch/sparc/kernel/pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/sparc') diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c index f12b23f7b515..3b26cf62df6d 100644 --- a/arch/sparc/kernel/pmc.c +++ b/arch/sparc/kernel/pmc.c @@ -71,7 +71,7 @@ static int pmc_probe(struct platform_device *op) return 0; } -static struct of_device_id pmc_match[] = { +static const struct of_device_id pmc_match[] = { { .name = PMC_OBPNAME, }, -- cgit v1.2.1