summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/kernel/smp.c')
-rw-r--r--arch/alpha/kernel/smp.c63
1 files changed, 49 insertions, 14 deletions
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index dd882dc14..94a3872c3 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -106,8 +106,9 @@ static inline void __init
smp_store_cpu_info(int cpuid)
{
cpu_data[cpuid].loops_per_sec = loops_per_sec;
- cpu_data[cpuid].last_asn
- = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION;
+ cpu_data[cpuid].last_asn = ASN_FIRST_VERSION;
+ cpu_data[cpuid].need_new_asn = 0;
+ cpu_data[cpuid].asn_lock = 0;
local_irq_count(cpuid) = 0;
local_bh_count(cpuid) = 0;
}
@@ -898,12 +899,16 @@ flush_tlb_all(void)
tbia();
}
+#define asn_locked() (cpu_data[smp_processor_id()].asn_lock)
+
static void
ipi_flush_tlb_mm(void *x)
{
struct mm_struct *mm = (struct mm_struct *) x;
- if (mm == current->active_mm)
+ if (mm == current->active_mm && !asn_locked())
flush_tlb_current(mm);
+ else
+ flush_tlb_other(mm);
}
void
@@ -911,10 +916,18 @@ flush_tlb_mm(struct mm_struct *mm)
{
if (mm == current->active_mm) {
flush_tlb_current(mm);
- if (atomic_read(&mm->mm_users) <= 1)
+ if (atomic_read(&mm->mm_users) <= 1) {
+ int i, cpu, this_cpu = smp_processor_id();
+ for (i = 0; i < smp_num_cpus; i++) {
+ cpu = cpu_logical_map(i);
+ if (cpu == this_cpu)
+ continue;
+ if (mm->context[cpu])
+ mm->context[cpu] = 0;
+ }
return;
- } else
- flush_tlb_other(mm);
+ }
+ }
if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
printk(KERN_CRIT "flush_tlb_mm: timed out\n");
@@ -931,8 +944,12 @@ static void
ipi_flush_tlb_page(void *x)
{
struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
- if (data->mm == current->active_mm)
- flush_tlb_current_page(data->mm, data->vma, data->addr);
+ struct mm_struct * mm = data->mm;
+
+ if (mm == current->active_mm && !asn_locked())
+ flush_tlb_current_page(mm, data->vma, data->addr);
+ else
+ flush_tlb_other(mm);
}
void
@@ -943,10 +960,18 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
if (mm == current->active_mm) {
flush_tlb_current_page(mm, vma, addr);
- if (atomic_read(&mm->mm_users) <= 1)
+ if (atomic_read(&mm->mm_users) <= 1) {
+ int i, cpu, this_cpu = smp_processor_id();
+ for (i = 0; i < smp_num_cpus; i++) {
+ cpu = cpu_logical_map(i);
+ if (cpu == this_cpu)
+ continue;
+ if (mm->context[cpu])
+ mm->context[cpu] = 0;
+ }
return;
- } else
- flush_tlb_other(mm);
+ }
+ }
data.vma = vma;
data.mm = mm;
@@ -968,8 +993,10 @@ static void
ipi_flush_icache_page(void *x)
{
struct mm_struct *mm = (struct mm_struct *) x;
- if (mm == current->active_mm)
+ if (mm == current->active_mm && !asn_locked())
__load_new_mm_context(mm);
+ else
+ flush_tlb_other(mm);
}
void
@@ -980,11 +1007,19 @@ flush_icache_page(struct vm_area_struct *vma, struct page *page)
if ((vma->vm_flags & VM_EXEC) == 0)
return;
- mm->context = 0;
if (mm == current->active_mm) {
__load_new_mm_context(mm);
- if (atomic_read(&mm->mm_users) <= 1)
+ if (atomic_read(&mm->mm_users) <= 1) {
+ int i, cpu, this_cpu = smp_processor_id();
+ for (i = 0; i < smp_num_cpus; i++) {
+ cpu = cpu_logical_map(i);
+ if (cpu == this_cpu)
+ continue;
+ if (mm->context[cpu])
+ mm->context[cpu] = 0;
+ }
return;
+ }
}
if (smp_call_function(ipi_flush_icache_page, mm, 1, 1)) {