diff options
Diffstat (limited to 'arch/blackfin/kernel/cplb-mpu/cplbmgr.c')
-rw-r--r-- | arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 128 |
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 | ||
251 | static noinline int dcplb_protection_fault(void) | 287 | static 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 | ||