Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Browse files Browse the repository at this point in the history
Pull sparc updates from David Miller:
 "Mostly more sparc64 THP bug fixes, and a refactoring of SMP bootup on
  sparc32 from Sam Ravnborg."

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
  sparc32: refactor smp boot
  sparc64: Fix huge PMD to PTE translation for sun4u in TLB miss handler.
  sparc64: Fix tsb_grow() in atomic context.
  sparc64: Handle hugepage TSB being NULL.
  sparc64: Fix gfp_flags setting in tsb_grow().
  • Loading branch information
Linus Torvalds committed Feb 20, 2013
2 parents 79a69d3 + f9fd348 commit 8ec4942
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 120 deletions.
1 change: 0 additions & 1 deletion arch/sparc/include/asm/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,

static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
{
hugetlb_setup(mm);
}

static inline int is_hugepage_only_range(struct mm_struct *mm,
Expand Down
4 changes: 2 additions & 2 deletions arch/sparc/include/asm/page_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
#ifndef __ASSEMBLY__

#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
struct mm_struct;
extern void hugetlb_setup(struct mm_struct *mm);
struct pt_regs;
extern void hugetlb_setup(struct pt_regs *regs);
#endif

#define WANT_PAGE_VIRTUAL
Expand Down
28 changes: 19 additions & 9 deletions arch/sparc/include/asm/tsb.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,26 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
andn REG2, 0x7, REG2; \
add REG1, REG2, REG1;

/* This macro exists only to make the PMD translator below easier
* to read. It hides the ELF section switch for the sun4v code
* patching.
/* These macros exists only to make the PMD translator below
* easier to read. It hides the ELF section switch for the
* sun4v code patching.
*/
#define OR_PTE_BIT(REG, NAME) \
#define OR_PTE_BIT_1INSN(REG, NAME) \
661: or REG, _PAGE_##NAME##_4U, REG; \
.section .sun4v_1insn_patch, "ax"; \
.word 661b; \
or REG, _PAGE_##NAME##_4V, REG; \
.previous;

#define OR_PTE_BIT_2INSN(REG, TMP, NAME) \
661: sethi %hi(_PAGE_##NAME##_4U), TMP; \
or REG, TMP, REG; \
.section .sun4v_2insn_patch, "ax"; \
.word 661b; \
mov -1, TMP; \
or REG, _PAGE_##NAME##_4V, REG; \
.previous;

/* Load into REG the PTE value for VALID, CACHE, and SZHUGE. */
#define BUILD_PTE_VALID_SZHUGE_CACHE(REG) \
661: sethi %uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG; \
Expand Down Expand Up @@ -214,12 +223,13 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
andn REG1, PMD_HUGE_PROTBITS, REG2; \
sllx REG2, PMD_PADDR_SHIFT, REG2; \
/* REG2 now holds PFN << PAGE_SHIFT */ \
andcc REG1, PMD_HUGE_EXEC, %g0; \
bne,a,pt %xcc, 1f; \
OR_PTE_BIT(REG2, EXEC); \
1: andcc REG1, PMD_HUGE_WRITE, %g0; \
andcc REG1, PMD_HUGE_WRITE, %g0; \
bne,a,pt %xcc, 1f; \
OR_PTE_BIT(REG2, W); \
OR_PTE_BIT_1INSN(REG2, W); \
1: andcc REG1, PMD_HUGE_EXEC, %g0; \
be,pt %xcc, 1f; \
nop; \
OR_PTE_BIT_2INSN(REG2, REG1, EXEC); \
/* REG1 can now be clobbered, build final PTE */ \
1: BUILD_PTE_VALID_SZHUGE_CACHE(REG1); \
ba,pt %xcc, PTE_LABEL; \
Expand Down
12 changes: 12 additions & 0 deletions arch/sparc/kernel/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ extern void sun4m_init_IRQ(void);
extern void sun4m_unmask_profile_irq(void);
extern void sun4m_clear_profile_irq(int cpu);

/* sun4m_smp.c */
void sun4m_cpu_pre_starting(void *arg);
void sun4m_cpu_pre_online(void *arg);

/* sun4d_irq.c */
extern spinlock_t sun4d_imsk_lock;

Expand All @@ -60,6 +64,14 @@ extern int show_sun4d_interrupts(struct seq_file *, void *);
extern void sun4d_distribute_irqs(void);
extern void sun4d_free_irq(unsigned int irq, void *dev_id);

/* sun4d_smp.c */
void sun4d_cpu_pre_starting(void *arg);
void sun4d_cpu_pre_online(void *arg);

/* leon_smp.c */
void leon_cpu_pre_starting(void *arg);
void leon_cpu_pre_online(void *arg);

/* head_32.S */
extern unsigned int t_nmi[];
extern unsigned int linux_trap_ipi15_sun4d[];
Expand Down
33 changes: 9 additions & 24 deletions arch/sparc/kernel/leon_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,19 @@ static inline unsigned long do_swap(volatile unsigned long *ptr,
return val;
}

void __cpuinit leon_callin(void)
void __cpuinit leon_cpu_pre_starting(void *arg)
{
int cpuid = hard_smp_processor_id();

local_ops->cache_all();
local_ops->tlb_all();
leon_configure_cache_smp();
}

notify_cpu_starting(cpuid);

/* Get our local ticker going. */
register_percpu_ce(cpuid);

calibrate_delay();
smp_store_cpu_info(cpuid);

local_ops->cache_all();
local_ops->tlb_all();
void __cpuinit leon_cpu_pre_online(void *arg)
{
int cpuid = hard_smp_processor_id();

/*
* Unblock the master CPU _only_ when the scheduler state
* of all secondary CPUs will be up-to-date, so after
* the SMP initialization the master will be just allowed
* to call the scheduler code.
* Allow master to continue.
/* Allow master to continue. The master will then give us the
* go-ahead by setting the smp_commenced_mask and will wait without
* timeouts until our setup is completed fully (signified by
* our bit being set in the cpu_online_mask).
*/
do_swap(&cpu_callin_map[cpuid], 1);

Expand All @@ -110,9 +98,6 @@ void __cpuinit leon_callin(void)

while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
mb();

local_irq_enable();
set_cpu_online(cpuid, true);
}

/*
Expand Down
86 changes: 86 additions & 0 deletions arch/sparc/kernel/smp_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/seq_file.h>
#include <linux/cache.h>
#include <linux/delay.h>
#include <linux/cpu.h>

#include <asm/ptrace.h>
#include <linux/atomic.h>
Expand All @@ -32,8 +33,10 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/cpudata.h>
#include <asm/timer.h>
#include <asm/leon.h>

#include "kernel.h"
#include "irq.h"

volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,};
Expand Down Expand Up @@ -294,6 +297,89 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
return ret;
}

void __cpuinit arch_cpu_pre_starting(void *arg)
{
local_ops->cache_all();
local_ops->tlb_all();

switch(sparc_cpu_model) {
case sun4m:
sun4m_cpu_pre_starting(arg);
break;
case sun4d:
sun4d_cpu_pre_starting(arg);
break;
case sparc_leon:
leon_cpu_pre_starting(arg);
break;
default:
BUG();
}
}

void __cpuinit arch_cpu_pre_online(void *arg)
{
unsigned int cpuid = hard_smp_processor_id();

register_percpu_ce(cpuid);

calibrate_delay();
smp_store_cpu_info(cpuid);

local_ops->cache_all();
local_ops->tlb_all();

switch(sparc_cpu_model) {
case sun4m:
sun4m_cpu_pre_online(arg);
break;
case sun4d:
sun4d_cpu_pre_online(arg);
break;
case sparc_leon:
leon_cpu_pre_online(arg);
break;
default:
BUG();
}
}

void __cpuinit sparc_start_secondary(void *arg)
{
unsigned int cpu;

/*
* SMP booting is extremely fragile in some architectures. So run
* the cpu initialization code first before anything else.
*/
arch_cpu_pre_starting(arg);

preempt_disable();
cpu = smp_processor_id();

/* Invoke the CPU_STARTING notifier callbacks */
notify_cpu_starting(cpu);

arch_cpu_pre_online(arg);

/* Set the CPU in the cpu_online_mask */
set_cpu_online(cpu, true);

/* Enable local interrupts now */
local_irq_enable();

wmb();
cpu_idle();

/* We should never reach here! */
BUG();
}

void __cpuinit smp_callin(void)
{
sparc_start_secondary(NULL);
}

void smp_bogo(struct seq_file *m)
{
int i;
Expand Down
29 changes: 9 additions & 20 deletions arch/sparc/kernel/sun4d_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,37 +50,30 @@ static inline void show_leds(int cpuid)
"i" (ASI_M_CTL));
}

void __cpuinit smp4d_callin(void)
void __cpuinit sun4d_cpu_pre_starting(void *arg)
{
int cpuid = hard_smp_processor_id();
unsigned long flags;

/* Show we are alive */
cpu_leds[cpuid] = 0x6;
show_leds(cpuid);

/* Enable level15 interrupt, disable level14 interrupt for now */
cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
}

local_ops->cache_all();
local_ops->tlb_all();
void __cpuinit sun4d_cpu_pre_online(void *arg)
{
unsigned long flags;
int cpuid;

notify_cpu_starting(cpuid);
/*
* Unblock the master CPU _only_ when the scheduler state
cpuid = hard_smp_processor_id();

/* Unblock the master CPU _only_ when the scheduler state
* of all secondary CPUs will be up-to-date, so after
* the SMP initialization the master will be just allowed
* to call the scheduler code.
*/
/* Get our local ticker going. */
register_percpu_ce(cpuid);

calibrate_delay();
smp_store_cpu_info(cpuid);
local_ops->cache_all();
local_ops->tlb_all();

/* Allow master to continue. */
sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1);
local_ops->cache_all();
local_ops->tlb_all();
Expand All @@ -106,16 +99,12 @@ void __cpuinit smp4d_callin(void)
local_ops->cache_all();
local_ops->tlb_all();

local_irq_enable(); /* We don't allow PIL 14 yet */

while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
barrier();

spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
set_cpu_online(cpuid, true);

}

/*
Expand Down
33 changes: 9 additions & 24 deletions arch/sparc/kernel/sun4m_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,19 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val)
return val;
}

void __cpuinit smp4m_callin(void)
void __cpuinit sun4m_cpu_pre_starting(void *arg)
{
int cpuid = hard_smp_processor_id();

local_ops->cache_all();
local_ops->tlb_all();

notify_cpu_starting(cpuid);

register_percpu_ce(cpuid);

calibrate_delay();
smp_store_cpu_info(cpuid);
}

local_ops->cache_all();
local_ops->tlb_all();
void __cpuinit sun4m_cpu_pre_online(void *arg)
{
int cpuid = hard_smp_processor_id();

/*
* Unblock the master CPU _only_ when the scheduler state
* of all secondary CPUs will be up-to-date, so after
* the SMP initialization the master will be just allowed
* to call the scheduler code.
/* Allow master to continue. The master will then give us the
* go-ahead by setting the smp_commenced_mask and will wait without
* timeouts until our setup is completed fully (signified by
* our bit being set in the cpu_online_mask).
*/
/* Allow master to continue. */
swap_ulong(&cpu_callin_map[cpuid], 1);

/* XXX: What's up with all the flushes? */
Expand All @@ -75,10 +64,6 @@ void __cpuinit smp4m_callin(void)

while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
mb();

local_irq_enable();

set_cpu_online(cpuid, true);
}

/*
Expand Down
Loading

0 comments on commit 8ec4942

Please sign in to comment.