aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
diff options
context:
space:
mode:
authorGraf Yang <graf.yang@analog.com>2008-11-18 04:48:22 -0500
committerBryan Wu <cooloney@kernel.org>2008-11-18 04:48:22 -0500
commitb8a989893cbdeb6c97a7b5af5f38fb0e480235f9 (patch)
tree658cf6df93dac687f0d6b94111d0f53b3dd0177c /arch/blackfin/kernel/cplb-mpu/cplbmgr.c
parent6b3087c64a92a36ae20d33479b4df6d7afc910d4 (diff)
Blackfin arch: SMP supporting patchset: Blackfin CPLB related code
Blackfin dual core BF561 processor can support SMP like features. https://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:smp-like In this patch, we provide SMP extend to Blackfin CPLB related code Signed-off-by: Graf Yang <graf.yang@analog.com> Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin/kernel/cplb-mpu/cplbmgr.c')
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c102
1 files changed, 52 insertions, 50 deletions
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index baa52e261f0d..76bd99177de5 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -30,10 +30,11 @@
30 30
31int page_mask_nelts; 31int page_mask_nelts;
32int page_mask_order; 32int page_mask_order;
33unsigned long *current_rwx_mask; 33unsigned long *current_rwx_mask[NR_CPUS];
34 34
35int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot; 35int nr_dcplb_miss[NR_CPUS], nr_icplb_miss[NR_CPUS];
36int nr_cplb_flush; 36int nr_icplb_supv_miss[NR_CPUS], nr_dcplb_prot[NR_CPUS];
37int nr_cplb_flush[NR_CPUS];
37 38
38static inline void disable_dcplb(void) 39static inline void disable_dcplb(void)
39{ 40{
@@ -98,42 +99,42 @@ static inline int write_permitted(int status, unsigned long data)
98} 99}
99 100
100/* Counters to implement round-robin replacement. */ 101/* Counters to implement round-robin replacement. */
101static int icplb_rr_index, dcplb_rr_index; 102static int icplb_rr_index[NR_CPUS], dcplb_rr_index[NR_CPUS];
102 103
103/* 104/*
104 * Find an ICPLB entry to be evicted and return its index. 105 * Find an ICPLB entry to be evicted and return its index.
105 */ 106 */
106static int evict_one_icplb(void) 107static int evict_one_icplb(unsigned int cpu)
107{ 108{
108 int i; 109 int i;
109 for (i = first_switched_icplb; i < MAX_CPLBS; i++) 110 for (i = first_switched_icplb; i < MAX_CPLBS; i++)
110 if ((icplb_tbl[i].data & CPLB_VALID) == 0) 111 if ((icplb_tbl[cpu][i].data & CPLB_VALID) == 0)
111 return i; 112 return i;
112 i = first_switched_icplb + icplb_rr_index; 113 i = first_switched_icplb + icplb_rr_index[cpu];
113 if (i >= MAX_CPLBS) { 114 if (i >= MAX_CPLBS) {
114 i -= MAX_CPLBS - first_switched_icplb; 115 i -= MAX_CPLBS - first_switched_icplb;
115 icplb_rr_index -= MAX_CPLBS - first_switched_icplb; 116 icplb_rr_index[cpu] -= MAX_CPLBS - first_switched_icplb;
116 } 117 }
117 icplb_rr_index++; 118 icplb_rr_index[cpu]++;
118 return i; 119 return i;
119} 120}
120 121
121static int evict_one_dcplb(void) 122static int evict_one_dcplb(unsigned int cpu)
122{ 123{
123 int i; 124 int i;
124 for (i = first_switched_dcplb; i < MAX_CPLBS; i++) 125 for (i = first_switched_dcplb; i < MAX_CPLBS; i++)
125 if ((dcplb_tbl[i].data & CPLB_VALID) == 0) 126 if ((dcplb_tbl[cpu][i].data & CPLB_VALID) == 0)
126 return i; 127 return i;
127 i = first_switched_dcplb + dcplb_rr_index; 128 i = first_switched_dcplb + dcplb_rr_index[cpu];
128 if (i >= MAX_CPLBS) { 129 if (i >= MAX_CPLBS) {
129 i -= MAX_CPLBS - first_switched_dcplb; 130 i -= MAX_CPLBS - first_switched_dcplb;
130 dcplb_rr_index -= MAX_CPLBS - first_switched_dcplb; 131 dcplb_rr_index[cpu] -= MAX_CPLBS - first_switched_dcplb;
131 } 132 }
132 dcplb_rr_index++; 133 dcplb_rr_index[cpu]++;
133 return i; 134 return i;
134} 135}
135 136
136static noinline int dcplb_miss(void) 137static noinline int dcplb_miss(unsigned int cpu)
137{ 138{
138 unsigned long addr = bfin_read_DCPLB_FAULT_ADDR(); 139 unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
139 int status = bfin_read_DCPLB_STATUS(); 140 int status = bfin_read_DCPLB_STATUS();
@@ -141,7 +142,7 @@ static noinline int dcplb_miss(void)
141 int idx; 142 int idx;
142 unsigned long d_data; 143 unsigned long d_data;
143 144
144 nr_dcplb_miss++; 145 nr_dcplb_miss[cpu]++;
145 146
146 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; 147 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
147#ifdef CONFIG_BFIN_DCACHE 148#ifdef CONFIG_BFIN_DCACHE
@@ -168,25 +169,25 @@ static noinline int dcplb_miss(void)
168 } else if (addr >= _ramend) { 169 } else if (addr >= _ramend) {
169 d_data |= CPLB_USER_RD | CPLB_USER_WR; 170 d_data |= CPLB_USER_RD | CPLB_USER_WR;
170 } else { 171 } else {
171 mask = current_rwx_mask; 172 mask = current_rwx_mask[cpu];
172 if (mask) { 173 if (mask) {
173 int page = addr >> PAGE_SHIFT; 174 int page = addr >> PAGE_SHIFT;
174 int offs = page >> 5; 175 int idx = page >> 5;
175 int bit = 1 << (page & 31); 176 int bit = 1 << (page & 31);
176 177
177 if (mask[offs] & bit) 178 if (mask[idx] & bit)
178 d_data |= CPLB_USER_RD; 179 d_data |= CPLB_USER_RD;
179 180
180 mask += page_mask_nelts; 181 mask += page_mask_nelts;
181 if (mask[offs] & bit) 182 if (mask[idx] & bit)
182 d_data |= CPLB_USER_WR; 183 d_data |= CPLB_USER_WR;
183 } 184 }
184 } 185 }
185 idx = evict_one_dcplb(); 186 idx = evict_one_dcplb(cpu);
186 187
187 addr &= PAGE_MASK; 188 addr &= PAGE_MASK;
188 dcplb_tbl[idx].addr = addr; 189 dcplb_tbl[cpu][idx].addr = addr;
189 dcplb_tbl[idx].data = d_data; 190 dcplb_tbl[cpu][idx].data = d_data;
190 191
191 disable_dcplb(); 192 disable_dcplb();
192 bfin_write32(DCPLB_DATA0 + idx * 4, d_data); 193 bfin_write32(DCPLB_DATA0 + idx * 4, d_data);
@@ -196,21 +197,21 @@ static noinline int dcplb_miss(void)
196 return 0; 197 return 0;
197} 198}
198 199
199static noinline int icplb_miss(void) 200static noinline int icplb_miss(unsigned int cpu)
200{ 201{
201 unsigned long addr = bfin_read_ICPLB_FAULT_ADDR(); 202 unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
202 int status = bfin_read_ICPLB_STATUS(); 203 int status = bfin_read_ICPLB_STATUS();
203 int idx; 204 int idx;
204 unsigned long i_data; 205 unsigned long i_data;
205 206
206 nr_icplb_miss++; 207 nr_icplb_miss[cpu]++;
207 208
208 /* If inside the uncached DMA region, fault. */ 209 /* If inside the uncached DMA region, fault. */
209 if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend) 210 if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend)
210 return CPLB_PROT_VIOL; 211 return CPLB_PROT_VIOL;
211 212
212 if (status & FAULT_USERSUPV) 213 if (status & FAULT_USERSUPV)
213 nr_icplb_supv_miss++; 214 nr_icplb_supv_miss[cpu]++;
214 215
215 /* 216 /*
216 * 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
@@ -218,8 +219,8 @@ static noinline int icplb_miss(void)
218 * that the instruction crosses a page boundary. 219 * that the instruction crosses a page boundary.
219 */ 220 */
220 for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) { 221 for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) {
221 if (icplb_tbl[idx].data & CPLB_VALID) { 222 if (icplb_tbl[cpu][idx].data & CPLB_VALID) {
222 unsigned long this_addr = icplb_tbl[idx].addr; 223 unsigned long this_addr = icplb_tbl[cpu][idx].addr;
223 if (this_addr <= addr && this_addr + PAGE_SIZE > addr) { 224 if (this_addr <= addr && this_addr + PAGE_SIZE > addr) {
224 addr += PAGE_SIZE; 225 addr += PAGE_SIZE;
225 break; 226 break;
@@ -257,23 +258,23 @@ static noinline int icplb_miss(void)
257 * Otherwise, check the x bitmap of the current process. 258 * Otherwise, check the x bitmap of the current process.
258 */ 259 */
259 if (!(status & FAULT_USERSUPV)) { 260 if (!(status & FAULT_USERSUPV)) {
260 unsigned long *mask = current_rwx_mask; 261 unsigned long *mask = current_rwx_mask[cpu];
261 262
262 if (mask) { 263 if (mask) {
263 int page = addr >> PAGE_SHIFT; 264 int page = addr >> PAGE_SHIFT;
264 int offs = page >> 5; 265 int idx = page >> 5;
265 int bit = 1 << (page & 31); 266 int bit = 1 << (page & 31);
266 267
267 mask += 2 * page_mask_nelts; 268 mask += 2 * page_mask_nelts;
268 if (mask[offs] & bit) 269 if (mask[idx] & bit)
269 i_data |= CPLB_USER_RD; 270 i_data |= CPLB_USER_RD;
270 } 271 }
271 } 272 }
272 } 273 }
273 idx = evict_one_icplb(); 274 idx = evict_one_icplb(cpu);
274 addr &= PAGE_MASK; 275 addr &= PAGE_MASK;
275 icplb_tbl[idx].addr = addr; 276 icplb_tbl[cpu][idx].addr = addr;
276 icplb_tbl[idx].data = i_data; 277 icplb_tbl[cpu][idx].data = i_data;
277 278
278 disable_icplb(); 279 disable_icplb();
279 bfin_write32(ICPLB_DATA0 + idx * 4, i_data); 280 bfin_write32(ICPLB_DATA0 + idx * 4, i_data);
@@ -283,19 +284,19 @@ static noinline int icplb_miss(void)
283 return 0; 284 return 0;
284} 285}
285 286
286static noinline int dcplb_protection_fault(void) 287static noinline int dcplb_protection_fault(unsigned int cpu)
287{ 288{
288 int status = bfin_read_DCPLB_STATUS(); 289 int status = bfin_read_DCPLB_STATUS();
289 290
290 nr_dcplb_prot++; 291 nr_dcplb_prot[cpu]++;
291 292
292 if (status & FAULT_RW) { 293 if (status & FAULT_RW) {
293 int idx = faulting_cplb_index(status); 294 int idx = faulting_cplb_index(status);
294 unsigned long data = dcplb_tbl[idx].data; 295 unsigned long data = dcplb_tbl[cpu][idx].data;
295 if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) && 296 if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
296 write_permitted(status, data)) { 297 write_permitted(status, data)) {
297 data |= CPLB_DIRTY; 298 data |= CPLB_DIRTY;
298 dcplb_tbl[idx].data = data; 299 dcplb_tbl[cpu][idx].data = data;
299 bfin_write32(DCPLB_DATA0 + idx * 4, data); 300 bfin_write32(DCPLB_DATA0 + idx * 4, data);
300 return 0; 301 return 0;
301 } 302 }
@@ -306,36 +307,37 @@ static noinline int dcplb_protection_fault(void)
306int cplb_hdr(int seqstat, struct pt_regs *regs) 307int cplb_hdr(int seqstat, struct pt_regs *regs)
307{ 308{
308 int cause = seqstat & 0x3f; 309 int cause = seqstat & 0x3f;
310 unsigned int cpu = smp_processor_id();
309 switch (cause) { 311 switch (cause) {
310 case 0x23: 312 case 0x23:
311 return dcplb_protection_fault(); 313 return dcplb_protection_fault(cpu);
312 case 0x2C: 314 case 0x2C:
313 return icplb_miss(); 315 return icplb_miss(cpu);
314 case 0x26: 316 case 0x26:
315 return dcplb_miss(); 317 return dcplb_miss(cpu);
316 default: 318 default:
317 return 1; 319 return 1;
318 } 320 }
319} 321}
320 322
321void flush_switched_cplbs(void) 323void flush_switched_cplbs(unsigned int cpu)
322{ 324{
323 int i; 325 int i;
324 unsigned long flags; 326 unsigned long flags;
325 327
326 nr_cplb_flush++; 328 nr_cplb_flush[cpu]++;
327 329
328 local_irq_save(flags); 330 local_irq_save(flags);
329 disable_icplb(); 331 disable_icplb();
330 for (i = first_switched_icplb; i < MAX_CPLBS; i++) { 332 for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
331 icplb_tbl[i].data = 0; 333 icplb_tbl[cpu][i].data = 0;
332 bfin_write32(ICPLB_DATA0 + i * 4, 0); 334 bfin_write32(ICPLB_DATA0 + i * 4, 0);
333 } 335 }
334 enable_icplb(); 336 enable_icplb();
335 337
336 disable_dcplb(); 338 disable_dcplb();
337 for (i = first_switched_dcplb; i < MAX_CPLBS; i++) { 339 for (i = first_switched_dcplb; i < MAX_CPLBS; i++) {
338 dcplb_tbl[i].data = 0; 340 dcplb_tbl[cpu][i].data = 0;
339 bfin_write32(DCPLB_DATA0 + i * 4, 0); 341 bfin_write32(DCPLB_DATA0 + i * 4, 0);
340 } 342 }
341 enable_dcplb(); 343 enable_dcplb();
@@ -343,7 +345,7 @@ void flush_switched_cplbs(void)
343 345
344} 346}
345 347
346void set_mask_dcplbs(unsigned long *masks) 348void set_mask_dcplbs(unsigned long *masks, unsigned int cpu)
347{ 349{
348 int i; 350 int i;
349 unsigned long addr = (unsigned long)masks; 351 unsigned long addr = (unsigned long)masks;
@@ -351,12 +353,12 @@ void set_mask_dcplbs(unsigned long *masks)
351 unsigned long flags; 353 unsigned long flags;
352 354
353 if (!masks) { 355 if (!masks) {
354 current_rwx_mask = masks; 356 current_rwx_mask[cpu] = masks;
355 return; 357 return;
356 } 358 }
357 359
358 local_irq_save(flags); 360 local_irq_save(flags);
359 current_rwx_mask = masks; 361 current_rwx_mask[cpu] = masks;
360 362
361 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; 363 d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
362#ifdef CONFIG_BFIN_DCACHE 364#ifdef CONFIG_BFIN_DCACHE
@@ -368,8 +370,8 @@ void set_mask_dcplbs(unsigned long *masks)
368 370
369 disable_dcplb(); 371 disable_dcplb();
370 for (i = first_mask_dcplb; i < first_switched_dcplb; i++) { 372 for (i = first_mask_dcplb; i < first_switched_dcplb; i++) {
371 dcplb_tbl[i].addr = addr; 373 dcplb_tbl[cpu][i].addr = addr;
372 dcplb_tbl[i].data = d_data; 374 dcplb_tbl[cpu][i].data = d_data;
373 bfin_write32(DCPLB_DATA0 + i * 4, d_data); 375 bfin_write32(DCPLB_DATA0 + i * 4, d_data);
374 bfin_write32(DCPLB_ADDR0 + i * 4, addr); 376 bfin_write32(DCPLB_ADDR0 + i * 4, addr);
375 addr += PAGE_SIZE; 377 addr += PAGE_SIZE;