Skip to content

Commit

Permalink
Merge tag 'arc-v3.13-rc1-part1' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/vgupta/arc

Pull ARC changes from Vineet Gupta:
 - Towards a working SMP setup (ASID allocation, TLB Flush,...)
 - Support for TRACE_IRQFLAGS, LOCKDEP
 - cacheflush backend consolidation for I/D
 - Lots of allmodconfig fixlets from Chen
 - Other improvements/fixes

* tag 'arc-v3.13-rc1-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc: (25 commits)
  ARC: [plat-arcfpga] defconfig update
  smp, ARC: kill SMP single function call interrupt
  ARC: [SMP] Disallow RTSC
  ARC: [SMP] Fix build failures for large NR_CPUS
  ARC: [SMP] enlarge possible NR_CPUS
  ARC: [SMP] TLB flush
  ARC: [SMP] ASID allocation
  arc: export symbol for pm_power_off in reset.c
  arc: export symbol for save_stack_trace() in stacktrace.c
  arc: remove '__init' for get_hw_config_num_irq()
  arc: remove '__init' for first_lines_of_secondary()
  arc: remove '__init' for setup_processor() and arc_init_IRQ()
  arc: kgdb: add default implementation for kgdb_roundup_cpus()
  ARC: Fix bogus gcc warning and micro-optimise TLB iteration loop
  ARC: Add support for irqflags tracing and lockdep
  ARC: Reset the value of Interrupt Priority Register
  ARC: Reduce #ifdef'ery for unaligned access emulation
  ARC: Change calling convention of do_page_fault()
  ARC: cacheflush optim - PTAG can be loop invariant if V-P is const
  ARC: cacheflush refactor #3: Unify the {d,i}cache flush leaf helpers
  ...
  • Loading branch information
torvalds committed Nov 11, 2013
2 parents 0a759b2 + 737d5b9 commit edae583
Show file tree
Hide file tree
Showing 28 changed files with 326 additions and 181 deletions.
16 changes: 9 additions & 7 deletions arch/arc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ config ARC
select PERF_USE_VMALLOC
select HAVE_DEBUG_STACKOVERFLOW

config TRACE_IRQFLAGS_SUPPORT
def_bool y

config LOCKDEP_SUPPORT
def_bool y

config SCHED_OMIT_FRAME_POINTER
def_bool y

Expand Down Expand Up @@ -130,17 +136,14 @@ if SMP
config ARC_HAS_COH_CACHES
def_bool n

config ARC_HAS_COH_RTSC
def_bool n

config ARC_HAS_REENTRANT_IRQ_LV2
def_bool n

endif

config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
int "Maximum number of CPUs (2-4096)"
range 2 4096
depends on SMP
default "2"

Expand Down Expand Up @@ -326,8 +329,7 @@ config ARC_HAS_RTSC
bool "Insn: RTSC (64-bit r/o cycle counter)"
default y
depends on ARC_CPU_REL_4_10
# if SMP, enable RTSC only if counter is coherent across cores
depends on !SMP || ARC_HAS_COH_RTSC
depends on !SMP

endmenu # "ARC CPU Configuration"

Expand Down
3 changes: 3 additions & 0 deletions arch/arc/configs/fpga_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
Expand Down Expand Up @@ -62,4 +64,5 @@ CONFIG_TMPFS=y
CONFIG_NFS_FS=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_XZ_DEC=y
8 changes: 1 addition & 7 deletions arch/arc/include/asm/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@
#endif

#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)

/* For a rare case where customers have differently config I/D */
#define ARC_ICACHE_LINE_LEN L1_CACHE_BYTES
#define ARC_DCACHE_LINE_LEN L1_CACHE_BYTES

#define ICACHE_LINE_MASK (~(ARC_ICACHE_LINE_LEN - 1))
#define DCACHE_LINE_MASK (~(ARC_DCACHE_LINE_LEN - 1))
#define CACHE_LINE_MASK (~(L1_CACHE_BYTES - 1))

/*
* ARC700 doesn't cache any access in top 256M.
Expand Down
4 changes: 2 additions & 2 deletions arch/arc/include/asm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

#include <asm-generic/irq.h>

extern void __init arc_init_IRQ(void);
extern int __init get_hw_config_num_irq(void);
extern void arc_init_IRQ(void);
extern int get_hw_config_num_irq(void);

void arc_local_timer_setup(unsigned int cpu);

Expand Down
22 changes: 22 additions & 0 deletions arch/arc/include/asm/irqflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,38 @@ static inline void arch_unmask_irq(unsigned int irq)

#else

#ifdef CONFIG_TRACE_IRQFLAGS

.macro TRACE_ASM_IRQ_DISABLE
bl trace_hardirqs_off
.endm

.macro TRACE_ASM_IRQ_ENABLE
bl trace_hardirqs_on
.endm

#else

.macro TRACE_ASM_IRQ_DISABLE
.endm

.macro TRACE_ASM_IRQ_ENABLE
.endm

#endif

.macro IRQ_DISABLE scratch
lr \scratch, [status32]
bic \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
flag \scratch
TRACE_ASM_IRQ_DISABLE
.endm

.macro IRQ_ENABLE scratch
lr \scratch, [status32]
or \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
flag \scratch
TRACE_ASM_IRQ_ENABLE
.endm

#endif /* __ASSEMBLY__ */
Expand Down
2 changes: 1 addition & 1 deletion arch/arc/include/asm/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#ifndef __ASSEMBLY__

typedef struct {
unsigned long asid; /* 8 bit MMU PID + Generation cycle */
unsigned long asid[NR_CPUS]; /* 8 bit MMU PID + Generation cycle */
} mm_context_t;

#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
Expand Down
61 changes: 44 additions & 17 deletions arch/arc/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
* "Fast Context Switch" i.e. no TLB flush on ctxt-switch
*
* Linux assigns each task a unique ASID. A simple round-robin allocation
* of H/w ASID is done using software tracker @asid_cache.
* of H/w ASID is done using software tracker @asid_cpu.
* When it reaches max 255, the allocation cycle starts afresh by flushing
* the entire TLB and wrapping ASID back to zero.
*
* A new allocation cycle, post rollover, could potentially reassign an ASID
* to a different task. Thus the rule is to refresh the ASID in a new cycle.
* The 32 bit @asid_cache (and mm->asid) have 8 bits MMU PID and rest 24 bits
* The 32 bit @asid_cpu (and mm->asid) have 8 bits MMU PID and rest 24 bits
* serve as cycle/generation indicator and natural 32 bit unsigned math
* automagically increments the generation when lower 8 bits rollover.
*/
Expand All @@ -47,16 +47,19 @@
#define MM_CTXT_FIRST_CYCLE (MM_CTXT_ASID_MASK + 1)
#define MM_CTXT_NO_ASID 0UL

#define hw_pid(mm) (mm->context.asid & MM_CTXT_ASID_MASK)
#define asid_mm(mm, cpu) mm->context.asid[cpu]
#define hw_pid(mm, cpu) (asid_mm(mm, cpu) & MM_CTXT_ASID_MASK)

extern unsigned int asid_cache;
DECLARE_PER_CPU(unsigned int, asid_cache);
#define asid_cpu(cpu) per_cpu(asid_cache, cpu)

/*
* Get a new ASID if task doesn't have a valid one (unalloc or from prev cycle)
* Also set the MMU PID register to existing/updated ASID
*/
static inline void get_new_mmu_context(struct mm_struct *mm)
{
const unsigned int cpu = smp_processor_id();
unsigned long flags;

local_irq_save(flags);
Expand All @@ -71,28 +74,28 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
* first need to destroy the context, setting it to invalid
* value.
*/
if (!((mm->context.asid ^ asid_cache) & MM_CTXT_CYCLE_MASK))
if (!((asid_mm(mm, cpu) ^ asid_cpu(cpu)) & MM_CTXT_CYCLE_MASK))
goto set_hw;

/* move to new ASID and handle rollover */
if (unlikely(!(++asid_cache & MM_CTXT_ASID_MASK))) {
if (unlikely(!(++asid_cpu(cpu) & MM_CTXT_ASID_MASK))) {

flush_tlb_all();
local_flush_tlb_all();

/*
* Above checke for rollover of 8 bit ASID in 32 bit container.
* If the container itself wrapped around, set it to a non zero
* "generation" to distinguish from no context
*/
if (!asid_cache)
asid_cache = MM_CTXT_FIRST_CYCLE;
if (!asid_cpu(cpu))
asid_cpu(cpu) = MM_CTXT_FIRST_CYCLE;
}

/* Assign new ASID to tsk */
mm->context.asid = asid_cache;
asid_mm(mm, cpu) = asid_cpu(cpu);

set_hw:
write_aux_reg(ARC_REG_PID, hw_pid(mm) | MMU_ENABLE);
write_aux_reg(ARC_REG_PID, hw_pid(mm, cpu) | MMU_ENABLE);

local_irq_restore(flags);
}
Expand All @@ -104,16 +107,45 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
static inline int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
mm->context.asid = MM_CTXT_NO_ASID;
int i;

for_each_possible_cpu(i)
asid_mm(mm, i) = MM_CTXT_NO_ASID;

return 0;
}

static inline void destroy_context(struct mm_struct *mm)
{
unsigned long flags;

/* Needed to elide CONFIG_DEBUG_PREEMPT warning */
local_irq_save(flags);
asid_mm(mm, smp_processor_id()) = MM_CTXT_NO_ASID;
local_irq_restore(flags);
}

/* Prepare the MMU for task: setup PID reg with allocated ASID
If task doesn't have an ASID (never alloc or stolen, get a new ASID)
*/
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
const int cpu = smp_processor_id();

/*
* Note that the mm_cpumask is "aggregating" only, we don't clear it
* for the switched-out task, unlike some other arches.
* It is used to enlist cpus for sending TLB flush IPIs and not sending
* it to CPUs where a task once ran-on, could cause stale TLB entry
* re-use, specially for a multi-threaded task.
* e.g. T1 runs on C1, migrates to C3. T2 running on C2 munmaps.
* For a non-aggregating mm_cpumask, IPI not sent C1, and if T1
* were to re-migrate to C1, it could access the unmapped region
* via any existing stale TLB entries.
*/
cpumask_set_cpu(cpu, mm_cpumask(next));

#ifndef CONFIG_SMP
/* PGD cached in MMU reg to avoid 3 mem lookups: task->mm->pgd */
write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
Expand All @@ -131,11 +163,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
*/
#define activate_mm(prev, next) switch_mm(prev, next, NULL)

static inline void destroy_context(struct mm_struct *mm)
{
mm->context.asid = MM_CTXT_NO_ASID;
}

/* it seemed that deactivate_mm( ) is a reasonable place to do book-keeping
* for retiring-mm. However destroy_context( ) still needs to do that because
* between mm_release( ) = >deactive_mm( ) and
Expand Down
2 changes: 1 addition & 1 deletion arch/arc/include/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct cpuinfo_data {
extern int root_mountflags, end_mem;
extern int running_on_hw;

void __init setup_processor(void);
void setup_processor(void);
void __init setup_arch_memory(void);

#endif /* __ASMARC_SETUP_H */
2 changes: 1 addition & 1 deletion arch/arc/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
* APIs provided by arch SMP code to rest of arch code
*/
extern void __init smp_init_cpus(void);
extern void __init first_lines_of_secondary(void);
extern void first_lines_of_secondary(void);
extern const char *arc_platform_smp_cpuinfo(void);

/*
Expand Down
11 changes: 9 additions & 2 deletions arch/arc/include/asm/tlbflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
void local_flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end);

/* XXX: Revisit for SMP */
#ifndef CONFIG_SMP
#define flush_tlb_range(vma, s, e) local_flush_tlb_range(vma, s, e)
#define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page)
#define flush_tlb_kernel_range(s, e) local_flush_tlb_kernel_range(s, e)
#define flush_tlb_all() local_flush_tlb_all()
#define flush_tlb_mm(mm) local_flush_tlb_mm(mm)

#else
extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
extern void flush_tlb_all(void);
extern void flush_tlb_mm(struct mm_struct *mm);
#endif /* CONFIG_SMP */
#endif
3 changes: 2 additions & 1 deletion arch/arc/include/asm/unaligned.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ static inline int
misaligned_fixup(unsigned long address, struct pt_regs *regs,
struct callee_regs *cregs)
{
return 0;
/* Not fixed */
return 1;
}
#endif

Expand Down
13 changes: 12 additions & 1 deletion arch/arc/kernel/ctx_sw.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <asm/asm-offsets.h>
#include <linux/sched.h>

#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)

struct task_struct *__sched
__switch_to(struct task_struct *prev_task, struct task_struct *next_task)
{
Expand Down Expand Up @@ -45,7 +47,16 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
#endif

/* set ksp of outgoing task in tsk->thread.ksp */
#if KSP_WORD_OFF <= 255
"st.as sp, [%3, %1] \n\t"
#else
/*
* Workaround for NR_CPUS=4k
* %1 is bigger than 255 (S9 offset for st.as)
*/
"add2 r24, %3, %1 \n\t"
"st sp, [r24] \n\t"
#endif

"sync \n\t"

Expand Down Expand Up @@ -97,7 +108,7 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
/* FP/BLINK restore generated by gcc (standard func epilogue */

: "=r"(tmp)
: "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev)
: "n"(KSP_WORD_OFF), "r"(next), "r"(prev)
: "blink"
);

Expand Down
11 changes: 9 additions & 2 deletions arch/arc/kernel/ctx_sw_asm.S
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <asm/asm-offsets.h>
#include <asm/linkage.h>

#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)

;################### Low Level Context Switch ##########################

.section .sched.text,"ax",@progbits
Expand All @@ -28,8 +30,13 @@ __switch_to:
SAVE_CALLEE_SAVED_KERNEL

/* Save the now KSP in task->thread.ksp */
st.as sp, [r0, (TASK_THREAD + THREAD_KSP)/4]

#if KSP_WORD_OFF <= 255
st.as sp, [r0, KSP_WORD_OFF]
#else
/* Workaround for NR_CPUS=4k as ST.as can only take s9 offset */
add2 r24, r0, KSP_WORD_OFF
st sp, [r24]
#endif
/*
* Return last task in r0 (return reg)
* On ARC, Return reg = First Arg reg = r0.
Expand Down
Loading

0 comments on commit edae583

Please sign in to comment.