summaryrefslogtreecommitdiffstats
path: root/arch/alpha
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-17 13:25:08 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-17 13:25:08 +0000
commit59223edaa18759982db0a8aced0e77457d10c68e (patch)
tree89354903b01fa0a447bffeefe00df3044495db2e /arch/alpha
parentdb7d4daea91e105e3859cf461d7e53b9b77454b2 (diff)
Merge with Linux 2.3.6. Sorry, this isn't tested on silicon, I don't
have a MIPS box at hand.
Diffstat (limited to 'arch/alpha')
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c1
-rw-r--r--arch/alpha/kernel/fpreg.c6
-rw-r--r--arch/alpha/kernel/head.S36
-rw-r--r--arch/alpha/kernel/irq.c10
-rw-r--r--arch/alpha/kernel/process.c49
-rw-r--r--arch/alpha/kernel/proto.h4
-rw-r--r--arch/alpha/kernel/ptrace.c23
-rw-r--r--arch/alpha/kernel/signal.c3
-rw-r--r--arch/alpha/kernel/smp.c1239
-rw-r--r--arch/alpha/kernel/time.c90
-rw-r--r--arch/alpha/kernel/traps.c21
-rw-r--r--arch/alpha/lib/memcpy.c88
-rw-r--r--arch/alpha/mm/init.c20
13 files changed, 861 insertions, 729 deletions
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 65975c168..ce949d722 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -52,6 +52,7 @@ EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(screen_info);
EXPORT_SYMBOL(perf_irq);
diff --git a/arch/alpha/kernel/fpreg.c b/arch/alpha/kernel/fpreg.c
index 6da94c0cb..0bd8b9f67 100644
--- a/arch/alpha/kernel/fpreg.c
+++ b/arch/alpha/kernel/fpreg.c
@@ -1,10 +1,10 @@
/*
- * kernel/fpreg.c
+ * arch/alpha/kernel/fpreg.c
*
* (C) Copyright 1998 Linus Torvalds
*/
-#ifdef __alpha_cix__
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
#define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
#else
#define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val));
@@ -52,7 +52,7 @@ alpha_read_fp_reg (unsigned long reg)
return val;
}
-#ifdef __alpha_cix__
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
#define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val));
#else
#define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val));
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index 8ba50462b..3fcbdbcda 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -32,24 +32,26 @@ __start:
#ifdef __SMP__
.align 3
- .globl __start_cpu
- .ent __start_cpu
- /* On entry here from SRM console, the HWPCB of this processor
- has been loaded, and $27 contains the task pointer */
-__start_cpu:
- .prologue 0
- /* First order of business, load the GP */
- br $26,1f
-1: ldgp $29,0($26)
- /* We need to get current loaded up with our first task... */
- mov $27,$8
- /* Set FEN */
- lda $16,1($31)
- call_pal PAL_wrfen
- /* ... and then we can start the processor. */
- jsr $26,start_secondary
+ .globl __smp_callin
+ .ent __smp_callin
+ /* On entry here from SRM console, the HWPCB of the per-cpu
+ slot for this processor has been loaded. We've arranged
+ for the UNIQUE value for this process to contain the PCBB
+ of the target idle task. */
+__smp_callin:
+ .prologue 1
+ ldgp $29,0($27) # First order of business, load the GP.
+
+ call_pal PAL_rduniq # Grab the target PCBB.
+ mov $0,$16 # Install it.
+ call_pal PAL_swpctx
+
+ lda $8,0x3fff # Find "current".
+ bic $30,$8,$8
+
+ jsr $26,smp_callin
call_pal PAL_halt
- .end __start_cpu
+ .end __smp_callin
#endif /* __SMP__ */
.align 3
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index e1a53ab57..d53f7ffea 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -192,7 +192,7 @@ unmask_irq(unsigned long irq)
}
void
-disable_irq(unsigned int irq_nr)
+disable_irq_nosync(unsigned int irq_nr)
{
unsigned long flags;
@@ -202,6 +202,14 @@ disable_irq(unsigned int irq_nr)
}
void
+disable_irq(unsigned int irq_nr)
+{
+ /* This works non-SMP, and SMP until we write code to distribute
+ interrupts to more that cpu 0. */
+ disable_irq_nosync(irq_nr);
+}
+
+void
enable_irq(unsigned int irq_nr)
{
unsigned long flags;
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 93d8db602..1993ed3b4 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -58,10 +58,10 @@ static struct fs_struct init_fs = INIT_FS;
static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
-struct mm_struct init_mm = INIT_MM;
+struct mm_struct init_mm = INIT_MM(init_mm);
union task_union init_task_union __attribute__((section("init_task")))
- = { task: INIT_TASK };
+ = { task: INIT_TASK(init_task_union.task) };
/*
* No need to acquire the kernel lock, we're entirely local..
@@ -75,33 +75,46 @@ sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
return 0;
}
-static void __attribute__((noreturn))
-do_cpu_idle(void)
+#ifdef __SMP__
+void
+cpu_idle(void *unused)
{
/* An endless idle loop with no priority at all. */
current->priority = 0;
+ current->counter = -100;
+
while (1) {
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
- current->counter = 0;
- schedule();
+ /* FIXME -- EV6 and LCA45 know how to power down
+ the CPU. */
+
+ /* Although we are an idle CPU, we do not want to
+ get into the scheduler unnecessarily. */
+ if (current->need_resched) {
+ schedule();
+ check_pgt_cache();
+ }
}
}
-
-#ifdef __SMP__
-void
-cpu_idle(void *unused)
-{
- do_cpu_idle();
-}
#endif
asmlinkage int
sys_idle(void)
{
- if (current->pid == 0)
- do_cpu_idle();
- return -EPERM;
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* An endless idle loop with no priority at all. */
+ current->priority = 0;
+ current->counter = -100;
+ init_idle();
+
+ while (1) {
+ /* FIXME -- EV6 and LCA45 know how to power down
+ the CPU. */
+
+ schedule();
+ check_pgt_cache();
+ }
}
void
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index 8a0efe52d..f7e54a982 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -151,6 +151,8 @@ extern unsigned long srm_hae;
extern void setup_smp(void);
extern int smp_info(char *buffer);
extern void handle_ipi(struct pt_regs *);
+extern void smp_percpu_timer_interrupt(struct pt_regs *);
+extern int smp_boot_cpuid;
/* bios32.c */
extern void reset_for_srm(void);
@@ -178,7 +180,7 @@ extern unsigned long alpha_read_fp_reg (unsigned long reg);
extern void wrmces(unsigned long mces);
extern void cserve_ena(unsigned long);
extern void cserve_dis(unsigned long);
-extern void __start_cpu(unsigned long);
+extern void __smp_callin(void);
/* entry.S */
extern void entArith(void);
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 18c9a8b13..3e20e7091 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -246,26 +246,6 @@ put_long(struct task_struct * tsk, struct vm_area_struct * vma,
flush_tlb();
}
-static struct vm_area_struct *
-find_extend_vma(struct task_struct * tsk, unsigned long addr)
-{
- struct vm_area_struct * vma;
-
- addr &= PAGE_MASK;
- vma = find_vma(tsk->mm,addr);
- if (!vma)
- return NULL;
- if (vma->vm_start <= addr)
- return vma;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- return NULL;
- if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
- return NULL;
- vma->vm_offset -= vma->vm_start - addr;
- vma->vm_start = addr;
- return vma;
-}
-
/*
* This routine checks the page boundaries, and that the offset is
* within the task area. It then calls get_long() to read a long.
@@ -506,7 +486,8 @@ sys_ptrace(long request, long pid, long addr, long data,
(current->uid != child->uid) ||
(current->gid != child->egid) ||
(current->gid != child->sgid) ||
- (current->gid != child->gid))
+ (current->gid != child->gid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)))
&& !capable(CAP_SYS_PTRACE))
goto out;
/* the same process cannot be attached many times */
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 99bd36785..a477c2344 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -24,6 +24,9 @@
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
+#include "proto.h"
+
+
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index aa1eaf363..f01c0e55d 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -18,6 +18,7 @@
#include <asm/ptrace.h>
#include <asm/atomic.h>
+#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
@@ -29,6 +30,8 @@
#include <asm/unistd.h>
#include "proto.h"
+#include "irq.h"
+
#define DEBUG_SMP 0
#if DEBUG_SMP
@@ -37,62 +40,44 @@
#define DBGS(args)
#endif
-struct ipi_msg_flush_tb_struct {
- volatile unsigned int flush_tb_mask;
- union {
- struct mm_struct * flush_mm;
- struct vm_area_struct * flush_vma;
- } p;
- unsigned long flush_addr;
- unsigned long flush_end;
-};
-
-static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
-static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
-
+/* A collection of per-processor data. */
struct cpuinfo_alpha cpu_data[NR_CPUS];
-spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
-
-unsigned int boot_cpu_id = 0;
-static int smp_activated = 0;
+/* A collection of single bit ipi messages. */
+static struct {
+ unsigned long bits __cacheline_aligned;
+} ipi_data[NR_CPUS];
-int smp_found_config = 0; /* Have we found an SMP box */
-static int max_cpus = -1;
+enum ipi_message_type {
+ IPI_RESCHEDULE,
+ IPI_CALL_FUNC,
+ IPI_CPU_STOP,
+};
-unsigned int cpu_present_map = 0;
+spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
-int smp_num_cpus = 1;
-int smp_num_probed = 0; /* Internal processor count */
+/* Set to a secondary's cpuid when it comes online. */
+static unsigned long smp_secondary_alive;
-int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
+unsigned long cpu_present_mask; /* Which cpus ids came online. */
+static int max_cpus = -1; /* Command-line limitation. */
+int smp_boot_cpuid; /* Which processor we booted from. */
+int smp_num_probed; /* Internal processor count */
+int smp_num_cpus = 1; /* Number that came online. */
+int smp_threads_ready; /* True once the per process idle is forked. */
cycles_t cacheflush_time;
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
-
-volatile int ipi_bits[NR_CPUS] __cacheline_aligned;
-
-unsigned long boot_cpu_palrev;
-
-volatile int smp_commenced = 0;
-volatile int smp_processors_ready = 0;
-
-volatile int cpu_number_map[NR_CPUS];
-volatile int cpu_logical_map[NR_CPUS];
+int cpu_number_map[NR_CPUS];
+int __cpu_logical_map[NR_CPUS];
extern void calibrate_delay(void);
-extern struct thread_struct * original_pcb_ptr;
+extern asmlinkage void entInt(void);
-static void smp_setup_percpu_timer(void);
-static void secondary_cpu_start(int, struct task_struct *);
-static void send_cpu_msg(char *, int);
-
-/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */
+
+/*
+ * Process bootcommand SMP options, like "nosmp" and "maxcpus=".
+ */
void __init
smp_setup(char *str, int *ints)
{
@@ -102,100 +87,87 @@ smp_setup(char *str, int *ints)
max_cpus = 0;
}
-static void __init
-smp_store_cpu_info(int id)
+/*
+ * Called by both boot and secondaries to move global data into
+ * per-processor storage.
+ */
+static inline void __init
+smp_store_cpu_info(int cpuid)
{
- /* This is it on Alpha, so far. */
- cpu_data[id].loops_per_sec = loops_per_sec;
+ cpu_data[cpuid].loops_per_sec = loops_per_sec;
}
-void __init
-smp_commence(void)
+/*
+ * Ideally sets up per-cpu profiling hooks. Doesn't do much now...
+ */
+static inline void __init
+smp_setup_percpu_timer(int cpuid)
{
- /* Lets the callin's below out of their loop. */
- mb();
- smp_commenced = 1;
+ cpu_data[cpuid].prof_counter = 1;
+ cpu_data[cpuid].prof_multiplier = 1;
+
+#ifdef NOT_YET_PROFILING
+ load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+ if (cpu == smp_boot_cpuid)
+ enable_pil_irq(14);
+#endif
}
+/*
+ * Where secondaries begin a life of C.
+ */
void __init
smp_callin(void)
{
int cpuid = hard_smp_processor_id();
DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state));
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
-#if 0
- set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
+
+ /* Turn on machine checks. */
+ wrmces(7);
+
+ /* Set trap vectors. */
+ trap_init();
+
+ /* Set interrupt vector. */
+ wrent(entInt, 0);
+
+ /* Setup the scheduler for this processor. */
+ init_idle();
/* Get our local ticker going. */
- smp_setup_percpu_timer();
+ smp_setup_percpu_timer(cpuid);
-#if 0
+ /* Must have completely accurate bogos. */
+ __sti();
calibrate_delay();
-#endif
smp_store_cpu_info(cpuid);
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
/* Allow master to continue. */
- set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]);
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
-
-#ifdef NOT_YET
- while(!task[cpuid] || current_set[cpuid] != task[cpuid])
- barrier();
-#endif
+ wmb();
+ smp_secondary_alive = cpuid;
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
-#if 0
- __sti();
-#endif
-}
+ /* Wait for the go code. */
+ while (!smp_threads_ready)
+ barrier();
-asmlinkage int __init
-start_secondary(void *unused)
-{
- extern asmlinkage void entInt(void);
- extern void paging_init_secondary(void);
+ printk(KERN_INFO "SMP: commencing CPU %d current %p\n",
+ cpuid, current);
- wrmces(7);
- paging_init_secondary();
- trap_init();
- wrent(entInt, 0);
-
- smp_callin();
- while (!smp_commenced)
- barrier();
-#if 1
- printk("start_secondary: commencing CPU %d current %p\n",
- hard_smp_processor_id(), current);
-#endif
+ /* Do nothing. */
cpu_idle(NULL);
}
+
+/*
+ * Rough estimation for SMP scheduling, this is the number of cycles it
+ * takes for a fully memory-limited process to flush the SMP-local cache.
+ *
+ * We are not told how much cache there is, so we have to guess.
+ */
static void __init
smp_tune_scheduling (void)
{
- /*
- * Rough estimation for SMP scheduling, this is the number of
- * cycles it takes for a fully memory-limited process to flush
- * the SMP-local cache.
- *
- * We are not told how much cache there is, so we have to guess.
- */
-
struct percpu_struct *cpu;
unsigned long on_chip_cache;
unsigned long freq;
@@ -231,259 +203,159 @@ smp_tune_scheduling (void)
cacheflush_time = freq / 1024 * on_chip_cache / 5000;
}
-
/*
- * Cycle through the processors sending START msgs to boot each.
+ * Send a message to a secondary's console. "START" is one such
+ * interesting message. ;-)
*/
-void __init
-smp_boot_cpus(void)
+static void
+send_secondary_console_msg(char *str, int cpuid)
{
- int cpucount = 0;
- int i, first, prev;
-
- printk("Entering SMP Mode.\n");
-
-#if 0
- __sti();
-#endif
-
- for(i=0; i < NR_CPUS; i++) {
- cpu_number_map[i] = -1;
- cpu_logical_map[i] = -1;
- prof_counter[i] = 1;
- prof_multiplier[i] = 1;
- ipi_bits[i] = 0;
- }
-
- cpu_number_map[boot_cpu_id] = 0;
- cpu_logical_map[0] = boot_cpu_id;
- current->processor = boot_cpu_id; /* ??? */
-
- smp_store_cpu_info(boot_cpu_id);
- smp_tune_scheduling();
-#ifdef NOT_YET
- printk("CPU%d: ", boot_cpu_id);
- print_cpu_info(&cpu_data[boot_cpu_id]);
- set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
- smp_setup_percpu_timer();
-#ifdef HUH
- local_flush_cache_all();
-#endif
- if (smp_num_probed == 1)
- return; /* Not an MP box. */
-
-#if NOT_YET
- /*
- * If SMP should be disabled, then really disable it!
- */
- if (!max_cpus)
- {
- smp_found_config = 0;
- printk(KERN_INFO "SMP mode deactivated.\n");
- }
-#endif
-
- for (i = 0; i < NR_CPUS; i++) {
+ struct percpu_struct *cpu;
+ register char *cp1, *cp2;
+ unsigned long cpumask;
+ size_t len;
+ long timeout;
- if (i == boot_cpu_id)
- continue;
+ cpu = (struct percpu_struct *)
+ ((char*)hwrpb
+ + hwrpb->processor_offset
+ + cpuid * hwrpb->processor_size);
- if (cpu_present_map & (1 << i)) {
- struct task_struct *idle;
- int timeout;
+ cpumask = (1L << cpuid);
+ if (hwrpb->txrdy & cpumask)
+ goto delay1;
+ ready1:
- /* Cook up an idler for this guy. */
- kernel_thread(start_secondary, NULL, CLONE_PID);
- idle = task[++cpucount];
- if (!idle)
- panic("No idle process for CPU %d", i);
- idle->processor = i;
+ cp2 = str;
+ len = strlen(cp2);
+ *(unsigned int *)&cpu->ipc_buffer[0] = len;
+ cp1 = (char *) &cpu->ipc_buffer[1];
+ memcpy(cp1, cp2, len);
- DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n",
- i, idle->state, idle->flags));
+ /* atomic test and set */
+ wmb();
+ set_bit(cpuid, &hwrpb->rxrdy);
- /* whirrr, whirrr, whirrrrrrrrr... */
-#ifdef HUH
- local_flush_cache_all();
-#endif
- secondary_cpu_start(i, idle);
+ if (hwrpb->txrdy & cpumask)
+ goto delay2;
+ ready2:
+ return;
- /* wheee... it's going... wait for 5 secs...*/
- for (timeout = 0; timeout < 50000; timeout++) {
- if (cpu_callin_map[i])
- break;
- udelay(100);
- }
- if (cpu_callin_map[i]) {
- /* Another "Red Snapper". */
- cpu_number_map[i] = cpucount;
- cpu_logical_map[cpucount] = i;
- } else {
- cpucount--;
- printk("smp_boot_cpus: Processor %d"
- " is stuck 0x%lx.\n", i, idle->flags);
- }
- }
- if (!(cpu_callin_map[i])) {
- cpu_present_map &= ~(1 << i);
- cpu_number_map[i] = -1;
- }
- }
-#ifdef HUH
- local_flush_cache_all();
-#endif
- if (cpucount == 0) {
- printk("smp_boot_cpus: ERROR - only one Processor found.\n");
- cpu_present_map = (1 << smp_processor_id());
- } else {
- unsigned long bogosum = 0;
- for (i = 0; i < NR_CPUS; i++) {
- if (cpu_present_map & (1 << i))
- bogosum += cpu_data[i].loops_per_sec;
- }
- printk("smp_boot_cpus: Total of %d Processors activated"
- " (%lu.%02lu BogoMIPS).\n",
- cpucount + 1,
- (bogosum + 2500)/500000,
- ((bogosum + 2500)/5000)%100);
- smp_activated = 1;
- smp_num_cpus = cpucount + 1;
+delay1:
+ /* Wait one second. Note that jiffies aren't ticking yet. */
+ for (timeout = 100000; timeout > 0; --timeout) {
+ if (!(hwrpb->txrdy & cpumask))
+ goto ready1;
+ udelay(10);
+ barrier();
}
+ goto timeout;
- /* Setup CPU list for IRQ distribution scheme. */
- first = prev = -1;
- for (i = 0; i < NR_CPUS; i++) {
- if (cpu_present_map & (1 << i)) {
- if (first == -1)
- first = i;
- if (prev != -1)
- cpu_data[i].next = i;
- prev = i;
- }
+delay2:
+ /* Wait one second. */
+ for (timeout = 100000; timeout > 0; --timeout) {
+ if (!(hwrpb->txrdy & cpumask))
+ goto ready2;
+ udelay(10);
+ barrier();
}
- cpu_data[prev].next = first;
+ goto timeout;
- /* Ok, they are spinning and ready to go. */
- smp_processors_ready = 1;
+timeout:
+ printk("Processor %x not ready\n", cpuid);
+ return;
}
-static void __init
-smp_setup_percpu_timer(void)
+/*
+ * A secondary console wants to send a message. Receive it.
+ */
+static void
+recv_secondary_console_msg(void)
{
- int cpu = smp_processor_id();
-
- prof_counter[cpu] = prof_multiplier[cpu] = 1;
-#ifdef NOT_YET
- load_profile_irq(mid_xlate[cpu], lvl14_resolution);
- if (cpu == boot_cpu_id)
- enable_pil_irq(14);
-#endif
-}
-
-extern void update_one_process(struct task_struct *p, unsigned long ticks,
- unsigned long user, unsigned long system,
- int cpu);
+ int mycpu, i, cnt;
+ unsigned long txrdy = hwrpb->txrdy;
+ char *cp1, *cp2, buf[80];
+ struct percpu_struct *cpu;
-void
-smp_percpu_timer_interrupt(struct pt_regs *regs)
-{
- int cpu = smp_processor_id();
+ DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy));
-#ifdef NOT_YET
- clear_profile_irq(mid_xlate[cpu]);
- if(!user_mode(regs))
- alpha_do_profile(regs->pc);
-#endif
+ mycpu = hard_smp_processor_id();
- if (!--prof_counter[cpu]) {
- int user = user_mode(regs);
- if (current->pid) {
- update_one_process(current, 1, user, !user, cpu);
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!(txrdy & (1L << i)))
+ continue;
- if (--current->counter < 0) {
- current->counter = 0;
- current->need_resched = 1;
- }
+ DBGS(("recv_secondary_console_msg: "
+ "TXRDY contains CPU %d.\n", i));
- spin_lock(&ticker_lock);
- if (user) {
- if (current->priority < DEF_PRIORITY) {
- kstat.cpu_nice++;
- kstat.per_cpu_nice[cpu]++;
- } else {
- kstat.cpu_user++;
- kstat.per_cpu_user[cpu]++;
- }
- } else {
- kstat.cpu_system++;
- kstat.per_cpu_system[cpu]++;
- }
- spin_unlock(&ticker_lock);
- }
- prof_counter[cpu] = prof_multiplier[cpu];
- }
-}
+ cpu = (struct percpu_struct *)
+ ((char*)hwrpb
+ + hwrpb->processor_offset
+ + i * hwrpb->processor_size);
-int __init
-setup_profiling_timer(unsigned int multiplier)
-{
-#ifdef NOT_YET
- int i;
- unsigned long flags;
+ printk(KERN_INFO "recv_secondary_console_msg: on %d from %d"
+ " HALT_REASON 0x%lx FLAGS 0x%lx\n",
+ mycpu, i, cpu->halt_reason, cpu->flags);
- /* Prevent level14 ticker IRQ flooding. */
- if((!multiplier) || (lvl14_resolution / multiplier) < 500)
- return -EINVAL;
+ cnt = cpu->ipc_buffer[0] >> 32;
+ if (cnt <= 0 || cnt >= 80)
+ strcpy(buf, "<<< BOGUS MSG >>>");
+ else {
+ cp1 = (char *) &cpu->ipc_buffer[11];
+ cp2 = buf;
+ strcpy(cp2, cp1);
+
+ while ((cp2 = strchr(cp2, '\r')) != 0) {
+ *cp2 = ' ';
+ if (cp2[1] == '\n')
+ cp2[1] = ' ';
+ }
+ }
- save_and_cli(flags);
- for(i = 0; i < NR_CPUS; i++) {
- if(cpu_present_map & (1 << i)) {
- load_profile_irq(mid_xlate[i], lvl14_resolution / multip
-lier);
- prof_multiplier[i] = multiplier;
- }
+ printk(KERN_INFO "recv_secondary_console_msg: on %d "
+ "message is '%s'\n", mycpu, buf);
}
- restore_flags(flags);
-
- return 0;
-
-#endif
- return -EINVAL;
-}
-
-/* Only broken Intel needs this, thus it should not even be
- referenced globally. */
-void __init
-initialize_secondary(void)
-{
+ hwrpb->txrdy = 0;
}
-static void __init
+/*
+ * Convince the console to have a secondary cpu begin execution.
+ */
+static int __init
secondary_cpu_start(int cpuid, struct task_struct *idle)
{
struct percpu_struct *cpu;
- int timeout;
+ struct pcb_struct *hwpcb;
+ long timeout;
cpu = (struct percpu_struct *)
((char*)hwrpb
+ hwrpb->processor_offset
+ cpuid * hwrpb->processor_size);
-
- /* Set context to idle thread this CPU will use when running
- assumption is that the idle thread is all set to go... ??? */
- memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct));
- cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */
-
- DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n",
- cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb));
+ hwpcb = (struct pcb_struct *) cpu->hwpcb;
+
+ /* Initialize the CPU's HWPCB to something just good enough for
+ us to get started. Immediately after starting, we'll swpctx
+ to the target idle task's tss. Reuse the stack in the mean
+ time. Precalculate the target PCBB. */
+ hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16;
+ hwpcb->usp = 0;
+ hwpcb->ptbr = idle->tss.ptbr;
+ hwpcb->pcc = 0;
+ hwpcb->asn = 0;
+ hwpcb->unique = virt_to_phys(&idle->tss);
+ hwpcb->flags = idle->tss.pal_flags;
+ hwpcb->res1 = hwpcb->res2 = 0;
+
+ DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
+ hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique));
DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
cpuid, idle->state, idle->tss.pal_flags));
/* Setup HWRPB fields that SRM uses to activate secondary CPU */
- hwrpb->CPU_restart = __start_cpu;
- hwrpb->CPU_restart_data = (unsigned long) idle;
+ hwrpb->CPU_restart = __smp_callin;
+ hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
/* Recalculate and update the HWRPB checksum */
hwrpb_update_checksum(hwrpb);
@@ -495,99 +367,97 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
/* SRM III 3.4.1.3 */
cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */
cpu->flags &= ~1; /* turn off Bootstrap In Progress */
- mb();
+ wmb();
- send_cpu_msg("START\r\n", cpuid);
+ send_secondary_console_msg("START\r\n", cpuid);
- /* now, we wait... */
- for (timeout = 10000; !(cpu->flags & 1); timeout--) {
- if (timeout <= 0) {
- printk("Processor %d failed to start\n", cpuid);
- /* needed for pset_info to work */
-#if 0
- ipc_processor_enable(cpu_to_processor(cpunum));
-#endif
- return;
- }
- mdelay(1);
+ /* Wait 1 second for an ACK from the console. Note that jiffies
+ aren't ticking yet. */
+ for (timeout = 100000; timeout > 0; timeout--) {
+ if (cpu->flags & 1)
+ goto started;
+ udelay(10);
barrier();
}
+ printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
+ return -1;
+
+started:
DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
+ return 0;
}
-static void
-send_cpu_msg(char *str, int cpuid)
+/*
+ * Bring one cpu online.
+ */
+static int __init
+smp_boot_one_cpu(int cpuid, int cpunum)
{
- struct percpu_struct *cpu;
- register char *cp1, *cp2;
- unsigned long cpumask;
- size_t len;
- int timeout;
-
- cpu = (struct percpu_struct *)
- ((char*)hwrpb
- + hwrpb->processor_offset
- + cpuid * hwrpb->processor_size);
-
- cpumask = (1L << cpuid);
- if (hwrpb->txrdy & cpumask)
- goto delay1;
- ready1:
-
- cp2 = str;
- len = strlen(cp2);
- *(unsigned int *)&cpu->ipc_buffer[0] = len;
- cp1 = (char *) &cpu->ipc_buffer[1];
- memcpy(cp1, cp2, len);
-
- /* atomic test and set */
- set_bit(cpuid, &hwrpb->rxrdy);
-
- if (hwrpb->txrdy & cpumask)
- goto delay2;
- ready2:
- return;
-
-delay1:
- for (timeout = 10000; timeout > 0; --timeout) {
- if (!(hwrpb->txrdy & cpumask))
- goto ready1;
- udelay(100);
+ struct task_struct *idle;
+ long timeout;
+
+ /* Cook up an idler for this guy. Note that the address we give
+ to kernel_thread is irrelevant -- it's going to start where
+ HWRPB.CPU_restart says to start. But this gets all the other
+ task-y sort of data structures set up like we wish. */
+ kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM);
+ idle = task[cpunum];
+ if (!idle)
+ panic("No idle process for CPU %d", cpuid);
+ idle->processor = cpuid;
+
+ /* Schedule the first task manually. */
+ /* ??? Ingo, what is this? */
+ idle->has_cpu = 1;
+
+ DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
+ cpuid, idle->state, idle->flags));
+
+ /* The secondary will change this once it is happy. Note that
+ secondary_cpu_start contains the necessary memory barrier. */
+ smp_secondary_alive = -1;
+
+ /* Whirrr, whirrr, whirrrrrrrrr... */
+ if (secondary_cpu_start(cpuid, idle))
+ return -1;
+
+ /* We've been acked by the console; wait one second for the task
+ to start up for real. Note that jiffies aren't ticking yet. */
+ for (timeout = 0; timeout < 100000; timeout++) {
+ if (smp_secondary_alive != -1)
+ goto alive;
+ udelay(10);
barrier();
}
- goto timeout;
-delay2:
- for (timeout = 10000; timeout > 0; --timeout) {
- if (!(hwrpb->txrdy & cpumask))
- goto ready2;
- udelay(100);
- barrier();
- }
- goto timeout;
+ printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
+ return -1;
-timeout:
- printk("Processor %x not ready\n", cpuid);
- return;
+alive:
+ /* Another "Red Snapper". */
+ cpu_number_map[cpuid] = cpunum;
+ __cpu_logical_map[cpunum] = cpuid;
+ return 0;
}
/*
- * setup_smp()
- *
- * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined
+ * Called from setup_arch. Detect an SMP system and which processors
+ * are present.
*/
void __init
setup_smp(void)
{
struct percpu_struct *cpubase, *cpu;
int i;
-
- boot_cpu_id = hard_smp_processor_id();
- if (boot_cpu_id != 0) {
- printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id);
+
+ smp_boot_cpuid = hard_smp_processor_id();
+ if (smp_boot_cpuid != 0) {
+ printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
+ smp_boot_cpuid);
}
if (hwrpb->nr_processors > 1) {
+ int boot_cpu_palrev;
DBGS(("setup_smp: nr_processors %ld\n",
hwrpb->nr_processors));
@@ -601,10 +471,9 @@ setup_smp(void)
((char *)cpubase + i*hwrpb->processor_size);
if ((cpu->flags & 0x1cc) == 0x1cc) {
smp_num_probed++;
- /* assume here that "whami" == index */
- cpu_present_map |= (1 << i);
- if (i != boot_cpu_id)
- cpu->pal_revision = boot_cpu_palrev;
+ /* Assume here that "whami" == index */
+ cpu_present_mask |= (1L << i);
+ cpu->pal_revision = boot_cpu_palrev;
}
DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
@@ -614,76 +483,249 @@ setup_smp(void)
}
} else {
smp_num_probed = 1;
- cpu_present_map = (1 << boot_cpu_id);
+ cpu_present_mask = (1L << smp_boot_cpuid);
}
- printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x,"
- " boot_cpu_id %d\n",
- smp_num_probed, cpu_present_map, boot_cpu_id);
+
+ printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
+ smp_num_probed, cpu_present_mask);
}
-static void
-secondary_console_message(void)
+/*
+ * Called by smp_init bring all the secondaries online and hold them.
+ */
+void __init
+smp_boot_cpus(void)
{
- int mycpu, i, cnt;
- unsigned long txrdy = hwrpb->txrdy;
- char *cp1, *cp2, buf[80];
- struct percpu_struct *cpu;
+ int cpu_count, i;
+ unsigned long bogosum;
- DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy));
+ /* Take care of some initial bookkeeping. */
+ memset(cpu_number_map, -1, sizeof(cpu_number_map));
+ memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map));
+ memset(ipi_data, 0, sizeof(ipi_data));
- mycpu = hard_smp_processor_id();
+ cpu_number_map[smp_boot_cpuid] = 0;
+ __cpu_logical_map[0] = smp_boot_cpuid;
+ current->processor = smp_boot_cpuid;
+
+ smp_store_cpu_info(smp_boot_cpuid);
+ smp_tune_scheduling();
+ smp_setup_percpu_timer(smp_boot_cpuid);
+
+ init_idle();
+ /* Nothing to do on a UP box, or when told not to. */
+ if (smp_num_probed == 1 || max_cpus == 0) {
+ printk(KERN_INFO "SMP mode deactivated.\n");
+ return;
+ }
+
+ printk(KERN_INFO "SMP starting up secondaries.\n");
+
+ cpu_count = 1;
for (i = 0; i < NR_CPUS; i++) {
- if (!(txrdy & (1L << i)))
+ if (i == smp_boot_cpuid)
continue;
- DBGS(("secondary_console_message: "
- "TXRDY contains CPU %d.\n", i));
+ if (((cpu_present_mask >> i) & 1) == 0)
+ continue;
- cpu = (struct percpu_struct *)
- ((char*)hwrpb
- + hwrpb->processor_offset
- + i * hwrpb->processor_size);
+ if (smp_boot_one_cpu(i, cpu_count))
+ continue;
- printk("secondary_console_message: on %d from %d"
- " HALT_REASON 0x%lx FLAGS 0x%lx\n",
- mycpu, i, cpu->halt_reason, cpu->flags);
+ cpu_count++;
+ }
- cnt = cpu->ipc_buffer[0] >> 32;
- if (cnt <= 0 || cnt >= 80)
- strcpy(buf, "<<< BOGUS MSG >>>");
- else {
- cp1 = (char *) &cpu->ipc_buffer[11];
- cp2 = buf;
- strcpy(cp2, cp1);
-
- while ((cp2 = strchr(cp2, '\r')) != 0) {
- *cp2 = ' ';
- if (cp2[1] == '\n')
- cp2[1] = ' ';
- }
- }
+ if (cpu_count == 1) {
+ printk(KERN_ERR "SMP: Only one lonely processor alive.\n");
+ return;
+ }
+
+ bogosum = 0;
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_present_mask & (1L << i))
+ bogosum += cpu_data[i].loops_per_sec;
+ }
+ printk(KERN_INFO "SMP: Total of %d processors activated "
+ "(%lu.%02lu BogoMIPS).\n",
+ cpu_count, (bogosum + 2500) / 500000,
+ ((bogosum + 2500) / 5000) % 100);
+
+ smp_num_cpus = cpu_count;
+}
+
+/*
+ * Called by smp_init to release the blocking online cpus once they
+ * are all started.
+ */
+void __init
+smp_commence(void)
+{
+ /* smp_init sets smp_threads_ready -- that's enough. */
+ mb();
+}
+
+/*
+ * Only broken Intel needs this, thus it should not even be
+ * referenced globally.
+ */
+
+void __init
+initialize_secondary(void)
+{
+}
+
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+ unsigned long user, unsigned long system,
+ int cpu);
- printk("secondary_console_message: on %d message is '%s'\n",
- mycpu, buf);
+void
+smp_percpu_timer_interrupt(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+ int user = user_mode(regs);
+ struct cpuinfo_alpha *data = &cpu_data[cpu];
+
+#ifdef NOT_YET_PROFILING
+ clear_profile_irq(mid_xlate[cpu]);
+ if (!user)
+ alpha_do_profile(regs->pc);
+#endif
+
+ if (!--data->prof_counter) {
+ /* We need to make like a normal interrupt -- otherwise
+ timer interrupts ignore the global interrupt lock,
+ which would be a Bad Thing. */
+ irq_enter(cpu, TIMER_IRQ);
+
+ update_one_process(current, 1, user, !user, cpu);
+ if (current->pid) {
+ if (--current->counter < 0) {
+ current->counter = 0;
+ current->need_resched = 1;
+ }
+
+ if (user) {
+ if (current->priority < DEF_PRIORITY) {
+ kstat.cpu_nice++;
+ kstat.per_cpu_nice[cpu]++;
+ } else {
+ kstat.cpu_user++;
+ kstat.per_cpu_user[cpu]++;
+ }
+ } else {
+ kstat.cpu_system++;
+ kstat.per_cpu_system[cpu]++;
+ }
+ }
+
+ data->prof_counter = data->prof_multiplier;
+ irq_exit(cpu, TIMER_IRQ);
}
+}
- hwrpb->txrdy = 0;
+int __init
+setup_profiling_timer(unsigned int multiplier)
+{
+#ifdef NOT_YET_PROFILING
+ int i;
+ unsigned long flags;
+
+ /* Prevent level14 ticker IRQ flooding. */
+ if((!multiplier) || (lvl14_resolution / multiplier) < 500)
+ return -EINVAL;
+
+ save_and_cli(flags);
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_present_mask & (1L << i)) {
+ load_profile_irq(mid_xlate[i],
+ lvl14_resolution / multiplier);
+ prof_multiplier[i] = multiplier;
+ }
+ }
+ restore_flags(flags);
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
}
-enum ipi_message_type {
- IPI_TLB_ALL,
- IPI_TLB_MM,
- IPI_TLB_PAGE,
- IPI_RESCHEDULE,
- IPI_CPU_STOP
+
+static void
+send_ipi_message(unsigned long to_whom, enum ipi_message_type operation)
+{
+ long i, j;
+
+ /* Reduce the number of memory barriers by doing two loops,
+ one to set the bits, one to invoke the interrupts. */
+
+ mb(); /* Order out-of-band data and bit setting. */
+
+ for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
+ if (to_whom & j)
+ set_bit(operation, &ipi_data[i].bits);
+ }
+
+ mb(); /* Order bit setting and interrupt. */
+
+ for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
+ if (to_whom & j)
+ wripir(i);
+ }
+}
+
+/* Structure and data for smp_call_function. This is designed to
+ minimize static memory requirements. Plus it looks cleaner. */
+
+struct smp_call_struct {
+ void (*func) (void *info);
+ void *info;
+ long wait;
+ atomic_t unstarted_count;
+ atomic_t unfinished_count;
};
+static struct smp_call_struct *smp_call_function_data;
+
+/* Atomicly drop data into a shared pointer. The pointer is free if
+ it is initially locked. If retry, spin until free. */
+
+static inline int
+pointer_lock (void *lock, void *data, int retry)
+{
+ void *old, *tmp;
+
+ mb();
+again:
+ /* Compare and swap with zero. */
+ asm volatile (
+ "1: ldq_l %0,%1\n"
+ " mov %3,%2\n"
+ " bne %0,2f\n"
+ " stq_c %2,%1\n"
+ " beq %2,1b\n"
+ "2:"
+ : "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp)
+ : "r"(data)
+ : "memory");
+
+ if (old == 0)
+ return 0;
+ if (! retry)
+ return -EBUSY;
+
+ while (*(void **)lock)
+ schedule();
+ goto again;
+}
+
void
handle_ipi(struct pt_regs *regs)
{
int this_cpu = smp_processor_id();
- volatile int * pending_ipis = &ipi_bits[this_cpu];
+ unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
unsigned long ops;
DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
@@ -699,190 +741,189 @@ handle_ipi(struct pt_regs *regs)
ops &= ~which;
which = ffz(~which);
- if (which < IPI_RESCHEDULE) {
- if (which == IPI_TLB_ALL)
- tbia();
- else if (which == IPI_TLB_MM) {
- struct mm_struct * mm;
- mm = ipi_msg_flush_tb.p.flush_mm;
- if (mm == current->mm)
- flush_tlb_current(mm);
- }
- else /* IPI_TLB_PAGE */ {
- struct vm_area_struct * vma;
- struct mm_struct * mm;
- unsigned long addr;
-
- vma = ipi_msg_flush_tb.p.flush_vma;
- mm = vma->vm_mm;
- addr = ipi_msg_flush_tb.flush_addr;
-
- if (mm == current->mm)
- flush_tlb_current_page(mm, vma, addr);
- }
- clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
- }
- else if (which == IPI_RESCHEDULE) {
+ if (which == IPI_RESCHEDULE) {
/* Reschedule callback. Everything to be done
is done by the interrupt return path. */
}
+ else if (which == IPI_CALL_FUNC) {
+ struct smp_call_struct *data;
+ void (*func)(void *info);
+ void *info;
+ int wait;
+
+ data = smp_call_function_data;
+ func = data->func;
+ info = data->info;
+ wait = data->wait;
+
+ /* Notify the sending CPU that the data has been
+ received, and execution is about to begin. */
+ mb();
+ atomic_dec (&data->unstarted_count);
+
+ /* At this point the structure may be gone unless
+ wait is true. */
+ (*func)(info);
+
+ /* Notify the sending CPU that the task is done. */
+ mb();
+ if (wait) atomic_dec (&data->unfinished_count);
+ }
else if (which == IPI_CPU_STOP) {
halt();
}
else {
- printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n",
+ printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
this_cpu, which);
}
} while (ops);
+
mb(); /* Order data access and bit testing. */
}
cpu_data[this_cpu].ipi_count++;
if (hwrpb->txrdy)
- secondary_console_message();
+ recv_secondary_console_msg();
}
-static void
-send_ipi_message(unsigned long to_whom, enum ipi_message_type operation)
+void
+smp_send_reschedule(int cpu)
{
- long i, j;
-
- /* Reduce the number of memory barriers by doing two loops,
- one to set the bits, one to invoke the interrupts. */
-
- mb(); /* Order out-of-band data and bit setting. */
-
- for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
- if (to_whom & j)
- set_bit(operation, &ipi_bits[i]);
- }
-
- mb(); /* Order bit setting and interrupt. */
+ send_ipi_message(1L << cpu, IPI_RESCHEDULE);
+}
- for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
- if (to_whom & j)
- wripir(i);
- }
+void
+smp_send_stop(void)
+{
+ unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+ send_ipi_message(to_whom, IPI_CPU_STOP);
}
+/*
+ * Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <retry> If true, keep retrying until ready.
+ * <wait> If true, wait until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or are or have executed.
+ */
+
int
-smp_info(char *buffer)
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
{
- long i;
- unsigned long sum = 0;
- for (i = 0; i < NR_CPUS; i++)
- sum += cpu_data[i].ipi_count;
+ unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+ struct smp_call_struct data;
+ long timeout;
+
+ data.func = func;
+ data.info = info;
+ data.wait = wait;
+ atomic_set(&data.unstarted_count, smp_num_cpus - 1);
+ atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+ /* Aquire the smp_call_function_data mutex. */
+ if (pointer_lock(&smp_call_function_data, &data, retry))
+ return -EBUSY;
+
+ /* Send a message to all other CPUs. */
+ send_ipi_message(to_whom, IPI_CALL_FUNC);
+
+ /* Wait for a minimal response. */
+ timeout = jiffies + HZ;
+ while (atomic_read (&data.unstarted_count) > 0
+ && time_before (jiffies, timeout))
+ barrier();
- return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n",
- smp_num_probed, smp_num_cpus, cpu_present_map, sum);
-}
+ /* We either got one or timed out -- clear the lock. */
+ mb();
+ smp_call_function_data = 0;
+ if (atomic_read (&data.unstarted_count) > 0)
+ return -ETIMEDOUT;
+
+ /* Wait for a complete response, if needed. */
+ if (wait) {
+ while (atomic_read (&data.unfinished_count) > 0)
+ barrier();
+ }
-void
-smp_send_reschedule(int cpu)
-{
- send_ipi_message(1 << cpu, IPI_RESCHEDULE);
+ return 0;
}
-void
-smp_send_stop(void)
+static void
+ipi_flush_tlb_all(void *ignored)
{
- unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
- send_ipi_message(to_whom, IPI_CPU_STOP);
+ tbia();
}
void
flush_tlb_all(void)
{
- unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
- long timeout = 1000000;
-
- spin_lock(&flush_tb_lock);
-
- ipi_msg_flush_tb.flush_tb_mask = to_whom;
- send_ipi_message(to_whom, IPI_TLB_ALL);
tbia();
- while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
- udelay(1);
- barrier();
- }
-
- if (timeout == 0) {
- printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
- smp_processor_id(),
- ipi_msg_flush_tb.flush_tb_mask);
- ipi_msg_flush_tb.flush_tb_mask = 0;
+ /* Although we don't have any data to pass, we do want to
+ synchronize with the other processors. */
+ if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) {
+ printk(KERN_CRIT "flush_tlb_all: timed out\n");
}
+}
- spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_mm(void *x)
+{
+ struct mm_struct *mm = (struct mm_struct *) x;
+ if (mm == current->mm)
+ flush_tlb_current(mm);
}
void
flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
- long timeout = 1000000;
-
- spin_lock(&flush_tb_lock);
-
- ipi_msg_flush_tb.flush_tb_mask = to_whom;
- ipi_msg_flush_tb.p.flush_mm = mm;
- send_ipi_message(to_whom, IPI_TLB_MM);
-
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
+ if (mm == current->mm)
flush_tlb_current(mm);
+ else
+ flush_tlb_other(mm);
- while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
- udelay(1);
- barrier();
+ if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
+ printk(KERN_CRIT "flush_tlb_mm: timed out\n");
}
+}
- if (timeout == 0) {
- printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n",
- smp_processor_id(),
- ipi_msg_flush_tb.flush_tb_mask);
- ipi_msg_flush_tb.flush_tb_mask = 0;
- }
+struct flush_tlb_page_struct {
+ struct vm_area_struct *vma;
+ struct mm_struct *mm;
+ unsigned long addr;
+};
- spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_page(void *x)
+{
+ struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
+ if (data->mm == current->mm)
+ flush_tlb_current_page(data->mm, data->vma, data->addr);
}
void
flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
{
- int cpu = smp_processor_id();
- unsigned long to_whom = cpu_present_map ^ (1 << cpu);
- struct mm_struct * mm = vma->vm_mm;
- int timeout = 1000000;
-
- spin_lock(&flush_tb_lock);
+ struct flush_tlb_page_struct data;
+ struct mm_struct *mm = vma->vm_mm;
- ipi_msg_flush_tb.flush_tb_mask = to_whom;
- ipi_msg_flush_tb.p.flush_vma = vma;
- ipi_msg_flush_tb.flush_addr = addr;
- send_ipi_message(to_whom, IPI_TLB_PAGE);
+ data.vma = vma;
+ data.mm = mm;
+ data.addr = addr;
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
+ if (mm == current->mm)
flush_tlb_current_page(mm, vma, addr);
-
- while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
- udelay(1);
- barrier();
- }
-
- if (timeout == 0) {
- printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n",
- smp_processor_id(),
- ipi_msg_flush_tb.flush_tb_mask);
- ipi_msg_flush_tb.flush_tb_mask = 0;
+ else
+ flush_tlb_other(mm);
+
+ if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) {
+ printk(KERN_CRIT "flush_tlb_page: timed out\n");
}
-
- spin_unlock(&flush_tb_lock);
}
void
@@ -892,6 +933,20 @@ flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
flush_tlb_mm(mm);
}
+
+int
+smp_info(char *buffer)
+{
+ long i;
+ unsigned long sum = 0;
+ for (i = 0; i < NR_CPUS; i++)
+ sum += cpu_data[i].ipi_count;
+
+ return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n",
+ smp_num_probed, smp_num_cpus, cpu_present_mask, sum);
+}
+
+
#if DEBUG_SPINLOCK
#ifdef MANAGE_SPINLOCK_IPL
@@ -932,17 +987,16 @@ void
spin_lock(spinlock_t * lock)
{
long tmp;
- long stuck = 1<<27;
+ long stuck;
void *inline_pc = __builtin_return_address(0);
unsigned long started = jiffies;
int printed = 0;
int cpu = smp_processor_id();
long old_ipl = spinlock_raise_ipl(lock);
+ stuck = 1L << 28;
try_again:
- stuck = 0x10000000; /* was 4G, now 256M */
-
/* Use sub-sections to put the actual loop at the end
of this object file's text section so as to perfect
branch prediction. */
@@ -961,19 +1015,16 @@ spin_lock(spinlock_t * lock)
" blbs %0,2b\n"
" br 1b\n"
".previous"
- : "=r" (tmp),
- "=m" (__dummy_lock(lock)),
- "=r" (stuck)
- : "2" (stuck));
+ : "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck)
+ : "1" (__dummy_lock(lock)), "2" (stuck));
if (stuck < 0) {
- if (!printed) {
- printk("spinlock stuck at %p(%d) owner %s at %p\n",
- inline_pc, cpu, lock->task->comm,
- lock->previous);
- printed = 1;
- }
- stuck = 1<<30;
+ printk(KERN_WARNING
+ "spinlock stuck at %p(%d) owner %s at %p(%d) st %ld\n",
+ inline_pc, cpu, lock->task->comm, lock->previous,
+ lock->task->processor, lock->task->state);
+ stuck = 1L << 36;
+ printed = 1;
goto try_again;
}
@@ -984,7 +1035,7 @@ spin_lock(spinlock_t * lock)
lock->task = current;
if (printed) {
- printk("spinlock grabbed at %p(%d) %ld ticks\n",
+ printk(KERN_WARNING "spinlock grabbed at %p(%d) %ld ticks\n",
inline_pc, cpu, jiffies - started);
}
}
@@ -1006,7 +1057,7 @@ spin_trylock(spinlock_t * lock)
return ret;
}
#endif /* DEBUG_SPINLOCK */
-
+
#if DEBUG_RWLOCK
void write_lock(rwlock_t * lock)
{
@@ -1038,18 +1089,17 @@ void write_lock(rwlock_t * lock)
" blt %1,8b\n"
" br 1b\n"
".previous"
- : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
- , "=&r" (stuck_lock), "=&r" (stuck_reader)
- : "0" (__dummy_lock(lock))
- , "3" (stuck_lock), "4" (stuck_reader)
- );
+ : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy),
+ "=&r" (stuck_lock), "=&r" (stuck_reader)
+ : "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader));
if (stuck_lock < 0) {
- printk("write_lock stuck at %p\n", inline_pc);
+ printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc);
goto try_again;
}
if (stuck_reader < 0) {
- printk("write_lock stuck on readers at %p\n", inline_pc);
+ printk(KERN_WARNING "write_lock stuck on readers at %p\n",
+ inline_pc);
goto try_again;
}
}
@@ -1079,11 +1129,10 @@ void read_lock(rwlock_t * lock)
" br 1b\n"
".previous"
: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock)
- : "0" (__dummy_lock(lock)), "2" (stuck_lock)
- );
+ : "0" (__dummy_lock(lock)), "2" (stuck_lock));
if (stuck_lock < 0) {
- printk("read_lock stuck at %p\n", inline_pc);
+ printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc);
goto try_again;
}
}
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index a84378926..927ca201f 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -42,6 +42,9 @@
#include "proto.h"
#include "irq.h"
+extern rwlock_t xtime_lock;
+extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
+
static int set_rtc_mmss(unsigned long);
@@ -86,15 +89,15 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
long nticks;
#ifdef __SMP__
- extern void smp_percpu_timer_interrupt(struct pt_regs *);
- extern unsigned int boot_cpu_id;
- /* when SMP, do this for *all* CPUs,
- but only do the rest for the boot CPU */
+ /* When SMP, do this for *all* CPUs, but only do the rest for
+ the boot CPU. */
smp_percpu_timer_interrupt(regs);
- if (smp_processor_id() != boot_cpu_id)
- return;
+ if (smp_processor_id() != smp_boot_cpuid)
+ return;
#endif
+ write_lock(&xtime_lock);
+
/*
* Calculate how many ticks have passed since the last update,
* including any previous partial leftover. Save any resulting
@@ -124,6 +127,8 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
int tmp = set_rtc_mmss(xtime.tv_sec);
state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0);
}
+
+ write_unlock(&xtime_lock);
}
/*
@@ -226,7 +231,8 @@ time_init(void)
{
void (*irq_handler)(int, void *, struct pt_regs *);
unsigned int year, mon, day, hour, min, sec, cc1, cc2;
- unsigned long cycle_freq, diff, one_percent;
+ unsigned long cycle_freq, one_percent;
+ long diff;
/*
* The Linux interpretation of the CMOS clock register contents:
@@ -242,7 +248,7 @@ time_init(void)
if (!est_cycle_freq) {
/* Sometimes the hwrpb->cycle_freq value is bogus.
- Go another round to check up on it and see. */
+ Go another round to check up on it and see. */
do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
cc2 = rpcc();
@@ -279,8 +285,7 @@ time_init(void)
mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR);
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- {
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
BCD_TO_BIN(hour);
@@ -328,18 +333,24 @@ time_init(void)
void
do_gettimeofday(struct timeval *tv)
{
- unsigned long flags, delta_cycles, delta_usec;
- unsigned long sec, usec;
- __u32 now;
- extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
+ unsigned long sec, usec, lost, flags;
+ unsigned long delta_cycles, delta_usec, partial_tick;
- now = rpcc();
- save_and_cli(flags);
+ read_lock_irqsave(&xtime_lock, flags);
+
+ delta_cycles = rpcc() - state.last_time;
sec = xtime.tv_sec;
usec = xtime.tv_usec;
- delta_cycles = now - state.last_time;
- restore_flags(flags);
+ partial_tick = state.partial_tick;
+ lost = lost_ticks;
+
+ read_unlock_irqrestore(&xtime_lock, flags);
+#ifdef __SMP__
+ /* Until and unless we figure out how to get cpu cycle counters
+ in sync and keep them there, we can't use the rpcc tricks. */
+ delta_usec = lost * (1000000 / HZ);
+#else
/*
* usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
* = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
@@ -354,13 +365,10 @@ do_gettimeofday(struct timeval *tv)
*/
delta_usec = (delta_cycles * state.scaled_ticks_per_cycle
- + state.partial_tick
- + (lost_ticks << FIX_SHIFT) ) * 15625;
+ + partial_tick
+ + (lost << FIX_SHIFT)) * 15625;
delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-
- /* the 'lost_tics' term above implements this:
- * delta_usec += lost_ticks * (1000000 / HZ);
- */
+#endif
usec += delta_usec;
if (usec >= 1000000) {
@@ -375,13 +383,41 @@ do_gettimeofday(struct timeval *tv)
void
do_settimeofday(struct timeval *tv)
{
- cli();
- xtime = *tv;
+ unsigned long delta_usec;
+ long sec, usec;
+
+ write_lock_irq(&xtime_lock);
+
+ /* The offset that is added into time in do_gettimeofday above
+ must be subtracted out here to keep a coherent view of the
+ time. Without this, a full-tick error is possible. */
+
+#ifdef __SMP__
+ delta_usec = lost_ticks * (1000000 / HZ);
+#else
+ delta_usec = rpcc() - state.last_time;
+ delta_usec = (delta_usec * state.scaled_ticks_per_cycle
+ + state.partial_tick
+ + (lost_ticks << FIX_SHIFT)) * 15625;
+ delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+#endif
+
+ sec = tv->tv_sec;
+ usec = tv->tv_usec;
+ usec -= delta_usec;
+ if (usec < 0) {
+ usec += 1000000;
+ sec -= 1;
+ }
+
+ xtime.tv_sec = sec;
+ xtime.tv_usec = usec;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
+
+ write_unlock_irq(&xtime_lock);
}
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 2548f0914..1b490b9c1 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -1,5 +1,5 @@
/*
- * kernel/traps.c
+ * arch/alpha/kernel/traps.c
*
* (C) Copyright 1994 Linus Torvalds
*/
@@ -95,6 +95,9 @@ die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
{
if (regs->ps & 8)
return;
+#ifdef __SMP__
+ printk("CPU %d ", hard_smp_processor_id());
+#endif
printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
dik_show_regs(regs, r9_15);
dik_show_code((unsigned int *)regs->pc);
@@ -128,8 +131,8 @@ do_entArith(unsigned long summary, unsigned long write_mask,
if (summary & 1) {
/* Software-completion summary bit is set, so try to
emulate the instruction. */
- if (implver() == IMPLVER_EV6) {
- /* Whee! EV6 has precice exceptions. */
+ if (!amask(AMASK_PRECISE_TRAP)) {
+ /* 21264 (except pass 1) has precise exceptions. */
if (alpha_fp_emul(regs.pc - 4))
return;
} else {
@@ -138,14 +141,12 @@ do_entArith(unsigned long summary, unsigned long write_mask,
}
}
- lock_kernel();
#if 0
printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
current->comm, regs.pc, summary, write_mask);
#endif
die_if_kernel("Arithmetic fault", &regs, 0, 0);
send_sig(SIGFPE, current, 1);
- unlock_kernel();
}
asmlinkage void
@@ -235,10 +236,8 @@ do_entDbg(unsigned long type, unsigned long a1,
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
- lock_kernel();
die_if_kernel("Instruction fault", &regs, type, 0);
force_sig(SIGILL, current);
- unlock_kernel();
}
@@ -453,10 +452,8 @@ got_exception:
unsigned long newpc;
newpc = fixup_exception(una_reg, fixup, pc);
- lock_kernel();
printk("Forwarding unaligned exception at %lx (%lx)\n",
pc, newpc);
- unlock_kernel();
(&regs)->pc = newpc;
return;
@@ -610,11 +607,9 @@ do_entUnaUser(void * va, unsigned long opcode,
cnt = 0;
}
if (++cnt < 5) {
- lock_kernel();
printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
current->comm, current->pid,
regs->pc - 4, va, opcode, reg);
- unlock_kernel();
}
last_time = jiffies;
}
@@ -868,16 +863,12 @@ do_entUnaUser(void * va, unsigned long opcode,
give_sigsegv:
regs->pc -= 4; /* make pc point to faulting insn */
- lock_kernel();
send_sig(SIGSEGV, current, 1);
- unlock_kernel();
return;
give_sigbus:
regs->pc -= 4;
- lock_kernel();
send_sig(SIGBUS, current, 1);
- unlock_kernel();
return;
}
diff --git a/arch/alpha/lib/memcpy.c b/arch/alpha/lib/memcpy.c
index dc708c73e..d715f0219 100644
--- a/arch/alpha/lib/memcpy.c
+++ b/arch/alpha/lib/memcpy.c
@@ -21,30 +21,44 @@
* This should be done in one go with ldq_u*2/mask/stq_u. Do it
* with a macro so that we can fix it up later..
*/
-#define ALIGN_DEST_TO8(d,s,n) \
+#define ALIGN_DEST_TO8_UP(d,s,n) \
while (d & 7) { \
if (n <= 0) return; \
n--; \
*(char *) d = *(char *) s; \
d++; s++; \
}
+#define ALIGN_DEST_TO8_DN(d,s,n) \
+ while (d & 7) { \
+ if (n <= 0) return; \
+ n--; \
+ d--; s--; \
+ *(char *) d = *(char *) s; \
+ }
/*
* This should similarly be done with ldq_u*2/mask/stq. The destination
* is aligned, but we don't fill in a full quad-word
*/
-#define DO_REST(d,s,n) \
+#define DO_REST_UP(d,s,n) \
while (n > 0) { \
n--; \
*(char *) d = *(char *) s; \
d++; s++; \
}
+#define DO_REST_DN(d,s,n) \
+ while (n > 0) { \
+ n--; \
+ d--; s--; \
+ *(char *) d = *(char *) s; \
+ }
/*
* This should be done with ldq/mask/stq. The source and destination are
* aligned, but we don't fill in a full quad-word
*/
-#define DO_REST_ALIGNED(d,s,n) DO_REST(d,s,n)
+#define DO_REST_ALIGNED_UP(d,s,n) DO_REST_UP(d,s,n)
+#define DO_REST_ALIGNED_DN(d,s,n) DO_REST_DN(d,s,n)
/*
* This does unaligned memory copies. We want to avoid storing to
@@ -53,9 +67,10 @@
*
* Note the ordering to try to avoid load (and address generation) latencies.
*/
-static inline void __memcpy_unaligned(unsigned long d, unsigned long s, long n)
+static inline void __memcpy_unaligned_up (unsigned long d, unsigned long s,
+ long n)
{
- ALIGN_DEST_TO8(d,s,n);
+ ALIGN_DEST_TO8_UP(d,s,n);
n -= 8; /* to avoid compare against 8 in the loop */
if (n >= 0) {
unsigned long low_word, high_word;
@@ -77,7 +92,17 @@ static inline void __memcpy_unaligned(unsigned long d, unsigned long s, long n)
} while (n >= 0);
}
n += 8;
- DO_REST(d,s,n);
+ DO_REST_UP(d,s,n);
+}
+
+static inline void __memcpy_unaligned_dn (unsigned long d, unsigned long s,
+ long n)
+{
+ /* I don't understand AXP assembler well enough for this. -Tim */
+ s += n;
+ d += n;
+ while (n--)
+ * (char *) --d = * (char *) --s;
}
/*
@@ -88,9 +113,10 @@ static inline void __memcpy_unaligned(unsigned long d, unsigned long s, long n)
*
* Note the ordering to try to avoid load (and address generation) latencies.
*/
-static inline void __memcpy_aligned(unsigned long d, unsigned long s, long n)
+static inline void __memcpy_aligned_up (unsigned long d, unsigned long s,
+ long n)
{
- ALIGN_DEST_TO8(d,s,n);
+ ALIGN_DEST_TO8_UP(d,s,n);
n -= 8;
while (n >= 0) {
unsigned long tmp;
@@ -101,18 +127,58 @@ static inline void __memcpy_aligned(unsigned long d, unsigned long s, long n)
d += 8;
}
n += 8;
- DO_REST_ALIGNED(d,s,n);
+ DO_REST_ALIGNED_UP(d,s,n);
+}
+static inline void __memcpy_aligned_dn (unsigned long d, unsigned long s,
+ long n)
+{
+ s += n;
+ d += n;
+ ALIGN_DEST_TO8_DN(d,s,n);
+ n -= 8;
+ while (n >= 0) {
+ unsigned long tmp;
+ s -= 8;
+ __asm__("ldq %0,%1":"=r" (tmp):"m" (*(unsigned long *) s));
+ n -= 8;
+ d -= 8;
+ *(unsigned long *) d = tmp;
+ }
+ n += 8;
+ DO_REST_ALIGNED_DN(d,s,n);
}
void * memcpy(void * dest, const void *src, size_t n)
{
if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) {
- __memcpy_aligned((unsigned long) dest, (unsigned long) src, n);
+ __memcpy_aligned_up ((unsigned long) dest, (unsigned long) src,
+ n);
return dest;
}
- __memcpy_unaligned((unsigned long) dest, (unsigned long) src, n);
+ __memcpy_unaligned_up ((unsigned long) dest, (unsigned long) src, n);
return dest;
}
/* For backward modules compatibility, define __memcpy. */
asm("__memcpy = memcpy; .globl __memcpy");
+
+void *memmove (void *dest, const void *src, size_t n)
+{
+ if (dest <= src) {
+ if (!(((unsigned long) dest ^ (unsigned long) src) & 7))
+ __memcpy_aligned_up ((unsigned long) dest,
+ (unsigned long) src, n);
+ else
+ __memcpy_unaligned_up ((unsigned long) dest,
+ (unsigned long) src, n);
+ }
+ else {
+ if (!(((unsigned long) dest ^ (unsigned long) src) & 7))
+ __memcpy_aligned_dn ((unsigned long) dest,
+ (unsigned long) src, n);
+ else
+ __memcpy_unaligned_dn ((unsigned long) dest,
+ (unsigned long) src, n);
+ }
+ return dest;
+}
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 2e67deb8a..fc5a964bb 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -256,26 +256,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
return start_mem;
}
-#ifdef __SMP__
-/*
- * paging_init_secondary(), called ONLY by secondary CPUs,
- * sets up current->tss contents appropriately and does a load_PCB.
- * note that current should be pointing at the idle thread task struct
- * for this CPU.
- */
-void
-paging_init_secondary(void)
-{
- current->tss.ptbr = init_task.tss.ptbr;
- current->tss.pal_flags = 1;
- current->tss.flags = 0;
- load_PCB(&current->tss);
- tbia();
-
- return;
-}
-#endif /* __SMP__ */
-
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
void
srm_paging_stop (void)