Commit 8f65873e authored by Graf Yang's avatar Graf Yang Committed by Bryan Wu

Blackfin arch: SMP supporting patchset: Blackfin kernel and memory management code

Blackfin dual core BF561 processor can support SMP like features.
https://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:smp-like

In this patch, we provide SMP extend to Blackfin kernel and memory management code
Singed-off-by: default avatarGraf Yang <graf.yang@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier.adi@gmail.com>
Signed-off-by: default avatarBryan Wu <cooloney@kernel.org>
parent b8a98989
...@@ -56,6 +56,9 @@ int main(void) ...@@ -56,6 +56,9 @@ int main(void)
/* offsets into the thread struct */ /* offsets into the thread struct */
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
DEFINE(THREAD_SR, offsetof(struct thread_struct, seqstat));
DEFINE(PT_SR, offsetof(struct thread_struct, seqstat));
DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
DEFINE(THREAD_PC, offsetof(struct thread_struct, pc)); DEFINE(THREAD_PC, offsetof(struct thread_struct, pc));
DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE); DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
...@@ -128,5 +131,31 @@ int main(void) ...@@ -128,5 +131,31 @@ int main(void)
DEFINE(SIGSEGV, SIGSEGV); DEFINE(SIGSEGV, SIGSEGV);
DEFINE(SIGTRAP, SIGTRAP); DEFINE(SIGTRAP, SIGTRAP);
/* PDA management (in L1 scratchpad) */
DEFINE(PDA_SYSCFG, offsetof(struct blackfin_pda, syscfg));
#ifdef CONFIG_SMP
DEFINE(PDA_IRQFLAGS, offsetof(struct blackfin_pda, imask));
#endif
DEFINE(PDA_IPDT, offsetof(struct blackfin_pda, ipdt));
DEFINE(PDA_IPDT_SWAPCOUNT, offsetof(struct blackfin_pda, ipdt_swapcount));
DEFINE(PDA_DPDT, offsetof(struct blackfin_pda, dpdt));
DEFINE(PDA_DPDT_SWAPCOUNT, offsetof(struct blackfin_pda, dpdt_swapcount));
DEFINE(PDA_EXIPTR, offsetof(struct blackfin_pda, ex_iptr));
DEFINE(PDA_EXOPTR, offsetof(struct blackfin_pda, ex_optr));
DEFINE(PDA_EXBUF, offsetof(struct blackfin_pda, ex_buf));
DEFINE(PDA_EXIMASK, offsetof(struct blackfin_pda, ex_imask));
DEFINE(PDA_EXSTACK, offsetof(struct blackfin_pda, ex_stack));
#ifdef ANOMALY_05000261
DEFINE(PDA_LFRETX, offsetof(struct blackfin_pda, last_cplb_fault_retx));
#endif
DEFINE(PDA_DCPLB, offsetof(struct blackfin_pda, dcplb_fault_addr));
DEFINE(PDA_ICPLB, offsetof(struct blackfin_pda, icplb_fault_addr));
DEFINE(PDA_RETX, offsetof(struct blackfin_pda, retx));
DEFINE(PDA_SEQSTAT, offsetof(struct blackfin_pda, seqstat));
#ifdef CONFIG_SMP
/* Inter-core lock (in L2 SRAM) */
DEFINE(SIZEOF_CORELOCK, sizeof(struct corelock_slot));
#endif
return 0; return 0;
} }
...@@ -68,3 +68,37 @@ EXPORT_SYMBOL(insw_8); ...@@ -68,3 +68,37 @@ EXPORT_SYMBOL(insw_8);
EXPORT_SYMBOL(outsl); EXPORT_SYMBOL(outsl);
EXPORT_SYMBOL(insl); EXPORT_SYMBOL(insl);
EXPORT_SYMBOL(insl_16); EXPORT_SYMBOL(insl_16);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(__raw_atomic_update_asm);
EXPORT_SYMBOL(__raw_atomic_clear_asm);
EXPORT_SYMBOL(__raw_atomic_set_asm);
EXPORT_SYMBOL(__raw_atomic_xor_asm);
EXPORT_SYMBOL(__raw_atomic_test_asm);
EXPORT_SYMBOL(__raw_xchg_1_asm);
EXPORT_SYMBOL(__raw_xchg_2_asm);
EXPORT_SYMBOL(__raw_xchg_4_asm);
EXPORT_SYMBOL(__raw_cmpxchg_1_asm);
EXPORT_SYMBOL(__raw_cmpxchg_2_asm);
EXPORT_SYMBOL(__raw_cmpxchg_4_asm);
EXPORT_SYMBOL(__raw_spin_is_locked_asm);
EXPORT_SYMBOL(__raw_spin_lock_asm);
EXPORT_SYMBOL(__raw_spin_trylock_asm);
EXPORT_SYMBOL(__raw_spin_unlock_asm);
EXPORT_SYMBOL(__raw_read_lock_asm);
EXPORT_SYMBOL(__raw_read_trylock_asm);
EXPORT_SYMBOL(__raw_read_unlock_asm);
EXPORT_SYMBOL(__raw_write_lock_asm);
EXPORT_SYMBOL(__raw_write_trylock_asm);
EXPORT_SYMBOL(__raw_write_unlock_asm);
EXPORT_SYMBOL(__raw_bit_set_asm);
EXPORT_SYMBOL(__raw_bit_clear_asm);
EXPORT_SYMBOL(__raw_bit_toggle_asm);
EXPORT_SYMBOL(__raw_bit_test_asm);
EXPORT_SYMBOL(__raw_bit_test_set_asm);
EXPORT_SYMBOL(__raw_bit_test_clear_asm);
EXPORT_SYMBOL(__raw_bit_test_toggle_asm);
EXPORT_SYMBOL(__raw_uncached_fetch_asm);
EXPORT_SYMBOL(__raw_smp_mark_barrier_asm);
EXPORT_SYMBOL(__raw_smp_check_barrier_asm);
#endif
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/blackfin.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/context.S> #include <asm/context.S>
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/trace.h> #include <asm/trace.h>
static unsigned long irq_err_count; static atomic_t irq_err_count;
static spinlock_t irq_controller_lock; static spinlock_t irq_controller_lock;
/* /*
...@@ -48,7 +48,7 @@ void dummy_mask_unmask_irq(unsigned int irq) ...@@ -48,7 +48,7 @@ void dummy_mask_unmask_irq(unsigned int irq)
void ack_bad_irq(unsigned int irq) void ack_bad_irq(unsigned int irq)
{ {
irq_err_count += 1; atomic_inc(&irq_err_count);
printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
} }
EXPORT_SYMBOL(ack_bad_irq); EXPORT_SYMBOL(ack_bad_irq);
...@@ -72,7 +72,7 @@ static struct irq_desc bad_irq_desc = { ...@@ -72,7 +72,7 @@ static struct irq_desc bad_irq_desc = {
int show_interrupts(struct seq_file *p, void *v) int show_interrupts(struct seq_file *p, void *v)
{ {
int i = *(loff_t *) v; int i = *(loff_t *) v, j;
struct irqaction *action; struct irqaction *action;
unsigned long flags; unsigned long flags;
...@@ -80,19 +80,20 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -80,19 +80,20 @@ int show_interrupts(struct seq_file *p, void *v)
spin_lock_irqsave(&irq_desc[i].lock, flags); spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action; action = irq_desc[i].action;
if (!action) if (!action)
goto unlock; goto skip;
seq_printf(p, "%3d: ", i);
seq_printf(p, "%3d: %10u ", i, kstat_irqs(i)); for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
seq_printf(p, " %8s", irq_desc[i].chip->name);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next) for (action = action->next; action; action = action->next)
seq_printf(p, ", %s", action->name); seq_printf(p, " %s", action->name);
seq_putc(p, '\n'); seq_putc(p, '\n');
unlock: skip:
spin_unlock_irqrestore(&irq_desc[i].lock, flags); spin_unlock_irqrestore(&irq_desc[i].lock, flags);
} else if (i == NR_IRQS) { } else if (i == NR_IRQS)
seq_printf(p, "Err: %10lu\n", irq_err_count); seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
}
return 0; return 0;
} }
...@@ -101,7 +102,6 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -101,7 +102,6 @@ int show_interrupts(struct seq_file *p, void *v)
* come via this function. Instead, they should provide their * come via this function. Instead, they should provide their
* own 'handler' * own 'handler'
*/ */
#ifdef CONFIG_DO_IRQ_L1 #ifdef CONFIG_DO_IRQ_L1
__attribute__((l1_text)) __attribute__((l1_text))
#endif #endif
......
...@@ -363,12 +363,12 @@ void kgdb_passive_cpu_callback(void *info) ...@@ -363,12 +363,12 @@ void kgdb_passive_cpu_callback(void *info)
void kgdb_roundup_cpus(unsigned long flags) void kgdb_roundup_cpus(unsigned long flags)
{ {
smp_call_function(kgdb_passive_cpu_callback, NULL, 0, 0); smp_call_function(kgdb_passive_cpu_callback, NULL, 0);
} }
void kgdb_roundup_cpu(int cpu, unsigned long flags) void kgdb_roundup_cpu(int cpu, unsigned long flags)
{ {
smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0, 0); smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0);
} }
#endif #endif
......
...@@ -343,7 +343,13 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, ...@@ -343,7 +343,13 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
pr_debug("location is %x, value is %x type is %d \n", pr_debug("location is %x, value is %x type is %d \n",
(unsigned int) location32, value, (unsigned int) location32, value,
ELF32_R_TYPE(rel[i].r_info)); ELF32_R_TYPE(rel[i].r_info));
#ifdef CONFIG_SMP
if ((unsigned long)location16 >= COREB_L1_DATA_A_START) {
printk(KERN_ERR "module %s: cannot relocate in L1: %u (SMP kernel)",
mod->name, ELF32_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
#endif
switch (ELF32_R_TYPE(rel[i].r_info)) { switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_pcrel24: case R_pcrel24:
...@@ -436,6 +442,7 @@ module_finalize(const Elf_Ehdr * hdr, ...@@ -436,6 +442,7 @@ module_finalize(const Elf_Ehdr * hdr,
{ {
unsigned int i, strindex = 0, symindex = 0; unsigned int i, strindex = 0, symindex = 0;
char *secstrings; char *secstrings;
long err = 0;
secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
...@@ -460,8 +467,10 @@ module_finalize(const Elf_Ehdr * hdr, ...@@ -460,8 +467,10 @@ module_finalize(const Elf_Ehdr * hdr,
(strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0) || (strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0) ||
((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) && ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
(hdr->e_flags & (EF_BFIN_CODE_IN_L1|EF_BFIN_CODE_IN_L2))))) { (hdr->e_flags & (EF_BFIN_CODE_IN_L1|EF_BFIN_CODE_IN_L2))))) {
apply_relocate_add((Elf_Shdr *) sechdrs, strtab, err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
symindex, i, mod); symindex, i, mod);
if (err < 0)
return -ENOEXEC;
} }
} }
return 0; return 0;
......
...@@ -171,6 +171,13 @@ asmlinkage int bfin_clone(struct pt_regs *regs) ...@@ -171,6 +171,13 @@ asmlinkage int bfin_clone(struct pt_regs *regs)
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
#ifdef __ARCH_SYNC_CORE_DCACHE
if (current->rt.nr_cpus_allowed == num_possible_cpus()) {
current->cpus_allowed = cpumask_of_cpu(smp_processor_id());
current->rt.nr_cpus_allowed = 1;
}
#endif
/* syscall2 puts clone_flags in r0 and usp in r1 */ /* syscall2 puts clone_flags in r0 and usp in r1 */
clone_flags = regs->r0; clone_flags = regs->r0;
newsp = regs->r1; newsp = regs->r1;
...@@ -338,22 +345,22 @@ int _access_ok(unsigned long addr, unsigned long size) ...@@ -338,22 +345,22 @@ int _access_ok(unsigned long addr, unsigned long size)
if (addr >= (unsigned long)__init_begin && if (addr >= (unsigned long)__init_begin &&
addr + size <= (unsigned long)__init_end) addr + size <= (unsigned long)__init_end)
return 1; return 1;
if (addr >= L1_SCRATCH_START if (addr >= get_l1_scratch_start()
&& addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH) && addr + size <= get_l1_scratch_start() + L1_SCRATCH_LENGTH)
return 1; return 1;
#if L1_CODE_LENGTH != 0 #if L1_CODE_LENGTH != 0
if (addr >= L1_CODE_START + (_etext_l1 - _stext_l1) if (addr >= get_l1_code_start() + (_etext_l1 - _stext_l1)
&& addr + size <= L1_CODE_START + L1_CODE_LENGTH) && addr + size <= get_l1_code_start() + L1_CODE_LENGTH)
return 1; return 1;
#endif #endif
#if L1_DATA_A_LENGTH != 0 #if L1_DATA_A_LENGTH != 0
if (addr >= L1_DATA_A_START + (_ebss_l1 - _sdata_l1) if (addr >= get_l1_data_a_start() + (_ebss_l1 - _sdata_l1)
&& addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH) && addr + size <= get_l1_data_a_start() + L1_DATA_A_LENGTH)
return 1; return 1;
#endif #endif
#if L1_DATA_B_LENGTH != 0 #if L1_DATA_B_LENGTH != 0
if (addr >= L1_DATA_B_START + (_ebss_b_l1 - _sdata_b_l1) if (addr >= get_l1_data_b_start() + (_ebss_b_l1 - _sdata_b_l1)
&& addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH) && addr + size <= get_l1_data_b_start() + L1_DATA_B_LENGTH)
return 1; return 1;
#endif #endif
#if L2_LENGTH != 0 #if L2_LENGTH != 0
......
...@@ -220,8 +220,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ...@@ -220,8 +220,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break; break;
pr_debug("ptrace: user address is valid\n"); pr_debug("ptrace: user address is valid\n");
if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START if (L1_CODE_LENGTH != 0 && addr >= get_l1_code_start()
&& addr + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) { && addr + sizeof(tmp) <= get_l1_code_start() + L1_CODE_LENGTH) {
safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp)); safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp));
copied = sizeof(tmp); copied = sizeof(tmp);
...@@ -300,8 +300,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ...@@ -300,8 +300,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break; break;
pr_debug("ptrace: user address is valid\n"); pr_debug("ptrace: user address is valid\n");
if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START if (L1_CODE_LENGTH != 0 && addr >= get_l1_code_start()
&& addr + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) { && addr + sizeof(data) <= get_l1_code_start() + L1_CODE_LENGTH) {
safe_dma_memcpy ((void *)(addr), &data, sizeof(data)); safe_dma_memcpy ((void *)(addr), &data, sizeof(data));
copied = sizeof(data); copied = sizeof(data);
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* the core reset. * the core reset.
*/ */
__attribute__((l1_text)) __attribute__((l1_text))
static void bfin_reset(void) static void _bfin_reset(void)
{ {
/* Wait for completion of "system" events such as cache line /* Wait for completion of "system" events such as cache line
* line fills so that we avoid infinite stalls later on as * line fills so that we avoid infinite stalls later on as
...@@ -66,6 +66,18 @@ static void bfin_reset(void) ...@@ -66,6 +66,18 @@ static void bfin_reset(void)
} }
} }
static void bfin_reset(void)
{
if (ANOMALY_05000353 || ANOMALY_05000386)
_bfin_reset();
else
/* the bootrom checks to see how it was reset and will
* automatically perform a software reset for us when
* it starts executing boot
*/
asm("raise 1;");
}
__attribute__((weak)) __attribute__((weak))
void native_machine_restart(char *cmd) void native_machine_restart(char *cmd)
{ {
...@@ -75,14 +87,10 @@ void machine_restart(char *cmd) ...@@ -75,14 +87,10 @@ void machine_restart(char *cmd)
{ {
native_machine_restart(cmd); native_machine_restart(cmd);
local_irq_disable(); local_irq_disable();
if (ANOMALY_05000353 || ANOMALY_05000386) if (smp_processor_id())
bfin_reset(); smp_call_function((void *)bfin_reset, 0, 1);
else else
/* the bootrom checks to see how it was reset and will bfin_reset();
* automatically perform a software reset for us when
* it starts executing boot
*/
asm("raise 1;");
} }
__attribute__((weak)) __attribute__((weak))
......
This diff is collapsed.
...@@ -34,9 +34,11 @@ ...@@ -34,9 +34,11 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/delay.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/gptimers.h>
/* This is an NTP setting */ /* This is an NTP setting */
#define TICK_SIZE (tick_nsec / 1000) #define TICK_SIZE (tick_nsec / 1000)
...@@ -46,11 +48,14 @@ static unsigned long gettimeoffset(void); ...@@ -46,11 +48,14 @@ static unsigned long gettimeoffset(void);
static struct irqaction bfin_timer_irq = { static struct irqaction bfin_timer_irq = {
.name = "BFIN Timer Tick", .name = "BFIN Timer Tick",
#ifdef CONFIG_IRQ_PER_CPU
.flags = IRQF_DISABLED | IRQF_PERCPU,
#else
.flags = IRQF_DISABLED .flags = IRQF_DISABLED
#endif
}; };
static void void setup_core_timer(void)
time_sched_init(irq_handler_t timer_routine)
{ {
u32 tcount; u32 tcount;
...@@ -71,12 +76,41 @@ time_sched_init(irq_handler_t timer_routine) ...@@ -71,12 +76,41 @@ time_sched_init(irq_handler_t timer_routine)
CSYNC(); CSYNC();
bfin_write_TCNTL(7); bfin_write_TCNTL(7);
}
#ifdef CONFIG_TICK_SOURCE_SYSTMR0
void setup_system_timer0(void)
{
/* Power down the core timer, just to play safe. */
bfin_write_TCNTL(0);
disable_gptimers(TIMER0bit);
set_gptimer_status(0, TIMER_STATUS_TRUN0);
while (get_gptimer_status(0) & TIMER_STATUS_TRUN0)
udelay(10);
set_gptimer_config(0, 0x59); /* IRQ enable, periodic, PWM_OUT, SCLKed, OUT PAD disabled */
set_gptimer_period(TIMER0_id, get_sclk() / HZ);
set_gptimer_pwidth(TIMER0_id, 1);
SSYNC();
enable_gptimers(TIMER0bit);
}
#endif
static void
time_sched_init(irqreturn_t(*timer_routine) (int, void *))
{
#ifdef CONFIG_TICK_SOURCE_SYSTMR0
setup_system_timer0();
#else
setup_core_timer();
#endif
bfin_timer_irq.handler = (irq_handler_t)timer_routine; bfin_timer_irq.handler = (irq_handler_t)timer_routine;
/* call setup_irq instead of request_irq because request_irq calls #ifdef CONFIG_TICK_SOURCE_SYSTMR0
* kmalloc which has not been initialized yet setup_irq(IRQ_TIMER0, &bfin_timer_irq);
*/ #else
setup_irq(IRQ_CORETMR, &bfin_timer_irq); setup_irq(IRQ_CORETMR, &bfin_timer_irq);
#endif
} }
/* /*
...@@ -87,17 +121,23 @@ static unsigned long gettimeoffset(void) ...@@ -87,17 +121,23 @@ static unsigned long gettimeoffset(void)
unsigned long offset; unsigned long offset;
unsigned long clocks_per_jiffy; unsigned long clocks_per_jiffy;
#ifdef CONFIG_TICK_SOURCE_SYSTMR0
clocks_per_jiffy = bfin_read_TIMER0_PERIOD();
offset = bfin_read_TIMER0_COUNTER() / \
(((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC);
if ((get_gptimer_status(0) & TIMER_STATUS_TIMIL0) && offset < (100000 / HZ / 2))
offset += (USEC_PER_SEC / HZ);
#else
clocks_per_jiffy = bfin_read_TPERIOD(); clocks_per_jiffy = bfin_read_TPERIOD();
offset = offset = (clocks_per_jiffy - bfin_read_TCOUNT()) / \
(clocks_per_jiffy - (((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC);
bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) /
USEC_PER_SEC);
/* Check if we just wrapped the counters and maybe missed a tick */ /* Check if we just wrapped the counters and maybe missed a tick */
if ((bfin_read_ILAT() & (1 << IRQ_CORETMR)) if ((bfin_read_ILAT() & (1 << IRQ_CORETMR))
&& (offset < (100000 / HZ / 2))) && (offset < (100000 / HZ / 2)))
offset += (USEC_PER_SEC / HZ); offset += (USEC_PER_SEC / HZ);
#endif
return offset; return offset;
} }
...@@ -120,34 +160,38 @@ irqreturn_t timer_interrupt(int irq, void *dummy) ...@@ -120,34 +160,38 @@ irqreturn_t timer_interrupt(int irq, void *dummy)
static long last_rtc_update; static long last_rtc_update;
write_seqlock(&xtime_lock); write_seqlock(&xtime_lock);
#ifdef CONFIG_TICK_SOURCE_SYSTMR0
do_timer(1); if (get_gptimer_status(0) & TIMER_STATUS_TIMIL0) {
#endif
profile_tick(CPU_PROFILING); do_timer(1);
/*
* If we have an externally synchronized Linux clock, then update /*
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * If we have an externally synchronized Linux clock, then update
* called as close as possible to 500 ms before the new second starts. * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
*/ * called as close as possible to 500 ms before the new second starts.
*/
if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 && if (ntp_synced() &&
(xtime.tv_nsec / NSEC_PER_USEC) >= xtime.tv_sec > last_rtc_update + 660 &&
500000 - ((unsigned)TICK_SIZE) / 2 (xtime.tv_nsec / NSEC_PER_USEC) >=
&& (xtime.tv_nsec / NSEC_PER_USEC) <= 500000 - ((unsigned)TICK_SIZE) / 2
500000 + ((unsigned)TICK_SIZE) / 2) { && (xtime.tv_nsec / NSEC_PER_USEC) <=
if (set_rtc_mmss(xtime.tv_sec) == 0) 500000 + ((unsigned)TICK_SIZE) / 2) {
last_rtc_update = xtime.tv_sec; if (set_rtc_mmss(xtime.tv_sec) == 0)
else last_rtc_update = xtime.tv_sec;
/* Do it again in 60s. */ else
last_rtc_update = xtime.tv_sec - 600; /* Do it again in 60s. */
last_rtc_update = xtime.tv_sec - 600;
}
#ifdef CONFIG_TICK_SOURCE_SYSTMR0
set_gptimer_status(0, TIMER_STATUS_TIMIL0);
} }
#endif
write_sequnlock(&xtime_lock); write_sequnlock(&xtime_lock);
#ifndef CONFIG_SMP
update_process_times(user_mode(get_irq_regs())); update_process_times(user_mode(get_irq_regs()));
#endif profile_tick(CPU_PROFILING);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -75,16 +75,6 @@ void __init trap_init(void) ...@@ -75,16 +75,6 @@ void __init trap_init(void)
CSYNC(); CSYNC();
} }
/*
* Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
* values across the transition from exception to IRQ5.
* We put these in L1, so they are going to be in a valid
* location during exception context
*/
__attribute__((l1_data))
unsigned long saved_retx, saved_seqstat,
saved_icplb_fault_addr, saved_dcplb_fault_addr;
static void decode_address(char *buf, unsigned long address) static void decode_address(char *buf, unsigned long address)
{ {
#ifdef CONFIG_DEBUG_VERBOSE #ifdef CONFIG_DEBUG_VERBOSE
...@@ -211,18 +201,18 @@ asmlinkage void double_fault_c(struct pt_regs *fp) ...@@ -211,18 +201,18 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) {
unsigned int cpu = smp_processor_id();
char buf[150]; char buf[150];
decode_address(buf, saved_retx); decode_address(buf, cpu_pda[cpu].retx);
printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
(int)saved_seqstat & SEQSTAT_EXCAUSE, buf); (unsigned int)cpu_pda[cpu].seqstat & SEQSTAT_EXCAUSE, buf);
decode_address(buf, saved_dcplb_fault_addr); decode_address(buf, cpu_pda[cpu].dcplb_fault_addr);
printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf);
decode_address(buf, saved_icplb_fault_addr); decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf);
decode_address(buf, fp->retx); decode_address(buf, fp->retx);
printk(KERN_NOTICE "The instruction at %s caused a double exception\n", printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf);
buf);
} else } else
#endif #endif
{ {
...@@ -239,6 +229,9 @@ asmlinkage void trap_c(struct pt_regs *fp) ...@@ -239,6 +229,9 @@ asmlinkage void trap_c(struct pt_regs *fp)
{ {
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
int j; int j;
#endif
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
unsigned int cpu = smp_processor_id();
#endif #endif
int sig = 0; int sig = 0;
siginfo_t info; siginfo_t info;
...@@ -417,7 +410,7 @@ asmlinkage void trap_c(struct pt_regs *fp) ...@@ -417,7 +410,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
info.si_code = ILL_CPLB_MULHIT; info.si_code = ILL_CPLB_MULHIT;
sig = SIGSEGV; sig = SIGSEGV;
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
if (saved_dcplb_fault_addr < FIXED_CODE_START) if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START)
verbose_printk(KERN_NOTICE "NULL pointer access\n"); verbose_printk(KERN_NOTICE "NULL pointer access\n");
else else
#endif #endif
...@@ -471,7 +464,7 @@ asmlinkage void trap_c(struct pt_regs *fp) ...@@ -471,7 +464,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
info.si_code = ILL_CPLB_MULHIT; info.si_code = ILL_CPLB_MULHIT;
sig = SIGSEGV; sig = SIGSEGV;
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
if (saved_icplb_fault_addr < FIXED_CODE_START) if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START)
verbose_printk(KERN_NOTICE "Jump to NULL address\n"); verbose_printk(KERN_NOTICE "Jump to NULL address\n");
else else
#endif #endif
...@@ -960,6 +953,7 @@ void dump_bfin_process(struct pt_regs *fp) ...@@ -960,6 +953,7 @@ void dump_bfin_process(struct pt_regs *fp)
else else
verbose_printk(KERN_NOTICE "COMM= invalid\n"); verbose_printk(KERN_NOTICE "COMM= invalid\n");
printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu);
if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
verbose_printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" verbose_printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
KERN_NOTICE " BSS = 0x%p-0x%p USER-STACK = 0x%p\n" KERN_NOTICE " BSS = 0x%p-0x%p USER-STACK = 0x%p\n"
...@@ -1053,6 +1047,7 @@ void show_regs(struct pt_regs *fp) ...@@ -1053,6 +1047,7 @@ void show_regs(struct pt_regs *fp)
struct irqaction *action; struct irqaction *action;
unsigned int i; unsigned int i;
unsigned long flags; unsigned long flags;
unsigned int cpu = smp_processor_id();
verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted()); verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n",
...@@ -1112,9 +1107,9 @@ void show_regs(struct pt_regs *fp) ...@@ -1112,9 +1107,9 @@ void show_regs(struct pt_regs *fp)
if (((long)fp->seqstat & SEQSTAT_EXCAUSE) && if (((long)fp->seqstat & SEQSTAT_EXCAUSE) &&
(((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
decode_address(buf, saved_dcplb_fault_addr); decode_address(buf, cpu_pda[cpu].dcplb_fault_addr);
verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
decode_address(buf, saved_icplb_fault_addr); decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
} }
...@@ -1153,20 +1148,21 @@ void show_regs(struct pt_regs *fp) ...@@ -1153,20 +1148,21 @@ void show_regs(struct pt_regs *fp)
asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
#endif #endif
asmlinkage int sys_bfin_spinlock(int *spinlock) static DEFINE_SPINLOCK(bfin_spinlock_lock);
asmlinkage int sys_bfin_spinlock(int *p)
{ {
int ret = 0; int ret, tmp = 0;
int tmp = 0;
local_irq_disable(); spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */
ret = get_user(tmp, spinlock); ret = get_user(tmp, p);
if (ret == 0) { if (likely(ret == 0)) {
if (tmp) if (unlikely(tmp))
ret = 1; ret = 1;
tmp = 1; else
put_user(tmp, spinlock); put_user(1, p);
} }
local_irq_enable(); spin_unlock(&bfin_spinlock_lock);
return ret; return ret;
} }
......
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/bfin-global.h> #include <asm/bfin-global.h>
#include <asm/l1layout.h> #include <asm/pda.h>
#include <asm/cplbinit.h>
#include "blackfin_sram.h" #include "blackfin_sram.h"
/* /*
...@@ -53,6 +54,11 @@ static unsigned long empty_bad_page; ...@@ -53,6 +54,11 @@ static unsigned long empty_bad_page;
unsigned long empty_zero_page; unsigned long empty_zero_page;
extern unsigned long exception_stack[NR_CPUS][1024];
struct blackfin_pda cpu_pda[NR_CPUS];
EXPORT_SYMBOL(cpu_pda);
/* /*
* paging_init() continues the virtual memory environment setup which * paging_init() continues the virtual memory environment setup which
* was begun by the code in arch/head.S. * was begun by the code in arch/head.S.
...@@ -98,6 +104,42 @@ void __init paging_init(void) ...@@ -98,6 +104,42 @@ void __init paging_init(void)
} }
} }
asmlinkage void init_pda(void)
{
unsigned int cpu = raw_smp_processor_id();
/* Initialize the PDA fields holding references to other parts
of the memory. The content of such memory is still
undefined at the time of the call, we are only setting up
valid pointers to it. */
memset(&cpu_pda[cpu], 0, sizeof(cpu_pda[cpu]));
cpu_pda[0].next = &cpu_pda[1];
cpu_pda[1].next = &cpu_pda[0];
cpu_pda[cpu].ex_stack = exception_stack[cpu + 1];
#ifdef CONFIG_MPU
#else
cpu_pda[cpu].ipdt = ipdt_tables[cpu];
cpu_pda[cpu].dpdt = dpdt_tables[cpu];
#ifdef CONFIG_CPLB_INFO
cpu_pda[cpu].ipdt_swapcount = ipdt_swapcount_tables[cpu];
cpu_pda[cpu].dpdt_swapcount = dpdt_swapcount_tables[cpu];
#endif
#endif
#ifdef CONFIG_SMP
cpu_pda[cpu].imask = 0x1f;
#endif
}
void __cpuinit reserve_pda(void)
{
printk(KERN_INFO "PDA for CPU%u reserved at %p\n", smp_processor_id(),
&cpu_pda[smp_processor_id()]);
}
void __init mem_init(void) void __init mem_init(void)
{ {
unsigned int codek = 0, datak = 0, initk = 0; unsigned int codek = 0, datak = 0, initk = 0;
...@@ -141,21 +183,13 @@ void __init mem_init(void) ...@@ -141,21 +183,13 @@ void __init mem_init(void)
static int __init sram_init(void) static int __init sram_init(void)
{ {
unsigned long tmp;
/* Initialize the blackfin L1 Memory. */ /* Initialize the blackfin L1 Memory. */
bfin_sram_init(); bfin_sram_init();
/* Allocate this once; never free it. We assume this gives us a /* Reserve the PDA space for the boot CPU right after we
pointer to the start of L1 scratchpad memory; panic if it * initialized the scratch memory allocator.
doesn't. */ */
tmp = (unsigned long)l1sram_alloc(sizeof(struct l1_scratch_task_info)); reserve_pda();
if (tmp != (unsigned long)L1_SCRATCH_TASK_INFO) {
printk(KERN_EMERG "mem_init(): Did not get the right address from l1sram_alloc: %08lx != %08lx\n",
tmp, (unsigned long)L1_SCRATCH_TASK_INFO);
panic("No L1, time to give up\n");
}
return 0; return 0;
} }
pure_initcall(sram_init); pure_initcall(sram_init);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment