-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ARM: SMP: split out software TLB maintainence broadcasting
smp.c is becoming too large, so split out the TLB maintainence broadcasting into a separate smp_tlb.c file. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
- Loading branch information
Russell King
committed
Dec 20, 2010
1 parent
10034aa
commit 03b505e
Showing
3 changed files
with
140 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* linux/arch/arm/kernel/smp_tlb.c | ||
* | ||
* Copyright (C) 2002 ARM Limited, All Rights Reserved. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
#include <linux/preempt.h> | ||
#include <linux/smp.h> | ||
|
||
#include <asm/smp_plat.h> | ||
#include <asm/tlbflush.h> | ||
|
||
static void on_each_cpu_mask(void (*func)(void *), void *info, int wait, | ||
const struct cpumask *mask) | ||
{ | ||
preempt_disable(); | ||
|
||
smp_call_function_many(mask, func, info, wait); | ||
if (cpumask_test_cpu(smp_processor_id(), mask)) | ||
func(info); | ||
|
||
preempt_enable(); | ||
} | ||
|
||
/**********************************************************************/ | ||
|
||
/* | ||
* TLB operations | ||
*/ | ||
struct tlb_args { | ||
struct vm_area_struct *ta_vma; | ||
unsigned long ta_start; | ||
unsigned long ta_end; | ||
}; | ||
|
||
static inline void ipi_flush_tlb_all(void *ignored) | ||
{ | ||
local_flush_tlb_all(); | ||
} | ||
|
||
static inline void ipi_flush_tlb_mm(void *arg) | ||
{ | ||
struct mm_struct *mm = (struct mm_struct *)arg; | ||
|
||
local_flush_tlb_mm(mm); | ||
} | ||
|
||
static inline void ipi_flush_tlb_page(void *arg) | ||
{ | ||
struct tlb_args *ta = (struct tlb_args *)arg; | ||
|
||
local_flush_tlb_page(ta->ta_vma, ta->ta_start); | ||
} | ||
|
||
static inline void ipi_flush_tlb_kernel_page(void *arg) | ||
{ | ||
struct tlb_args *ta = (struct tlb_args *)arg; | ||
|
||
local_flush_tlb_kernel_page(ta->ta_start); | ||
} | ||
|
||
static inline void ipi_flush_tlb_range(void *arg) | ||
{ | ||
struct tlb_args *ta = (struct tlb_args *)arg; | ||
|
||
local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); | ||
} | ||
|
||
static inline void ipi_flush_tlb_kernel_range(void *arg) | ||
{ | ||
struct tlb_args *ta = (struct tlb_args *)arg; | ||
|
||
local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); | ||
} | ||
|
||
void flush_tlb_all(void) | ||
{ | ||
if (tlb_ops_need_broadcast()) | ||
on_each_cpu(ipi_flush_tlb_all, NULL, 1); | ||
else | ||
local_flush_tlb_all(); | ||
} | ||
|
||
void flush_tlb_mm(struct mm_struct *mm) | ||
{ | ||
if (tlb_ops_need_broadcast()) | ||
on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); | ||
else | ||
local_flush_tlb_mm(mm); | ||
} | ||
|
||
void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | ||
{ | ||
if (tlb_ops_need_broadcast()) { | ||
struct tlb_args ta; | ||
ta.ta_vma = vma; | ||
ta.ta_start = uaddr; | ||
on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); | ||
} else | ||
local_flush_tlb_page(vma, uaddr); | ||
} | ||
|
||
void flush_tlb_kernel_page(unsigned long kaddr) | ||
{ | ||
if (tlb_ops_need_broadcast()) { | ||
struct tlb_args ta; | ||
ta.ta_start = kaddr; | ||
on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | ||
} else | ||
local_flush_tlb_kernel_page(kaddr); | ||
} | ||
|
||
void flush_tlb_range(struct vm_area_struct *vma, | ||
unsigned long start, unsigned long end) | ||
{ | ||
if (tlb_ops_need_broadcast()) { | ||
struct tlb_args ta; | ||
ta.ta_vma = vma; | ||
ta.ta_start = start; | ||
ta.ta_end = end; | ||
on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); | ||
} else | ||
local_flush_tlb_range(vma, start, end); | ||
} | ||
|
||
void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
{ | ||
if (tlb_ops_need_broadcast()) { | ||
struct tlb_args ta; | ||
ta.ta_start = start; | ||
ta.ta_end = end; | ||
on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | ||
} else | ||
local_flush_tlb_kernel_range(start, end); | ||
} | ||
|