Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.18 533 lines 13 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (C) 2005-2017 Andes Technology Corporation 3 4#include <linux/module.h> 5#include <linux/sched.h> 6#include <linux/mm.h> 7#include <asm/nds32.h> 8#include <asm/pgtable.h> 9#include <asm/tlbflush.h> 10#include <asm/cacheflush.h> 11#include <asm/l2_cache.h> 12#include <nds32_intrinsic.h> 13 14#include <asm/cache_info.h> 15extern struct cache_info L1_cache_info[2]; 16 17int va_kernel_present(unsigned long addr) 18{ 19 pmd_t *pmd; 20 pte_t *ptep, pte; 21 22 pmd = pmd_offset(pgd_offset_k(addr), addr); 23 if (!pmd_none(*pmd)) { 24 ptep = pte_offset_map(pmd, addr); 25 pte = *ptep; 26 if (pte_present(pte)) 27 return pte; 28 } 29 return 0; 30} 31 32pte_t va_present(struct mm_struct * mm, unsigned long addr) 33{ 34 pgd_t *pgd; 35 pud_t *pud; 36 pmd_t *pmd; 37 pte_t *ptep, pte; 38 39 pgd = pgd_offset(mm, addr); 40 if (!pgd_none(*pgd)) { 41 pud = pud_offset(pgd, addr); 42 if (!pud_none(*pud)) { 43 pmd = pmd_offset(pud, addr); 44 if (!pmd_none(*pmd)) { 45 ptep = pte_offset_map(pmd, addr); 46 pte = *ptep; 47 if (pte_present(pte)) 48 return pte; 49 } 50 } 51 } 52 return 0; 53 54} 55 56int va_readable(struct pt_regs *regs, unsigned long addr) 57{ 58 struct mm_struct *mm = current->mm; 59 pte_t pte; 60 int ret = 0; 61 62 if (user_mode(regs)) { 63 /* user mode */ 64 pte = va_present(mm, addr); 65 if (!pte && pte_read(pte)) 66 ret = 1; 67 } else { 68 /* superuser mode is always readable, so we can only 69 * check it is present or not*/ 70 return (! !va_kernel_present(addr)); 71 } 72 return ret; 73} 74 75int va_writable(struct pt_regs *regs, unsigned long addr) 76{ 77 struct mm_struct *mm = current->mm; 78 pte_t pte; 79 int ret = 0; 80 81 if (user_mode(regs)) { 82 /* user mode */ 83 pte = va_present(mm, addr); 84 if (!pte && pte_write(pte)) 85 ret = 1; 86 } else { 87 /* superuser mode */ 88 pte = va_kernel_present(addr); 89 if (!pte && pte_kernel_write(pte)) 90 ret = 1; 91 } 92 return ret; 93} 94 95/* 96 * All 97 */ 98void cpu_icache_inval_all(void) 99{ 100 unsigned long end, line_size; 101 102 line_size = L1_cache_info[ICACHE].line_size; 103 end = 104 line_size * L1_cache_info[ICACHE].ways * L1_cache_info[ICACHE].sets; 105 106 do { 107 end -= line_size; 108 __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); 109 end -= line_size; 110 __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); 111 end -= line_size; 112 __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); 113 end -= line_size; 114 __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); 115 } while (end > 0); 116 __nds32__isb(); 117} 118 119void cpu_dcache_inval_all(void) 120{ 121 __nds32__cctl_l1d_invalall(); 122} 123 124#ifdef CONFIG_CACHE_L2 125void dcache_wb_all_level(void) 126{ 127 unsigned long flags, cmd; 128 local_irq_save(flags); 129 __nds32__cctl_l1d_wball_alvl(); 130 /* Section 1: Ensure the section 2 & 3 program code execution after */ 131 __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); 132 133 /* Section 2: Confirm the writeback all level is done in CPU and L2C */ 134 cmd = CCTL_CMD_L2_SYNC; 135 L2_CMD_RDY(); 136 L2C_W_REG(L2_CCTL_CMD_OFF, cmd); 137 L2_CMD_RDY(); 138 139 /* Section 3: Writeback whole L2 cache */ 140 cmd = CCTL_ALL_CMD | CCTL_CMD_L2_IX_WB; 141 L2_CMD_RDY(); 142 L2C_W_REG(L2_CCTL_CMD_OFF, cmd); 143 L2_CMD_RDY(); 144 __nds32__msync_all(); 145 local_irq_restore(flags); 146} 147EXPORT_SYMBOL(dcache_wb_all_level); 148#endif 149 150void cpu_dcache_wb_all(void) 151{ 152 __nds32__cctl_l1d_wball_one_lvl(); 153 __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); 154} 155 156void cpu_dcache_wbinval_all(void) 157{ 158#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 159 unsigned long flags; 160 local_irq_save(flags); 161#endif 162 cpu_dcache_wb_all(); 163 cpu_dcache_inval_all(); 164#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 165 local_irq_restore(flags); 166#endif 167} 168 169/* 170 * Page 171 */ 172void cpu_icache_inval_page(unsigned long start) 173{ 174 unsigned long line_size, end; 175 176 line_size = L1_cache_info[ICACHE].line_size; 177 end = start + PAGE_SIZE; 178 179 do { 180 end -= line_size; 181 __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); 182 end -= line_size; 183 __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); 184 end -= line_size; 185 __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); 186 end -= line_size; 187 __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); 188 } while (end != start); 189 __nds32__isb(); 190} 191 192void cpu_dcache_inval_page(unsigned long start) 193{ 194 unsigned long line_size, end; 195 196 line_size = L1_cache_info[DCACHE].line_size; 197 end = start + PAGE_SIZE; 198 199 do { 200 end -= line_size; 201 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 202 end -= line_size; 203 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 204 end -= line_size; 205 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 206 end -= line_size; 207 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 208 } while (end != start); 209} 210 211void cpu_dcache_wb_page(unsigned long start) 212{ 213#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 214 unsigned long line_size, end; 215 216 line_size = L1_cache_info[DCACHE].line_size; 217 end = start + PAGE_SIZE; 218 219 do { 220 end -= line_size; 221 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 222 end -= line_size; 223 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 224 end -= line_size; 225 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 226 end -= line_size; 227 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 228 } while (end != start); 229 __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); 230#endif 231} 232 233void cpu_dcache_wbinval_page(unsigned long start) 234{ 235 unsigned long line_size, end; 236 237 line_size = L1_cache_info[DCACHE].line_size; 238 end = start + PAGE_SIZE; 239 240 do { 241 end -= line_size; 242#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 243 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 244#endif 245 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 246 end -= line_size; 247#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 248 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 249#endif 250 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 251 end -= line_size; 252#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 253 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 254#endif 255 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 256 end -= line_size; 257#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 258 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); 259#endif 260 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); 261 } while (end != start); 262 __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); 263} 264 265void cpu_cache_wbinval_page(unsigned long page, int flushi) 266{ 267 cpu_dcache_wbinval_page(page); 268 if (flushi) 269 cpu_icache_inval_page(page); 270} 271 272/* 273 * Range 274 */ 275void cpu_icache_inval_range(unsigned long start, unsigned long end) 276{ 277 unsigned long line_size; 278 279 line_size = L1_cache_info[ICACHE].line_size; 280 281 while (end > start) { 282 __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (start)); 283 start += line_size; 284 } 285 __nds32__isb(); 286} 287 288void cpu_dcache_inval_range(unsigned long start, unsigned long end) 289{ 290 unsigned long line_size; 291 292 line_size = L1_cache_info[DCACHE].line_size; 293 294 while (end > start) { 295 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start)); 296 start += line_size; 297 } 298} 299 300void cpu_dcache_wb_range(unsigned long start, unsigned long end) 301{ 302#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 303 unsigned long line_size; 304 305 line_size = L1_cache_info[DCACHE].line_size; 306 307 while (end > start) { 308 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start)); 309 start += line_size; 310 } 311 __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); 312#endif 313} 314 315void cpu_dcache_wbinval_range(unsigned long start, unsigned long end) 316{ 317 unsigned long line_size; 318 319 line_size = L1_cache_info[DCACHE].line_size; 320 321 while (end > start) { 322#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 323 __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start)); 324#endif 325 __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start)); 326 start += line_size; 327 } 328 __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD,0); 329} 330 331void cpu_cache_wbinval_range(unsigned long start, unsigned long end, int flushi) 332{ 333 unsigned long line_size, align_start, align_end; 334 335 line_size = L1_cache_info[DCACHE].line_size; 336 align_start = start & ~(line_size - 1); 337 align_end = (end + line_size - 1) & ~(line_size - 1); 338 cpu_dcache_wbinval_range(align_start, align_end); 339 340 if (flushi) { 341 line_size = L1_cache_info[ICACHE].line_size; 342 align_start = start & ~(line_size - 1); 343 align_end = (end + line_size - 1) & ~(line_size - 1); 344 cpu_icache_inval_range(align_start, align_end); 345 } 346} 347 348void cpu_cache_wbinval_range_check(struct vm_area_struct *vma, 349 unsigned long start, unsigned long end, 350 bool flushi, bool wbd) 351{ 352 unsigned long line_size, t_start, t_end; 353 354 if (!flushi && !wbd) 355 return; 356 line_size = L1_cache_info[DCACHE].line_size; 357 start = start & ~(line_size - 1); 358 end = (end + line_size - 1) & ~(line_size - 1); 359 360 if ((end - start) > (8 * PAGE_SIZE)) { 361 if (wbd) 362 cpu_dcache_wbinval_all(); 363 if (flushi) 364 cpu_icache_inval_all(); 365 return; 366 } 367 368 t_start = (start + PAGE_SIZE) & PAGE_MASK; 369 t_end = ((end - 1) & PAGE_MASK); 370 371 if ((start & PAGE_MASK) == t_end) { 372 if (va_present(vma->vm_mm, start)) { 373 if (wbd) 374 cpu_dcache_wbinval_range(start, end); 375 if (flushi) 376 cpu_icache_inval_range(start, end); 377 } 378 return; 379 } 380 381 if (va_present(vma->vm_mm, start)) { 382 if (wbd) 383 cpu_dcache_wbinval_range(start, t_start); 384 if (flushi) 385 cpu_icache_inval_range(start, t_start); 386 } 387 388 if (va_present(vma->vm_mm, end - 1)) { 389 if (wbd) 390 cpu_dcache_wbinval_range(t_end, end); 391 if (flushi) 392 cpu_icache_inval_range(t_end, end); 393 } 394 395 while (t_start < t_end) { 396 if (va_present(vma->vm_mm, t_start)) { 397 if (wbd) 398 cpu_dcache_wbinval_page(t_start); 399 if (flushi) 400 cpu_icache_inval_page(t_start); 401 } 402 t_start += PAGE_SIZE; 403 } 404} 405 406#ifdef CONFIG_CACHE_L2 407static inline void cpu_l2cache_op(unsigned long start, unsigned long end, unsigned long op) 408{ 409 if (atl2c_base) { 410 unsigned long p_start = __pa(start); 411 unsigned long p_end = __pa(end); 412 unsigned long cmd; 413 unsigned long line_size; 414 /* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */ 415 line_size = L2_CACHE_LINE_SIZE(); 416 p_start = p_start & (~(line_size - 1)); 417 p_end = (p_end + line_size - 1) & (~(line_size - 1)); 418 cmd = 419 (p_start & ~(line_size - 1)) | op | 420 CCTL_SINGLE_CMD; 421 do { 422 L2_CMD_RDY(); 423 L2C_W_REG(L2_CCTL_CMD_OFF, cmd); 424 cmd += line_size; 425 p_start += line_size; 426 } while (p_end > p_start); 427 cmd = CCTL_CMD_L2_SYNC; 428 L2_CMD_RDY(); 429 L2C_W_REG(L2_CCTL_CMD_OFF, cmd); 430 L2_CMD_RDY(); 431 } 432} 433#else 434#define cpu_l2cache_op(start,end,op) do { } while (0) 435#endif 436/* 437 * DMA 438 */ 439void cpu_dma_wb_range(unsigned long start, unsigned long end) 440{ 441 unsigned long line_size; 442 unsigned long flags; 443 line_size = L1_cache_info[DCACHE].line_size; 444 start = start & (~(line_size - 1)); 445 end = (end + line_size - 1) & (~(line_size - 1)); 446 if (unlikely(start == end)) 447 return; 448 449 local_irq_save(flags); 450 cpu_dcache_wb_range(start, end); 451 cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WB); 452 __nds32__msync_all(); 453 local_irq_restore(flags); 454} 455 456void cpu_dma_inval_range(unsigned long start, unsigned long end) 457{ 458 unsigned long line_size; 459 unsigned long old_start = start; 460 unsigned long old_end = end; 461 unsigned long flags; 462 line_size = L1_cache_info[DCACHE].line_size; 463 start = start & (~(line_size - 1)); 464 end = (end + line_size - 1) & (~(line_size - 1)); 465 if (unlikely(start == end)) 466 return; 467 local_irq_save(flags); 468 if (start != old_start) { 469 cpu_dcache_wbinval_range(start, start + line_size); 470 cpu_l2cache_op(start, start + line_size, CCTL_CMD_L2_PA_WBINVAL); 471 } 472 if (end != old_end) { 473 cpu_dcache_wbinval_range(end - line_size, end); 474 cpu_l2cache_op(end - line_size, end, CCTL_CMD_L2_PA_WBINVAL); 475 } 476 cpu_dcache_inval_range(start, end); 477 cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_INVAL); 478 __nds32__msync_all(); 479 local_irq_restore(flags); 480 481} 482 483void cpu_dma_wbinval_range(unsigned long start, unsigned long end) 484{ 485 unsigned long line_size; 486 unsigned long flags; 487 line_size = L1_cache_info[DCACHE].line_size; 488 start = start & (~(line_size - 1)); 489 end = (end + line_size - 1) & (~(line_size - 1)); 490 if (unlikely(start == end)) 491 return; 492 493 local_irq_save(flags); 494 cpu_dcache_wbinval_range(start, end); 495 cpu_l2cache_op(start, end, CCTL_CMD_L2_PA_WBINVAL); 496 __nds32__msync_all(); 497 local_irq_restore(flags); 498} 499 500void cpu_proc_init(void) 501{ 502} 503 504void cpu_proc_fin(void) 505{ 506} 507 508void cpu_do_idle(void) 509{ 510 __nds32__standby_no_wake_grant(); 511} 512 513void cpu_reset(unsigned long reset) 514{ 515 u32 tmp; 516 GIE_DISABLE(); 517 tmp = __nds32__mfsr(NDS32_SR_CACHE_CTL); 518 tmp &= ~(CACHE_CTL_mskIC_EN | CACHE_CTL_mskDC_EN); 519 __nds32__mtsr_isb(tmp, NDS32_SR_CACHE_CTL); 520 cpu_dcache_wbinval_all(); 521 cpu_icache_inval_all(); 522 523 __asm__ __volatile__("jr.toff %0\n\t"::"r"(reset)); 524} 525 526void cpu_switch_mm(struct mm_struct *mm) 527{ 528 unsigned long cid; 529 cid = __nds32__mfsr(NDS32_SR_TLB_MISC); 530 cid = (cid & ~TLB_MISC_mskCID) | mm->context.id; 531 __nds32__mtsr_dsb(cid, NDS32_SR_TLB_MISC); 532 __nds32__mtsr_isb(__pa(mm->pgd), NDS32_SR_L1_PPTB); 533}