aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/cplb-mpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/cplb-mpu')
-rw-r--r--arch/blackfin/kernel/cplb-mpu/Makefile6
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cacheinit.c4
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbinfo.c136
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbinit.c48
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c119
5 files changed, 96 insertions, 217 deletions
diff --git a/arch/blackfin/kernel/cplb-mpu/Makefile b/arch/blackfin/kernel/cplb-mpu/Makefile
index 286b69357f97..7d70d3bf3212 100644
--- a/arch/blackfin/kernel/cplb-mpu/Makefile
+++ b/arch/blackfin/kernel/cplb-mpu/Makefile
@@ -4,5 +4,7 @@
4 4
5obj-y := cplbinit.o cacheinit.o cplbmgr.o 5obj-y := cplbinit.o cacheinit.o cplbmgr.o
6 6
7obj-$(CONFIG_CPLB_INFO) += cplbinfo.o 7CFLAGS_cplbmgr.o := -ffixed-I0 -ffixed-I1 -ffixed-I2 -ffixed-I3 \
8 8 -ffixed-L0 -ffixed-L1 -ffixed-L2 -ffixed-L3 \
9 -ffixed-M0 -ffixed-M1 -ffixed-M2 -ffixed-M3 \
10 -ffixed-B0 -ffixed-B1 -ffixed-B2 -ffixed-B3
diff --git a/arch/blackfin/kernel/cplb-mpu/cacheinit.c b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
index a8b712a24c59..c6ff947f9d37 100644
--- a/arch/blackfin/kernel/cplb-mpu/cacheinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
@@ -25,7 +25,7 @@
25#include <asm/cplbinit.h> 25#include <asm/cplbinit.h>
26 26
27#if defined(CONFIG_BFIN_ICACHE) 27#if defined(CONFIG_BFIN_ICACHE)
28void __init bfin_icache_init(void) 28void __cpuinit bfin_icache_init(struct cplb_entry *icplb_tbl)
29{ 29{
30 unsigned long ctrl; 30 unsigned long ctrl;
31 int i; 31 int i;
@@ -43,7 +43,7 @@ void __init bfin_icache_init(void)
43#endif 43#endif
44 44
45#if defined(CONFIG_BFIN_DCACHE) 45#if defined(CONFIG_BFIN_DCACHE)
46void __init bfin_dcache_init(void) 46void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl)
47{ 47{
48 unsigned long ctrl; 48 unsigned long ctrl;
49 int i; 49 int i;
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
deleted file mode 100644
index 822beefa3a4b..000000000000
--- a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
+++ /dev/null
@@ -1,136 +0,0 @@
1/*
2 * File: arch/blackfin/mach-common/cplbinfo.c
3 * Based on:
4 * Author: Sonic Zhang <sonic.zhang@analog.com>
5 *
6 * Created: Jan. 2005
7 * Description: Display CPLB status
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/init.h>
33#include <linux/proc_fs.h>
34#include <linux/uaccess.h>
35
36#include <asm/current.h>
37#include <asm/system.h>
38#include <asm/cplb.h>
39#include <asm/cplbinit.h>
40#include <asm/blackfin.h>
41
42static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
43
44static char *cplb_print_entry(char *buf, struct cplb_entry *tbl, int switched)
45{
46 int i;
47 buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n");
48 for (i = 0; i < MAX_CPLBS; i++) {
49 unsigned long data = tbl[i].data;
50 unsigned long addr = tbl[i].addr;
51 if (!(data & CPLB_VALID))
52 continue;
53
54 buf +=
55 sprintf(buf,
56 "%d\t0x%08lx\t%06lx\t%s\t%c\t%c\t%c\t%c\n",
57 i, addr, data,
58 page_size_string_table[(data & 0x30000) >> 16],
59 (data & CPLB_USER_RD) ? 'Y' : 'N',
60 (data & CPLB_USER_WR) ? 'Y' : 'N',
61 (data & CPLB_SUPV_WR) ? 'Y' : 'N',
62 i < switched ? 'N' : 'Y');
63 }
64 buf += sprintf(buf, "\n");
65
66 return buf;
67}
68
69int cplbinfo_proc_output(char *buf)
70{
71 char *p;
72
73 p = buf;
74
75 p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
76
77 if (bfin_read_IMEM_CONTROL() & ENICPLB) {
78 p += sprintf(p, "Instruction CPLB entry:\n");
79 p = cplb_print_entry(p, icplb_tbl, first_switched_icplb);
80 } else
81 p += sprintf(p, "Instruction CPLB is disabled.\n\n");
82
83 if (1 || bfin_read_DMEM_CONTROL() & ENDCPLB) {
84 p += sprintf(p, "Data CPLB entry:\n");
85 p = cplb_print_entry(p, dcplb_tbl, first_switched_dcplb);
86 } else
87 p += sprintf(p, "Data CPLB is disabled.\n");
88
89 p += sprintf(p, "ICPLB miss: %d\nICPLB supervisor miss: %d\n",
90 nr_icplb_miss, nr_icplb_supv_miss);
91 p += sprintf(p, "DCPLB miss: %d\nDCPLB protection fault:%d\n",
92 nr_dcplb_miss, nr_dcplb_prot);
93 p += sprintf(p, "CPLB flushes: %d\n",
94 nr_cplb_flush);
95
96 return p - buf;
97}
98
99static int cplbinfo_read_proc(char *page, char **start, off_t off,
100 int count, int *eof, void *data)
101{
102 int len;
103
104 len = cplbinfo_proc_output(page);
105 if (len <= off + count)
106 *eof = 1;
107 *start = page + off;
108 len -= off;
109 if (len > count)
110 len = count;
111 if (len < 0)
112 len = 0;
113 return len;
114}
115
116static int __init cplbinfo_init(void)
117{
118 struct proc_dir_entry *entry;
119
120 entry = create_proc_entry("cplbinfo", 0, NULL);
121 if (!entry)
122 return -ENOMEM;
123
124 entry->read_proc = cplbinfo_read_proc;
125 entry->data = NULL;
126
127 return 0;
128}
129
130static void __exit cplbinfo_exit(void)
131{
132 remove_proc_entry("cplbinfo", NULL);
133}
134
135module_init(cplbinfo_init);
136module_exit(cplbinfo_exit);
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
index 55af729f8495..bdb958486e76 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -25,18 +25,19 @@
25#include <asm/blackfin.h> 25#include <asm/blackfin.h>
26#include <asm/cplb.h> 26#include <asm/cplb.h>
27#include <asm/cplbinit.h> 27#include <asm/cplbinit.h>
28#include <asm/mem_map.h>
28 29
29#if ANOMALY_05000263 30#if ANOMALY_05000263
30# error the MPU will not function safely while Anomaly 05000263 applies 31# error the MPU will not function safely while Anomaly 05000263 applies
31#endif 32#endif
32 33
33struct cplb_entry icplb_tbl[MAX_CPLBS]; 34struct cplb_entry icplb_tbl[NR_CPUS][MAX_CPLBS];
34struct cplb_entry dcplb_tbl[MAX_CPLBS]; 35struct cplb_entry dcplb_tbl[NR_CPUS][MAX_CPLBS];
35 36
36int first_switched_icplb, first_switched_dcplb; 37int first_switched_icplb, first_switched_dcplb;
37int first_mask_dcplb; 38int first_mask_dcplb;
38 39
39void __init generate_cplb_tables(void) 40void __init generate_cplb_tables_cpu(unsigned int cpu)
40{ 41{
41 int i_d, i_i; 42 int i_d, i_i;
42 unsigned long addr; 43 unsigned long addr;
@@ -55,15 +56,16 @@ void __init generate_cplb_tables(void)
55 d_cache |= CPLB_L1_AOW | CPLB_WT; 56 d_cache |= CPLB_L1_AOW | CPLB_WT;
56#endif 57#endif
57#endif 58#endif
59
58 i_d = i_i = 0; 60 i_d = i_i = 0;
59 61
60 /* Set up the zero page. */ 62 /* Set up the zero page. */
61 dcplb_tbl[i_d].addr = 0; 63 dcplb_tbl[cpu][i_d].addr = 0;
62 dcplb_tbl[i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB; 64 dcplb_tbl[cpu][i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB;
63 65
64#if 0 66#if 0
65 icplb_tbl[i_i].addr = 0; 67 icplb_tbl[cpu][i_i].addr = 0;
66 icplb_tbl[i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB; 68 icplb_tbl[cpu][i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB;
67#endif 69#endif
68 70
69 /* Cover kernel memory with 4M pages. */ 71 /* Cover kernel memory with 4M pages. */
@@ -72,28 +74,28 @@ void __init generate_cplb_tables(void)
72 i_data = i_cache | CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4MB; 74 i_data = i_cache | CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4MB;
73 75
74 for (; addr < memory_start; addr += 4 * 1024 * 1024) { 76 for (; addr < memory_start; addr += 4 * 1024 * 1024) {
75 dcplb_tbl[i_d].addr = addr; 77 dcplb_tbl[cpu][i_d].addr = addr;
76 dcplb_tbl[i_d++].data = d_data; 78 dcplb_tbl[cpu][i_d++].data = d_data;
77 icplb_tbl[i_i].addr = addr; 79 icplb_tbl[cpu][i_i].addr = addr;
78 icplb_tbl[i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0); 80 icplb_tbl[cpu][i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0);
79 } 81 }
80 82
81 /* Cover L1 memory. One 4M area for code and data each is enough. */ 83 /* Cover L1 memory. One 4M area for code and data each is enough. */
82#if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0 84#if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0
83 dcplb_tbl[i_d].addr = L1_DATA_A_START; 85 dcplb_tbl[cpu][i_d].addr = get_l1_data_a_start_cpu(cpu);
84 dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB; 86 dcplb_tbl[cpu][i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
85#endif 87#endif
86#if L1_CODE_LENGTH > 0 88#if L1_CODE_LENGTH > 0
87 icplb_tbl[i_i].addr = L1_CODE_START; 89 icplb_tbl[cpu][i_i].addr = get_l1_code_start_cpu(cpu);
88 icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB; 90 icplb_tbl[cpu][i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
89#endif 91#endif
90 92
91 /* Cover L2 memory */ 93 /* Cover L2 memory */
92#if L2_LENGTH > 0 94#if L2_LENGTH > 0
93 dcplb_tbl[i_d].addr = L2_START; 95 dcplb_tbl[cpu][i_d].addr = L2_START;
94 dcplb_tbl[i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB; 96 dcplb_tbl[cpu][i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB;
95 icplb_tbl[i_i].addr = L2_START; 97 icplb_tbl[cpu][i_i].addr = L2_START;
96 icplb_tbl[i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB; 98 icplb_tbl[cpu][i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB;
97#endif 99#endif
98 100
99 first_mask_dcplb = i_d; 101 first_mask_dcplb = i_d;
@@ -101,7 +103,11 @@ void __init generate_cplb_tables(void)
101 first_switched_icplb = i_i; 103 first_switched_icplb = i_i;
102 104
103 while (i_d < MAX_CPLBS) 105 while (i_d < MAX_CPLBS)
104 dcplb_tbl[i_d++].data = 0; 106 dcplb_tbl[cpu][i_d++].data = 0;
105 while (i_i < MAX_CPLBS) 107 while (i_i < MAX_CPLBS)
106 icplb_tbl[i_i++].data = 0; 108 icplb_tbl[cpu][i_i++].data = 0;
109}
110
111void generate_cplb_tables_all(void)
112{
107} 113}
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index baa52e261f0d..87463ce87f5a 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -25,15 +25,21 @@
25#include <asm/cplbinit.h> 25#include <asm/cplbinit.h>
26#include <asm/mmu_context.h> 26#include <asm/mmu_context.h>
27 27
28#define FAULT_RW (1 << 16) 28/*
29#define FAULT_USERSUPV (1 << 17) 29 * WARNING
30 *
31 * This file is compiled with certain -ffixed-reg options. We have to
32 * make sure not to call any functions here that could clobber these
33 * registers.
34 */
30 35
31int page_mask_nelts; 36int page_mask_nelts;
32int page_mask_order; 37int page_mask_order;
33unsigned long *current_rwx_mask; 38unsigned long *current_rwx_mask[NR_CPUS];
34 39
35int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot; 40int nr_dcplb_miss[NR_CPUS], nr_icplb_miss[NR_CPUS];
36int nr_cplb_flush; 41int nr_icplb_supv_miss[NR_CPUS], nr_dcplb_prot[NR_CPUS];
42int nr_cplb_flush[NR_CPUS];
37 43
38static inline void disable_dcplb(void) 44static inline void disable_dcplb(void)
39{ 45{
@@ -98,42 +104,42 @@ static inline int write_permitted(int status, unsigned long data)
98} 104}
99 105
100/* Counters to implement round-robin replacement. */ 106/* Counters to implement round-robin replacement. */
101static int icplb_rr_index, dcplb_rr_index; 107static int icplb_rr_index[NR_CPUS], dcplb_rr_index[NR_CPUS];
102 108
103/* 109/*
104 * Find an ICPLB entry to be evicted and return its index. 110 * Find an ICPLB entry to be evicted and return its index.
105 */ 111 */
106static int evict_one_icplb(void) 112static int evict_one_icplb(unsigned int cpu)
107{ 113{
108 int i; 114 int i;
109 for (i = first_switched_icplb; i < MAX_CPLBS; i++) 115 for (i = first_switched_icplb; i < MAX_CPLBS; i++)
110 if ((icplb_tbl[i].data & CPLB_VALID) == 0) 116 if ((icplb_tbl[cpu][i].data & CPLB_VALID) == 0)
111 return i; 117 return i;
112 i = first_switched_icplb + icplb_rr_index; 118 i = first_switched_icplb + icplb_rr_index[cpu];
113 if (i >= MAX_CPLBS) { 119 if (i >= MAX_CPLBS) {
114 i -= MAX_CPLBS - first_switched_icplb; 120 i -= MAX_CPLBS - first_switched_icplb;
115 icplb_rr_index -= MAX_CPLBS - first_switched_icplb; 121 icplb_rr_index[cpu] -= MAX_CPLBS - first_switched_icplb;
116 } 122 }
117 icplb_rr_index++; 123 icplb_rr_index[cpu]++;
118 return i; 124 return i;
119} 125}
120 126
121static int evict_one_dcplb(void) 127static int evict_one_dcplb(unsigned int cpu)
122{ 128{
123 int i; 129 int i;
124 for (i = first_switched_dcplb; i < MAX_CPLBS; i++) 130 for (i = first_switched_dcplb; i < MAX_CPLBS; i++)
125 if ((dcplb_tbl[i].data & CPLB_VALID) == 0) 131 if ((dcplb_tbl[cpu][i].data & CPLB_VALID) == 0)
126 return i; 132 return i;
127 i = first_switched_dcplb + dcplb_rr_index; 133 i = first_switched_dcplb + dcplb_rr_index[cpu];
128 if (i >= MAX_CPLBS) { 134 if (i >= MAX_CPLBS) {
129 i -= MAX_CPLBS - first_switched_dcplb; 135 i -= MAX_CPLBS - first_switched_dcplb;
130 dcplb_rr_index -= MAX_CPLBS - first_switched_dcplb; 136 dcplb_rr_index[cpu] -= MAX_CPLBS - first_switched_dcplb;
131 } 137 }
132 dcplb_rr_index++; 138 dcplb_rr_index[cpu]++;
133 return i; 139 return i;
134} 140}
135 141
136static noinline int dcplb_miss(void) 142static noinline int dcplb_miss(unsigned int cpu)
137{ 143{
138 unsigned long addr = bfin_read_DCPLB_FAULT_ADDR(); 144 unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
139 int status = bfin_read_DCPLB_STATUS(); 145 int status = bfin_read_DCPLB_STATUS();
@@ -141,7 +147,7 @@ static noinline int dcplb_miss(void)
141 int idx; 147 int idx;
142 unsigned long d_data; 148 unsigned long d_data;
143 149
144 nr_dcplb_miss++; 150 nr_dcplb_miss[cpu]++;
145 151
146 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; 152 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
147#ifdef CONFIG_BFIN_DCACHE 153#ifdef CONFIG_BFIN_DCACHE
@@ -168,25 +174,25 @@ static noinline int dcplb_miss(void)
168 } else if (addr >= _ramend) { 174 } else if (addr >= _ramend) {
169 d_data |= CPLB_USER_RD | CPLB_USER_WR; 175 d_data |= CPLB_USER_RD | CPLB_USER_WR;
170 } else { 176 } else {
171 mask = current_rwx_mask; 177 mask = current_rwx_mask[cpu];
172 if (mask) { 178 if (mask) {
173 int page = addr >> PAGE_SHIFT; 179 int page = addr >> PAGE_SHIFT;
174 int offs = page >> 5; 180 int idx = page >> 5;
175 int bit = 1 << (page & 31); 181 int bit = 1 << (page & 31);
176 182
177 if (mask[offs] & bit) 183 if (mask[idx] & bit)
178 d_data |= CPLB_USER_RD; 184 d_data |= CPLB_USER_RD;
179 185
180 mask += page_mask_nelts; 186 mask += page_mask_nelts;
181 if (mask[offs] & bit) 187 if (mask[idx] & bit)
182 d_data |= CPLB_USER_WR; 188 d_data |= CPLB_USER_WR;
183 } 189 }
184 } 190 }
185 idx = evict_one_dcplb(); 191 idx = evict_one_dcplb(cpu);
186 192
187 addr &= PAGE_MASK; 193 addr &= PAGE_MASK;
188 dcplb_tbl[idx].addr = addr; 194 dcplb_tbl[cpu][idx].addr = addr;
189 dcplb_tbl[idx].data = d_data; 195 dcplb_tbl[cpu][idx].data = d_data;
190 196
191 disable_dcplb(); 197 disable_dcplb();
192 bfin_write32(DCPLB_DATA0 + idx * 4, d_data); 198 bfin_write32(DCPLB_DATA0 + idx * 4, d_data);
@@ -196,21 +202,21 @@ static noinline int dcplb_miss(void)
196 return 0; 202 return 0;
197} 203}
198 204
199static noinline int icplb_miss(void) 205static noinline int icplb_miss(unsigned int cpu)
200{ 206{
201 unsigned long addr = bfin_read_ICPLB_FAULT_ADDR(); 207 unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
202 int status = bfin_read_ICPLB_STATUS(); 208 int status = bfin_read_ICPLB_STATUS();
203 int idx; 209 int idx;
204 unsigned long i_data; 210 unsigned long i_data;
205 211
206 nr_icplb_miss++; 212 nr_icplb_miss[cpu]++;
207 213
208 /* If inside the uncached DMA region, fault. */ 214 /* If inside the uncached DMA region, fault. */
209 if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend) 215 if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend)
210 return CPLB_PROT_VIOL; 216 return CPLB_PROT_VIOL;
211 217
212 if (status & FAULT_USERSUPV) 218 if (status & FAULT_USERSUPV)
213 nr_icplb_supv_miss++; 219 nr_icplb_supv_miss[cpu]++;
214 220
215 /* 221 /*
216 * First, try to find a CPLB that matches this address. If we 222 * First, try to find a CPLB that matches this address. If we
@@ -218,8 +224,8 @@ static noinline int icplb_miss(void)
218 * that the instruction crosses a page boundary. 224 * that the instruction crosses a page boundary.
219 */ 225 */
220 for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) { 226 for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) {
221 if (icplb_tbl[idx].data & CPLB_VALID) { 227 if (icplb_tbl[cpu][idx].data & CPLB_VALID) {
222 unsigned long this_addr = icplb_tbl[idx].addr; 228 unsigned long this_addr = icplb_tbl[cpu][idx].addr;
223 if (this_addr <= addr && this_addr + PAGE_SIZE > addr) { 229 if (this_addr <= addr && this_addr + PAGE_SIZE > addr) {
224 addr += PAGE_SIZE; 230 addr += PAGE_SIZE;
225 break; 231 break;
@@ -257,23 +263,23 @@ static noinline int icplb_miss(void)
257 * Otherwise, check the x bitmap of the current process. 263 * Otherwise, check the x bitmap of the current process.
258 */ 264 */
259 if (!(status & FAULT_USERSUPV)) { 265 if (!(status & FAULT_USERSUPV)) {
260 unsigned long *mask = current_rwx_mask; 266 unsigned long *mask = current_rwx_mask[cpu];
261 267
262 if (mask) { 268 if (mask) {
263 int page = addr >> PAGE_SHIFT; 269 int page = addr >> PAGE_SHIFT;
264 int offs = page >> 5; 270 int idx = page >> 5;
265 int bit = 1 << (page & 31); 271 int bit = 1 << (page & 31);
266 272
267 mask += 2 * page_mask_nelts; 273 mask += 2 * page_mask_nelts;
268 if (mask[offs] & bit) 274 if (mask[idx] & bit)
269 i_data |= CPLB_USER_RD; 275 i_data |= CPLB_USER_RD;
270 } 276 }
271 } 277 }
272 } 278 }
273 idx = evict_one_icplb(); 279 idx = evict_one_icplb(cpu);
274 addr &= PAGE_MASK; 280 addr &= PAGE_MASK;
275 icplb_tbl[idx].addr = addr; 281 icplb_tbl[cpu][idx].addr = addr;
276 icplb_tbl[idx].data = i_data; 282 icplb_tbl[cpu][idx].data = i_data;
277 283
278 disable_icplb(); 284 disable_icplb();
279 bfin_write32(ICPLB_DATA0 + idx * 4, i_data); 285 bfin_write32(ICPLB_DATA0 + idx * 4, i_data);
@@ -283,19 +289,19 @@ static noinline int icplb_miss(void)
283 return 0; 289 return 0;
284} 290}
285 291
286static noinline int dcplb_protection_fault(void) 292static noinline int dcplb_protection_fault(unsigned int cpu)
287{ 293{
288 int status = bfin_read_DCPLB_STATUS(); 294 int status = bfin_read_DCPLB_STATUS();
289 295
290 nr_dcplb_prot++; 296 nr_dcplb_prot[cpu]++;
291 297
292 if (status & FAULT_RW) { 298 if (status & FAULT_RW) {
293 int idx = faulting_cplb_index(status); 299 int idx = faulting_cplb_index(status);
294 unsigned long data = dcplb_tbl[idx].data; 300 unsigned long data = dcplb_tbl[cpu][idx].data;
295 if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) && 301 if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
296 write_permitted(status, data)) { 302 write_permitted(status, data)) {
297 data |= CPLB_DIRTY; 303 data |= CPLB_DIRTY;
298 dcplb_tbl[idx].data = data; 304 dcplb_tbl[cpu][idx].data = data;
299 bfin_write32(DCPLB_DATA0 + idx * 4, data); 305 bfin_write32(DCPLB_DATA0 + idx * 4, data);
300 return 0; 306 return 0;
301 } 307 }
@@ -306,44 +312,45 @@ static noinline int dcplb_protection_fault(void)
306int cplb_hdr(int seqstat, struct pt_regs *regs) 312int cplb_hdr(int seqstat, struct pt_regs *regs)
307{ 313{
308 int cause = seqstat & 0x3f; 314 int cause = seqstat & 0x3f;
315 unsigned int cpu = smp_processor_id();
309 switch (cause) { 316 switch (cause) {
310 case 0x23: 317 case 0x23:
311 return dcplb_protection_fault(); 318 return dcplb_protection_fault(cpu);
312 case 0x2C: 319 case 0x2C:
313 return icplb_miss(); 320 return icplb_miss(cpu);
314 case 0x26: 321 case 0x26:
315 return dcplb_miss(); 322 return dcplb_miss(cpu);
316 default: 323 default:
317 return 1; 324 return 1;
318 } 325 }
319} 326}
320 327
321void flush_switched_cplbs(void) 328void flush_switched_cplbs(unsigned int cpu)
322{ 329{
323 int i; 330 int i;
324 unsigned long flags; 331 unsigned long flags;
325 332
326 nr_cplb_flush++; 333 nr_cplb_flush[cpu]++;
327 334
328 local_irq_save(flags); 335 local_irq_save_hw(flags);
329 disable_icplb(); 336 disable_icplb();
330 for (i = first_switched_icplb; i < MAX_CPLBS; i++) { 337 for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
331 icplb_tbl[i].data = 0; 338 icplb_tbl[cpu][i].data = 0;
332 bfin_write32(ICPLB_DATA0 + i * 4, 0); 339 bfin_write32(ICPLB_DATA0 + i * 4, 0);
333 } 340 }
334 enable_icplb(); 341 enable_icplb();
335 342
336 disable_dcplb(); 343 disable_dcplb();
337 for (i = first_switched_dcplb; i < MAX_CPLBS; i++) { 344 for (i = first_switched_dcplb; i < MAX_CPLBS; i++) {
338 dcplb_tbl[i].data = 0; 345 dcplb_tbl[cpu][i].data = 0;
339 bfin_write32(DCPLB_DATA0 + i * 4, 0); 346 bfin_write32(DCPLB_DATA0 + i * 4, 0);
340 } 347 }
341 enable_dcplb(); 348 enable_dcplb();
342 local_irq_restore(flags); 349 local_irq_restore_hw(flags);
343 350
344} 351}
345 352
346void set_mask_dcplbs(unsigned long *masks) 353void set_mask_dcplbs(unsigned long *masks, unsigned int cpu)
347{ 354{
348 int i; 355 int i;
349 unsigned long addr = (unsigned long)masks; 356 unsigned long addr = (unsigned long)masks;
@@ -351,12 +358,12 @@ void set_mask_dcplbs(unsigned long *masks)
351 unsigned long flags; 358 unsigned long flags;
352 359
353 if (!masks) { 360 if (!masks) {
354 current_rwx_mask = masks; 361 current_rwx_mask[cpu] = masks;
355 return; 362 return;
356 } 363 }
357 364
358 local_irq_save(flags); 365 local_irq_save_hw(flags);
359 current_rwx_mask = masks; 366 current_rwx_mask[cpu] = masks;
360 367
361 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; 368 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
362#ifdef CONFIG_BFIN_DCACHE 369#ifdef CONFIG_BFIN_DCACHE
@@ -368,12 +375,12 @@ void set_mask_dcplbs(unsigned long *masks)
368 375
369 disable_dcplb(); 376 disable_dcplb();
370 for (i = first_mask_dcplb; i < first_switched_dcplb; i++) { 377 for (i = first_mask_dcplb; i < first_switched_dcplb; i++) {
371 dcplb_tbl[i].addr = addr; 378 dcplb_tbl[cpu][i].addr = addr;
372 dcplb_tbl[i].data = d_data; 379 dcplb_tbl[cpu][i].data = d_data;
373 bfin_write32(DCPLB_DATA0 + i * 4, d_data); 380 bfin_write32(DCPLB_DATA0 + i * 4, d_data);
374 bfin_write32(DCPLB_ADDR0 + i * 4, addr); 381 bfin_write32(DCPLB_ADDR0 + i * 4, addr);
375 addr += PAGE_SIZE; 382 addr += PAGE_SIZE;
376 } 383 }
377 enable_dcplb(); 384 enable_dcplb();
378 local_irq_restore(flags); 385 local_irq_restore_hw(flags);
379} 386}