diff options
Diffstat (limited to 'arch/blackfin/kernel/cplb-nompu/cplbmgr.c')
-rw-r--r-- | arch/blackfin/kernel/cplb-nompu/cplbmgr.c | 54 |
1 files changed, 3 insertions, 51 deletions
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbmgr.c b/arch/blackfin/kernel/cplb-nompu/cplbmgr.c index 8cbb47c7b663..12b030842fdb 100644 --- a/arch/blackfin/kernel/cplb-nompu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-nompu/cplbmgr.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/cplbinit.h> | 28 | #include <asm/cplbinit.h> |
29 | #include <asm/cplb.h> | 29 | #include <asm/cplb.h> |
30 | #include <asm/mmu_context.h> | 30 | #include <asm/mmu_context.h> |
31 | #include <asm/traps.h> | ||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * WARNING | 34 | * WARNING |
@@ -100,28 +101,6 @@ static inline void write_icplb_data(int cpu, int idx, unsigned long data, | |||
100 | #endif | 101 | #endif |
101 | } | 102 | } |
102 | 103 | ||
103 | /* | ||
104 | * Given the contents of the status register, return the index of the | ||
105 | * CPLB that caused the fault. | ||
106 | */ | ||
107 | static inline int faulting_cplb_index(int status) | ||
108 | { | ||
109 | int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF); | ||
110 | return 30 - signbits; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * Given the contents of the status register and the DCPLB_DATA contents, | ||
115 | * return true if a write access should be permitted. | ||
116 | */ | ||
117 | static inline int write_permitted(int status, unsigned long data) | ||
118 | { | ||
119 | if (status & FAULT_USERSUPV) | ||
120 | return !!(data & CPLB_SUPV_WR); | ||
121 | else | ||
122 | return !!(data & CPLB_USER_WR); | ||
123 | } | ||
124 | |||
125 | /* Counters to implement round-robin replacement. */ | 104 | /* Counters to implement round-robin replacement. */ |
126 | static int icplb_rr_index[NR_CPUS] PDT_ATTR; | 105 | static int icplb_rr_index[NR_CPUS] PDT_ATTR; |
127 | static int dcplb_rr_index[NR_CPUS] PDT_ATTR; | 106 | static int dcplb_rr_index[NR_CPUS] PDT_ATTR; |
@@ -245,43 +224,16 @@ MGR_ATTR static int dcplb_miss(int cpu) | |||
245 | return CPLB_RELOADED; | 224 | return CPLB_RELOADED; |
246 | } | 225 | } |
247 | 226 | ||
248 | MGR_ATTR static noinline int dcplb_protection_fault(int cpu) | ||
249 | { | ||
250 | int status = bfin_read_DCPLB_STATUS(); | ||
251 | |||
252 | nr_dcplb_prot[cpu]++; | ||
253 | |||
254 | if (likely(status & FAULT_RW)) { | ||
255 | int idx = faulting_cplb_index(status); | ||
256 | unsigned long regaddr = DCPLB_DATA0 + idx * 4; | ||
257 | unsigned long data = bfin_read32(regaddr); | ||
258 | |||
259 | /* Check if fault is to dirty a clean page */ | ||
260 | if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) && | ||
261 | write_permitted(status, data)) { | ||
262 | |||
263 | dcplb_tbl[cpu][idx].data = data; | ||
264 | bfin_write32(regaddr, data); | ||
265 | return CPLB_RELOADED; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | return CPLB_PROT_VIOL; | ||
270 | } | ||
271 | |||
272 | MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs) | 227 | MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs) |
273 | { | 228 | { |
274 | int cause = seqstat & 0x3f; | 229 | int cause = seqstat & 0x3f; |
275 | unsigned int cpu = smp_processor_id(); | 230 | unsigned int cpu = smp_processor_id(); |
276 | switch (cause) { | 231 | switch (cause) { |
277 | case 0x2C: | 232 | case VEC_CPLB_I_M: |
278 | return icplb_miss(cpu); | 233 | return icplb_miss(cpu); |
279 | case 0x26: | 234 | case VEC_CPLB_M: |
280 | return dcplb_miss(cpu); | 235 | return dcplb_miss(cpu); |
281 | default: | 236 | default: |
282 | if (unlikely(cause == 0x23)) | ||
283 | return dcplb_protection_fault(cpu); | ||
284 | |||
285 | return CPLB_UNKNOWN_ERR; | 237 | return CPLB_UNKNOWN_ERR; |
286 | } | 238 | } |
287 | } | 239 | } |