linux/arch/tile/include/asm/processor.h
Davidlohr Bueso 3a6bfbc91d arch, locking: Ciao arch_mutex_cpu_relax()
The arch_mutex_cpu_relax() function, introduced by 34b133f, is
hacky and ugly. It was added a few years ago to address the fact
that common cpu_relax() calls include yielding on s390, and thus
impact the optimistic spinning functionality of mutexes. Nowadays
we use this function well beyond mutexes: rwsem, qrwlock, mcs and
lockref. Since the macro that defines the call is in the mutex header,
any users must include mutex.h and the naming is misleading as well.

This patch (i) renames the call to cpu_relax_lowlatency  ("relax, but
only if you can do it with very low latency") and (ii) defines it in
each arch's asm/processor.h local header, just like for regular cpu_relax
functions. On all archs, except s390, cpu_relax_lowlatency is simply cpu_relax,
and thus we can take it out of mutex.h. While this can seem redundant,
I believe it is a good choice as it allows us to move out arch specific
logic from generic locking primitives and enables future(?) archs to
transparently define it, similarly to System Z.

Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Anton Blanchard <anton@samba.org>
Cc: Aurelien Jacquiot <a-jacquiot@ti.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Bharat Bhushan <r65777@freescale.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chen Liqin <liqin.linux@gmail.com>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Chris Zankel <chris@zankel.net>
Cc: David Howells <dhowells@redhat.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Cc: Dominik Dingel <dingel@linux.vnet.ibm.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Guan Xuetao <gxt@mprc.pku.edu.cn>
Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Helge Deller <deller@gmx.de>
Cc: Hirokazu Takata <takata@linux-m32r.org>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: James E.J. Bottomley <jejb@parisc-linux.org>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: Jesper Nilsson <jesper.nilsson@axis.com>
Cc: Joe Perches <joe@perches.com>
Cc: Jonas Bonn <jonas@southpole.se>
Cc: Joseph Myers <joseph@codesourcery.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Koichi Yasutake <yasutake.koichi@jp.panasonic.com>
Cc: Lennox Wu <lennox.wu@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mark Salter <msalter@redhat.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Matt Turner <mattst88@gmail.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Neuling <mikey@neuling.org>
Cc: Michal Simek <monstr@monstr.eu>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: Qiaowei Ren <qiaowei.ren@intel.com>
Cc: Rafael Wysocki <rafael.j.wysocki@intel.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Richard Kuo <rkuo@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Steven Miao <realmz6@gmail.com>
Cc: Steven Rostedt <srostedt@redhat.com>
Cc: Stratos Karafotis <stratosk@semaphore.gr>
Cc: Tim Chen <tim.c.chen@linux.intel.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Vasily Kulikov <segoon@openwall.com>
Cc: Vineet Gupta <vgupta@synopsys.com>
Cc: Vineet Gupta <Vineet.Gupta1@synopsys.com>
Cc: Waiman Long <Waiman.Long@hp.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Wolfram Sang <wsa@the-dreams.de>
Cc: adi-buildroot-devel@lists.sourceforge.net
Cc: linux390@de.ibm.com
Cc: linux-alpha@vger.kernel.org
Cc: linux-am33-list@redhat.com
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-c6x-dev@linux-c6x.org
Cc: linux-cris-kernel@axis.com
Cc: linux-hexagon@vger.kernel.org
Cc: linux-ia64@vger.kernel.org
Cc: linux@lists.openrisc.net
Cc: linux-m32r-ja@ml.linux-m32r.org
Cc: linux-m32r@ml.linux-m32r.org
Cc: linux-m68k@lists.linux-m68k.org
Cc: linux-metag@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: linux-parisc@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-s390@vger.kernel.org
Cc: linux-sh@vger.kernel.org
Cc: linux-xtensa@linux-xtensa.org
Cc: sparclinux@vger.kernel.org
Link: http://lkml.kernel.org/r/1404079773.2619.4.camel@buesod1.americas.hpqcorp.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-07-17 12:32:47 +02:00

380 lines
11 KiB
C

/*
* Copyright 2010 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
*/
#ifndef _ASM_TILE_PROCESSOR_H
#define _ASM_TILE_PROCESSOR_H
#include <arch/chip.h>
#ifndef __ASSEMBLY__
/*
* NOTE: we don't include <linux/ptrace.h> or <linux/percpu.h> as one
* normally would, due to #include dependencies.
*/
#include <linux/types.h>
#include <asm/ptrace.h>
#include <asm/percpu.h>
#include <arch/spr_def.h>
struct task_struct;
struct thread_struct;
typedef struct {
unsigned long seg;
} mm_segment_t;
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
*/
void *current_text_addr(void);
#if CHIP_HAS_TILE_DMA()
/* Capture the state of a suspended DMA. */
struct tile_dma_state {
int enabled;
unsigned long src;
unsigned long dest;
unsigned long strides;
unsigned long chunk_size;
unsigned long src_chunk;
unsigned long dest_chunk;
unsigned long byte;
unsigned long status;
};
/*
* A mask of the DMA status register for selecting only the 'running'
* and 'done' bits.
*/
#define DMA_STATUS_MASK \
(SPR_DMA_STATUS__RUNNING_MASK | SPR_DMA_STATUS__DONE_MASK)
#endif
/*
* Track asynchronous TLB events (faults and access violations)
* that occur while we are in kernel mode from DMA or the SN processor.
*/
struct async_tlb {
short fault_num; /* original fault number; 0 if none */
char is_fault; /* was it a fault (vs an access violation) */
char is_write; /* for fault: was it caused by a write? */
unsigned long address; /* what address faulted? */
};
#ifdef CONFIG_HARDWALL
struct hardwall_info;
struct hardwall_task {
/* Which hardwall is this task tied to? (or NULL if none) */
struct hardwall_info *info;
/* Chains this task into the list at info->task_head. */
struct list_head list;
};
#ifdef __tilepro__
#define HARDWALL_TYPES 1 /* udn */
#else
#define HARDWALL_TYPES 3 /* udn, idn, and ipi */
#endif
#endif
struct thread_struct {
/* kernel stack pointer */
unsigned long ksp;
/* kernel PC */
unsigned long pc;
/* starting user stack pointer (for page migration) */
unsigned long usp0;
/* pid of process that created this one */
pid_t creator_pid;
#if CHIP_HAS_TILE_DMA()
/* DMA info for suspended threads (byte == 0 means no DMA state) */
struct tile_dma_state tile_dma_state;
#endif
/* User EX_CONTEXT registers */
unsigned long ex_context[2];
/* User SYSTEM_SAVE registers */
unsigned long system_save[4];
/* User interrupt mask */
unsigned long long interrupt_mask;
/* User interrupt-control 0 state */
unsigned long intctrl_0;
/* Is this task currently doing a backtrace? */
bool in_backtrace;
/* Any other miscellaneous processor state bits */
unsigned long proc_status;
#if !CHIP_HAS_FIXED_INTVEC_BASE()
/* Interrupt base for PL0 interrupts */
unsigned long interrupt_vector_base;
#endif
/* Tile cache retry fifo high-water mark */
unsigned long tile_rtf_hwm;
#if CHIP_HAS_DSTREAM_PF()
/* Data stream prefetch control */
unsigned long dstream_pf;
#endif
#ifdef CONFIG_HARDWALL
/* Hardwall information for various resources. */
struct hardwall_task hardwall[HARDWALL_TYPES];
#endif
#if CHIP_HAS_TILE_DMA()
/* Async DMA TLB fault information */
struct async_tlb dma_async_tlb;
#endif
};
#endif /* !__ASSEMBLY__ */
/*
* Start with "sp" this many bytes below the top of the kernel stack.
* This allows us to be cache-aware when handling the initial save
* of the pt_regs value to the stack.
*/
#define STACK_TOP_DELTA 64
/*
* When entering the kernel via a fault, start with the top of the
* pt_regs structure this many bytes below the top of the page.
* This aligns the pt_regs structure optimally for cache-line access.
*/
#ifdef __tilegx__
#define KSTK_PTREGS_GAP 48
#else
#define KSTK_PTREGS_GAP 56
#endif
#ifndef __ASSEMBLY__
#ifdef __tilegx__
#define TASK_SIZE_MAX (_AC(1, UL) << (MAX_VA_WIDTH - 1))
#else
#define TASK_SIZE_MAX PAGE_OFFSET
#endif
/* TASK_SIZE and related variables are always checked in "current" context. */
#ifdef CONFIG_COMPAT
#define COMPAT_TASK_SIZE (1UL << 31)
#define TASK_SIZE ((current_thread_info()->status & TS_COMPAT) ?\
COMPAT_TASK_SIZE : TASK_SIZE_MAX)
#else
#define TASK_SIZE TASK_SIZE_MAX
#endif
#define VDSO_BASE ((unsigned long)current->active_mm->context.vdso_base)
#define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x))
#define STACK_TOP TASK_SIZE
/* STACK_TOP_MAX is used temporarily in execve and should not check COMPAT. */
#define STACK_TOP_MAX TASK_SIZE_MAX
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's, if it is using bottom-up mapping.
*/
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
#define HAVE_ARCH_PICK_MMAP_LAYOUT
#define INIT_THREAD { \
.ksp = (unsigned long)init_stack + THREAD_SIZE - STACK_TOP_DELTA, \
.interrupt_mask = -1ULL \
}
/* Kernel stack top for the task that first boots on this cpu. */
DECLARE_PER_CPU(unsigned long, boot_sp);
/* PC to boot from on this cpu. */
DECLARE_PER_CPU(unsigned long, boot_pc);
/* Do necessary setup to start up a newly executed thread. */
static inline void start_thread(struct pt_regs *regs,
unsigned long pc, unsigned long usp)
{
regs->pc = pc;
regs->sp = usp;
single_step_execve();
}
/* Free all resources held by a thread. */
static inline void release_thread(struct task_struct *dead_task)
{
/* Nothing for now */
}
extern int do_work_pending(struct pt_regs *regs, u32 flags);
/*
* Return saved (kernel) PC of a blocked thread.
* Only used in a printk() in kernel/sched/core.c, so don't work too hard.
*/
#define thread_saved_pc(t) ((t)->thread.pc)
unsigned long get_wchan(struct task_struct *p);
/* Return initial ksp value for given task. */
#define task_ksp0(task) \
((unsigned long)(task)->stack + THREAD_SIZE - STACK_TOP_DELTA)
/* Return some info about the user process TASK. */
#define task_pt_regs(task) \
((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1)
#define current_pt_regs() \
((struct pt_regs *)((stack_pointer | (THREAD_SIZE - 1)) - \
STACK_TOP_DELTA - (KSTK_PTREGS_GAP - 1)) - 1)
#define task_sp(task) (task_pt_regs(task)->sp)
#define task_pc(task) (task_pt_regs(task)->pc)
/* Aliases for pc and sp (used in fs/proc/array.c) */
#define KSTK_EIP(task) task_pc(task)
#define KSTK_ESP(task) task_sp(task)
/* Fine-grained unaligned JIT support */
#define GET_UNALIGN_CTL(tsk, adr) get_unalign_ctl((tsk), (adr))
#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val))
extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr);
extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
/* Standard format for printing registers and other word-size data. */
#ifdef __tilegx__
# define REGFMT "0x%016lx"
#else
# define REGFMT "0x%08lx"
#endif
/*
* Do some slow action (e.g. read a slow SPR).
* Note that this must also have compiler-barrier semantics since
* it may be used in a busy loop reading memory.
*/
static inline void cpu_relax(void)
{
__insn_mfspr(SPR_PASS);
barrier();
}
#define cpu_relax_lowlatency() cpu_relax()
/* Info on this processor (see fs/proc/cpuinfo.c) */
struct seq_operations;
extern const struct seq_operations cpuinfo_op;
/* Provide information about the chip model. */
extern char chip_model[64];
/* Data on which physical memory controller corresponds to which NUMA node. */
extern int node_controller[];
/* Does the heap allocator return hash-for-home pages by default? */
extern int hash_default;
/* Should kernel stack pages be hash-for-home? */
extern int kstack_hash;
/* Does MAP_ANONYMOUS return hash-for-home pages by default? */
#define uheap_hash hash_default
/* Are we using huge pages in the TLB for kernel data? */
extern int kdata_huge;
/* Support standard Linux prefetching. */
#define ARCH_HAS_PREFETCH
#define prefetch(x) __builtin_prefetch(x)
#define PREFETCH_STRIDE CHIP_L2_LINE_SIZE()
/* Bring a value into the L1D, faulting the TLB if necessary. */
#ifdef __tilegx__
#define prefetch_L1(x) __insn_prefetch_l1_fault((void *)(x))
#else
#define prefetch_L1(x) __insn_prefetch_L1((void *)(x))
#endif
#else /* __ASSEMBLY__ */
/* Do some slow action (e.g. read a slow SPR). */
#define CPU_RELAX mfspr zero, SPR_PASS
#endif /* !__ASSEMBLY__ */
/* Assembly code assumes that the PL is in the low bits. */
#if SPR_EX_CONTEXT_1_1__PL_SHIFT != 0
# error Fix assembly assumptions about PL
#endif
/* We sometimes use these macros for EX_CONTEXT_0_1 as well. */
#if SPR_EX_CONTEXT_1_1__PL_SHIFT != SPR_EX_CONTEXT_0_1__PL_SHIFT || \
SPR_EX_CONTEXT_1_1__PL_RMASK != SPR_EX_CONTEXT_0_1__PL_RMASK || \
SPR_EX_CONTEXT_1_1__ICS_SHIFT != SPR_EX_CONTEXT_0_1__ICS_SHIFT || \
SPR_EX_CONTEXT_1_1__ICS_RMASK != SPR_EX_CONTEXT_0_1__ICS_RMASK
# error Fix assumptions that EX1 macros work for both PL0 and PL1
#endif
/* Allow pulling apart and recombining the PL and ICS bits in EX_CONTEXT. */
#define EX1_PL(ex1) \
(((ex1) >> SPR_EX_CONTEXT_1_1__PL_SHIFT) & SPR_EX_CONTEXT_1_1__PL_RMASK)
#define EX1_ICS(ex1) \
(((ex1) >> SPR_EX_CONTEXT_1_1__ICS_SHIFT) & SPR_EX_CONTEXT_1_1__ICS_RMASK)
#define PL_ICS_EX1(pl, ics) \
(((pl) << SPR_EX_CONTEXT_1_1__PL_SHIFT) | \
((ics) << SPR_EX_CONTEXT_1_1__ICS_SHIFT))
/*
* Provide symbolic constants for PLs.
*/
#define USER_PL 0
#if CONFIG_KERNEL_PL == 2
#define GUEST_PL 1
#endif
#define KERNEL_PL CONFIG_KERNEL_PL
/* SYSTEM_SAVE_K_0 holds the current cpu number ORed with ksp0. */
#ifdef __tilegx__
#define CPU_SHIFT 48
#if CHIP_VA_WIDTH() > CPU_SHIFT
# error Too many VA bits!
#endif
#define MAX_CPU_ID ((1 << (64 - CPU_SHIFT)) - 1)
#define raw_smp_processor_id() \
((int)(__insn_mfspr(SPR_SYSTEM_SAVE_K_0) >> CPU_SHIFT))
#define get_current_ksp0() \
((unsigned long)(((long)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) << \
(64 - CPU_SHIFT)) >> (64 - CPU_SHIFT)))
#define next_current_ksp0(task) ({ \
unsigned long __ksp0 = task_ksp0(task) & ((1UL << CPU_SHIFT) - 1); \
unsigned long __cpu = (long)raw_smp_processor_id() << CPU_SHIFT; \
__ksp0 | __cpu; \
})
#else
#define LOG2_NR_CPU_IDS 6
#define MAX_CPU_ID ((1 << LOG2_NR_CPU_IDS) - 1)
#define raw_smp_processor_id() \
((int)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & MAX_CPU_ID)
#define get_current_ksp0() \
(__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & ~MAX_CPU_ID)
#define next_current_ksp0(task) ({ \
unsigned long __ksp0 = task_ksp0(task); \
int __cpu = raw_smp_processor_id(); \
BUG_ON(__ksp0 & MAX_CPU_ID); \
__ksp0 | __cpu; \
})
#endif
#if CONFIG_NR_CPUS > (MAX_CPU_ID + 1)
# error Too many cpus!
#endif
#endif /* _ASM_TILE_PROCESSOR_H */