aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/cplb-mpu/cplbmgr.c')
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c128
1 files changed, 80 insertions, 48 deletions
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index c426a22f9907..99f2831e2964 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -24,8 +24,6 @@
24#include <asm/cplbinit.h> 24#include <asm/cplbinit.h>
25#include <asm/mmu_context.h> 25#include <asm/mmu_context.h>
26 26
27#ifdef CONFIG_BFIN_ICACHE
28
29#define FAULT_RW (1 << 16) 27#define FAULT_RW (1 << 16)
30#define FAULT_USERSUPV (1 << 17) 28#define FAULT_USERSUPV (1 << 17)
31 29
@@ -143,30 +141,48 @@ static noinline int dcplb_miss(void)
143 unsigned long d_data; 141 unsigned long d_data;
144 142
145 nr_dcplb_miss++; 143 nr_dcplb_miss++;
146 if (addr >= _ramend)
147 return CPLB_PROT_VIOL;
148 144
149 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; 145 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
150#ifdef CONFIG_BFIN_DCACHE 146#ifdef CONFIG_BFIN_DCACHE
151 d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND; 147 if (addr < _ramend - DMA_UNCACHED_REGION ||
152#ifdef CONFIG_BLKFIN_WT 148 (reserved_mem_dcache_on && addr >= _ramend &&
153 d_data |= CPLB_L1_AOW | CPLB_WT; 149 addr < physical_mem_end)) {
154#endif 150 d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
151#ifdef CONFIG_BFIN_WT
152 d_data |= CPLB_L1_AOW | CPLB_WT;
155#endif 153#endif
156 mask = current_rwx_mask;
157 if (mask) {
158 int page = addr >> PAGE_SHIFT;
159 int offs = page >> 5;
160 int bit = 1 << (page & 31);
161
162 if (mask[offs] & bit)
163 d_data |= CPLB_USER_RD;
164
165 mask += page_mask_nelts;
166 if (mask[offs] & bit)
167 d_data |= CPLB_USER_WR;
168 } 154 }
155#endif
156 if (addr >= physical_mem_end) {
157 if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE
158 && (status & FAULT_USERSUPV)) {
159 addr &= ~0x3fffff;
160 d_data &= ~PAGE_SIZE_4KB;
161 d_data |= PAGE_SIZE_4MB;
162 } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
163 && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) {
164 addr &= ~(1 * 1024 * 1024 - 1);
165 d_data &= ~PAGE_SIZE_4KB;
166 d_data |= PAGE_SIZE_1MB;
167 } else
168 return CPLB_PROT_VIOL;
169 } else if (addr >= _ramend) {
170 d_data |= CPLB_USER_RD | CPLB_USER_WR;
171 } else {
172 mask = current_rwx_mask;
173 if (mask) {
174 int page = addr >> PAGE_SHIFT;
175 int offs = page >> 5;
176 int bit = 1 << (page & 31);
177
178 if (mask[offs] & bit)
179 d_data |= CPLB_USER_RD;
169 180
181 mask += page_mask_nelts;
182 if (mask[offs] & bit)
183 d_data |= CPLB_USER_WR;
184 }
185 }
170 idx = evict_one_dcplb(); 186 idx = evict_one_dcplb();
171 187
172 addr &= PAGE_MASK; 188 addr &= PAGE_MASK;
@@ -189,12 +205,14 @@ static noinline int icplb_miss(void)
189 unsigned long i_data; 205 unsigned long i_data;
190 206
191 nr_icplb_miss++; 207 nr_icplb_miss++;
192 if (status & FAULT_USERSUPV)
193 nr_icplb_supv_miss++;
194 208
195 if (addr >= _ramend) 209 /* If inside the uncached DMA region, fault. */
210 if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend)
196 return CPLB_PROT_VIOL; 211 return CPLB_PROT_VIOL;
197 212
213 if (status & FAULT_USERSUPV)
214 nr_icplb_supv_miss++;
215
198 /* 216 /*
199 * First, try to find a CPLB that matches this address. If we 217 * First, try to find a CPLB that matches this address. If we
200 * find one, then the fact that we're in the miss handler means 218 * find one, then the fact that we're in the miss handler means
@@ -211,30 +229,48 @@ static noinline int icplb_miss(void)
211 } 229 }
212 230
213 i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB; 231 i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB;
214#ifdef CONFIG_BFIN_ICACHE
215 i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
216#endif
217 232
233#ifdef CONFIG_BFIN_ICACHE
218 /* 234 /*
219 * Two cases to distinguish - a supervisor access must necessarily 235 * Normal RAM, and possibly the reserved memory area, are
220 * be for a module page; we grant it unconditionally (could do better 236 * cacheable.
221 * here in the future). Otherwise, check the x bitmap of the current
222 * process.
223 */ 237 */
224 if (!(status & FAULT_USERSUPV)) { 238 if (addr < _ramend ||
225 unsigned long *mask = current_rwx_mask; 239 (addr < physical_mem_end && reserved_mem_icache_on))
226 240 i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
227 if (mask) { 241#endif
228 int page = addr >> PAGE_SHIFT;
229 int offs = page >> 5;
230 int bit = 1 << (page & 31);
231 242
232 mask += 2 * page_mask_nelts; 243 if (addr >= physical_mem_end) {
233 if (mask[offs] & bit) 244 if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
234 i_data |= CPLB_USER_RD; 245 && (status & FAULT_USERSUPV)) {
246 addr &= ~(1 * 1024 * 1024 - 1);
247 i_data &= ~PAGE_SIZE_4KB;
248 i_data |= PAGE_SIZE_1MB;
249 } else
250 return CPLB_PROT_VIOL;
251 } else if (addr >= _ramend) {
252 i_data |= CPLB_USER_RD;
253 } else {
254 /*
255 * Two cases to distinguish - a supervisor access must
256 * necessarily be for a module page; we grant it
257 * unconditionally (could do better here in the future).
258 * Otherwise, check the x bitmap of the current process.
259 */
260 if (!(status & FAULT_USERSUPV)) {
261 unsigned long *mask = current_rwx_mask;
262
263 if (mask) {
264 int page = addr >> PAGE_SHIFT;
265 int offs = page >> 5;
266 int bit = 1 << (page & 31);
267
268 mask += 2 * page_mask_nelts;
269 if (mask[offs] & bit)
270 i_data |= CPLB_USER_RD;
271 }
235 } 272 }
236 } 273 }
237
238 idx = evict_one_icplb(); 274 idx = evict_one_icplb();
239 addr &= PAGE_MASK; 275 addr &= PAGE_MASK;
240 icplb_tbl[idx].addr = addr; 276 icplb_tbl[idx].addr = addr;
@@ -250,7 +286,6 @@ static noinline int icplb_miss(void)
250 286
251static noinline int dcplb_protection_fault(void) 287static noinline int dcplb_protection_fault(void)
252{ 288{
253 unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
254 int status = bfin_read_DCPLB_STATUS(); 289 int status = bfin_read_DCPLB_STATUS();
255 290
256 nr_dcplb_prot++; 291 nr_dcplb_prot++;
@@ -280,8 +315,7 @@ int cplb_hdr(int seqstat, struct pt_regs *regs)
280 case 0x26: 315 case 0x26:
281 return dcplb_miss(); 316 return dcplb_miss();
282 default: 317 default:
283 return 1; 318 return 1;
284 panic_cplb_error(seqstat, regs);
285 } 319 }
286} 320}
287 321
@@ -299,7 +333,7 @@ void flush_switched_cplbs(void)
299 enable_icplb(); 333 enable_icplb();
300 334
301 disable_dcplb(); 335 disable_dcplb();
302 for (i = first_mask_dcplb; i < MAX_CPLBS; i++) { 336 for (i = first_switched_dcplb; i < MAX_CPLBS; i++) {
303 dcplb_tbl[i].data = 0; 337 dcplb_tbl[i].data = 0;
304 bfin_write32(DCPLB_DATA0 + i * 4, 0); 338 bfin_write32(DCPLB_DATA0 + i * 4, 0);
305 } 339 }
@@ -319,7 +353,7 @@ void set_mask_dcplbs(unsigned long *masks)
319 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; 353 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
320#ifdef CONFIG_BFIN_DCACHE 354#ifdef CONFIG_BFIN_DCACHE
321 d_data |= CPLB_L1_CHBL; 355 d_data |= CPLB_L1_CHBL;
322#ifdef CONFIG_BLKFIN_WT 356#ifdef CONFIG_BFIN_WT
323 d_data |= CPLB_L1_AOW | CPLB_WT; 357 d_data |= CPLB_L1_AOW | CPLB_WT;
324#endif 358#endif
325#endif 359#endif
@@ -334,5 +368,3 @@ void set_mask_dcplbs(unsigned long *masks)
334 } 368 }
335 enable_dcplb(); 369 enable_dcplb();
336} 370}
337
338#endif