1 |
1276 |
phoenix |
/* asm-generic/tlb.h
|
2 |
|
|
*
|
3 |
|
|
* Generic TLB shootdown code
|
4 |
|
|
*
|
5 |
|
|
* Copyright 2001 Red Hat, Inc.
|
6 |
|
|
* Based on code from mm/memory.c Copyright Linus Torvalds and others.
|
7 |
|
|
*
|
8 |
|
|
* This program is free software; you can redistribute it and/or
|
9 |
|
|
* modify it under the terms of the GNU General Public License
|
10 |
|
|
* as published by the Free Software Foundation; either version
|
11 |
|
|
* 2 of the License, or (at your option) any later version.
|
12 |
|
|
*/
|
13 |
|
|
#ifndef _ASM_GENERIC__TLB_H
|
14 |
|
|
#define _ASM_GENERIC__TLB_H
|
15 |
|
|
|
16 |
|
|
#include <linux/config.h>
|
17 |
|
|
|
18 |
|
|
#ifdef CONFIG_SMP
|
19 |
|
|
/* aim for something that fits in the L1 cache */
|
20 |
|
|
#define FREE_PTE_NR 508
|
21 |
|
|
|
22 |
|
|
/* mmu_gather_t is an opaque type used by the mm code for passing around any
|
23 |
|
|
* data needed by arch specific code for tlb_remove_page. This structure can
|
24 |
|
|
* be per-CPU or per-MM as the page table lock is held for the duration of TLB
|
25 |
|
|
* shootdown.
|
26 |
|
|
*/
|
27 |
|
|
typedef struct free_pte_ctx {
|
28 |
|
|
struct mm_struct *mm;
|
29 |
|
|
unsigned long nr; /* set to ~0UL means fast mode */
|
30 |
|
|
unsigned long start_addr, end_addr;
|
31 |
|
|
pte_t ptes[FREE_PTE_NR];
|
32 |
|
|
} mmu_gather_t;
|
33 |
|
|
|
34 |
|
|
/* Users of the generic TLB shootdown code must declare this storage space. */
|
35 |
|
|
extern mmu_gather_t mmu_gathers[NR_CPUS];
|
36 |
|
|
|
37 |
|
|
/* tlb_gather_mmu
|
38 |
|
|
* Return a pointer to an initialized mmu_gather_t.
|
39 |
|
|
*/
|
40 |
|
|
static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm)
|
41 |
|
|
{
|
42 |
|
|
mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()];
|
43 |
|
|
|
44 |
|
|
tlb->mm = mm;
|
45 |
|
|
/* Use fast mode if there is only one user of this mm (this process) */
|
46 |
|
|
tlb->nr = (atomic_read(&(mm)->mm_users) == 1) ? ~0UL : 0UL;
|
47 |
|
|
return tlb;
|
48 |
|
|
}
|
49 |
|
|
|
50 |
|
|
/* void tlb_remove_page(mmu_gather_t *tlb, pte_t *ptep, unsigned long addr)
|
51 |
|
|
* Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
|
52 |
|
|
* handling the additional races in SMP caused by other CPUs caching valid
|
53 |
|
|
* mappings in their TLBs.
|
54 |
|
|
*/
|
55 |
|
|
#define tlb_remove_page(ctxp, pte, addr) do {\
|
56 |
|
|
/* Handle the common case fast, first. */\
|
57 |
|
|
if ((ctxp)->nr == ~0UL) {\
|
58 |
|
|
pte_t __pte = *(pte);\
|
59 |
|
|
pte_clear(pte);\
|
60 |
|
|
__free_pte(__pte);\
|
61 |
|
|
break;\
|
62 |
|
|
}\
|
63 |
|
|
if (!(ctxp)->nr) \
|
64 |
|
|
(ctxp)->start_addr = (addr);\
|
65 |
|
|
(ctxp)->ptes[(ctxp)->nr++] = ptep_get_and_clear(pte);\
|
66 |
|
|
(ctxp)->end_addr = (addr) + PAGE_SIZE;\
|
67 |
|
|
if ((ctxp)->nr >= FREE_PTE_NR)\
|
68 |
|
|
tlb_finish_mmu((ctxp), 0, 0);\
|
69 |
|
|
} while (0)
|
70 |
|
|
|
71 |
|
|
/* tlb_finish_mmu
|
72 |
|
|
* Called at the end of the shootdown operation to free up any resources
|
73 |
|
|
* that were required. The page talbe lock is still held at this point.
|
74 |
|
|
*/
|
75 |
|
|
static inline void tlb_finish_mmu(struct free_pte_ctx *ctx, unsigned long start, unsigned long end)
|
76 |
|
|
{
|
77 |
|
|
unsigned long i, nr;
|
78 |
|
|
|
79 |
|
|
/* Handle the fast case first. */
|
80 |
|
|
if (ctx->nr == ~0UL) {
|
81 |
|
|
flush_tlb_range(ctx->mm, start, end);
|
82 |
|
|
return;
|
83 |
|
|
}
|
84 |
|
|
nr = ctx->nr;
|
85 |
|
|
ctx->nr = 0;
|
86 |
|
|
if (nr)
|
87 |
|
|
flush_tlb_range(ctx->mm, ctx->start_addr, ctx->end_addr);
|
88 |
|
|
for (i=0; i < nr; i++) {
|
89 |
|
|
pte_t pte = ctx->ptes[i];
|
90 |
|
|
__free_pte(pte);
|
91 |
|
|
}
|
92 |
|
|
}
|
93 |
|
|
|
94 |
|
|
#else
|
95 |
|
|
|
96 |
|
|
/* The uniprocessor functions are quite simple and are inline macros in an
|
97 |
|
|
* attempt to get gcc to generate optimal code since this code is run on each
|
98 |
|
|
* page in a process at exit.
|
99 |
|
|
*/
|
100 |
|
|
typedef struct mm_struct mmu_gather_t;
|
101 |
|
|
|
102 |
|
|
#define tlb_gather_mmu(mm) (mm)
|
103 |
|
|
#define tlb_finish_mmu(tlb, start, end) flush_tlb_range(tlb, start, end)
|
104 |
|
|
#define tlb_remove_page(tlb, ptep, addr) do {\
|
105 |
|
|
pte_t __pte = *(ptep);\
|
106 |
|
|
pte_clear(ptep);\
|
107 |
|
|
__free_pte(__pte);\
|
108 |
|
|
} while (0)
|
109 |
|
|
|
110 |
|
|
#endif
|
111 |
|
|
|
112 |
|
|
|
113 |
|
|
#endif /* _ASM_GENERIC__TLB_H */
|
114 |
|
|
|