18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org) 78c2ecf20Sopenharmony_ci * Copyright (C) 2007 Maciej W. Rozycki 88c2ecf20Sopenharmony_ci * Copyright (C) 2008 Thiemo Seufer 98c2ecf20Sopenharmony_ci * Copyright (C) 2012 MIPS Technologies, Inc. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/sched.h> 138c2ecf20Sopenharmony_ci#include <linux/smp.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/bugs.h> 188c2ecf20Sopenharmony_ci#include <asm/cacheops.h> 198c2ecf20Sopenharmony_ci#include <asm/cpu-type.h> 208c2ecf20Sopenharmony_ci#include <asm/inst.h> 218c2ecf20Sopenharmony_ci#include <asm/io.h> 228c2ecf20Sopenharmony_ci#include <asm/page.h> 238c2ecf20Sopenharmony_ci#include <asm/prefetch.h> 248c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 258c2ecf20Sopenharmony_ci#include <asm/mipsregs.h> 268c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 278c2ecf20Sopenharmony_ci#include <asm/cpu.h> 288c2ecf20Sopenharmony_ci#include <asm/war.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#ifdef CONFIG_SIBYTE_DMA_PAGEOPS 318c2ecf20Sopenharmony_ci#include <asm/sibyte/sb1250.h> 328c2ecf20Sopenharmony_ci#include <asm/sibyte/sb1250_regs.h> 338c2ecf20Sopenharmony_ci#include <asm/sibyte/sb1250_dma.h> 348c2ecf20Sopenharmony_ci#endif 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <asm/uasm.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Registers used in the assembled routines. */ 398c2ecf20Sopenharmony_ci#define ZERO 0 408c2ecf20Sopenharmony_ci#define AT 2 418c2ecf20Sopenharmony_ci#define A0 4 428c2ecf20Sopenharmony_ci#define A1 5 438c2ecf20Sopenharmony_ci#define A2 6 448c2ecf20Sopenharmony_ci#define T0 8 458c2ecf20Sopenharmony_ci#define T1 9 468c2ecf20Sopenharmony_ci#define T2 10 478c2ecf20Sopenharmony_ci#define T3 11 488c2ecf20Sopenharmony_ci#define T9 25 498c2ecf20Sopenharmony_ci#define RA 31 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* Handle labels (which must be positive integers). */ 528c2ecf20Sopenharmony_cienum label_id { 538c2ecf20Sopenharmony_ci label_clear_nopref = 1, 548c2ecf20Sopenharmony_ci label_clear_pref, 558c2ecf20Sopenharmony_ci label_copy_nopref, 568c2ecf20Sopenharmony_ci label_copy_pref_both, 578c2ecf20Sopenharmony_ci label_copy_pref_store, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciUASM_L_LA(_clear_nopref) 618c2ecf20Sopenharmony_ciUASM_L_LA(_clear_pref) 628c2ecf20Sopenharmony_ciUASM_L_LA(_copy_nopref) 638c2ecf20Sopenharmony_ciUASM_L_LA(_copy_pref_both) 648c2ecf20Sopenharmony_ciUASM_L_LA(_copy_pref_store) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* We need one branch and therefore one relocation per target label. */ 678c2ecf20Sopenharmony_cistatic struct uasm_label labels[5]; 688c2ecf20Sopenharmony_cistatic struct uasm_reloc relocs[5]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) 718c2ecf20Sopenharmony_ci#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * R6 has a limited offset of the pref instruction. 758c2ecf20Sopenharmony_ci * Skip it if the offset is more than 9 bits. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci#define _uasm_i_pref(a, b, c, d) \ 788c2ecf20Sopenharmony_cido { \ 798c2ecf20Sopenharmony_ci if (cpu_has_mips_r6) { \ 808c2ecf20Sopenharmony_ci if (c <= 0xff && c >= -0x100) \ 818c2ecf20Sopenharmony_ci uasm_i_pref(a, b, c, d);\ 828c2ecf20Sopenharmony_ci } else { \ 838c2ecf20Sopenharmony_ci uasm_i_pref(a, b, c, d); \ 848c2ecf20Sopenharmony_ci } \ 858c2ecf20Sopenharmony_ci} while(0) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int pref_bias_clear_store; 888c2ecf20Sopenharmony_cistatic int pref_bias_copy_load; 898c2ecf20Sopenharmony_cistatic int pref_bias_copy_store; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic u32 pref_src_mode; 928c2ecf20Sopenharmony_cistatic u32 pref_dst_mode; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int clear_word_size; 958c2ecf20Sopenharmony_cistatic int copy_word_size; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int half_clear_loop_size; 988c2ecf20Sopenharmony_cistatic int half_copy_loop_size; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int cache_line_size; 1018c2ecf20Sopenharmony_ci#define cache_line_mask() (cache_line_size - 1) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic inline void 1048c2ecf20Sopenharmony_cipg_addiu(u32 **buf, unsigned int reg1, unsigned int reg2, unsigned int off) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) { 1078c2ecf20Sopenharmony_ci if (off > 0x7fff) { 1088c2ecf20Sopenharmony_ci uasm_i_lui(buf, T9, uasm_rel_hi(off)); 1098c2ecf20Sopenharmony_ci uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); 1108c2ecf20Sopenharmony_ci } else 1118c2ecf20Sopenharmony_ci uasm_i_addiu(buf, T9, ZERO, off); 1128c2ecf20Sopenharmony_ci uasm_i_daddu(buf, reg1, reg2, T9); 1138c2ecf20Sopenharmony_ci } else { 1148c2ecf20Sopenharmony_ci if (off > 0x7fff) { 1158c2ecf20Sopenharmony_ci uasm_i_lui(buf, T9, uasm_rel_hi(off)); 1168c2ecf20Sopenharmony_ci uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); 1178c2ecf20Sopenharmony_ci UASM_i_ADDU(buf, reg1, reg2, T9); 1188c2ecf20Sopenharmony_ci } else 1198c2ecf20Sopenharmony_ci UASM_i_ADDIU(buf, reg1, reg2, off); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void set_prefetch_parameters(void) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) 1268c2ecf20Sopenharmony_ci clear_word_size = 8; 1278c2ecf20Sopenharmony_ci else 1288c2ecf20Sopenharmony_ci clear_word_size = 4; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (cpu_has_64bit_gp_regs) 1318c2ecf20Sopenharmony_ci copy_word_size = 8; 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci copy_word_size = 4; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* 1368c2ecf20Sopenharmony_ci * The pref's used here are using "streaming" hints, which cause the 1378c2ecf20Sopenharmony_ci * copied data to be kicked out of the cache sooner. A page copy often 1388c2ecf20Sopenharmony_ci * ends up copying a lot more data than is commonly used, so this seems 1398c2ecf20Sopenharmony_ci * to make sense in terms of reducing cache pollution, but I've no real 1408c2ecf20Sopenharmony_ci * performance data to back this up. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci if (cpu_has_prefetch) { 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * XXX: Most prefetch bias values in here are based on 1458c2ecf20Sopenharmony_ci * guesswork. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci cache_line_size = cpu_dcache_line_size(); 1488c2ecf20Sopenharmony_ci switch (current_cpu_type()) { 1498c2ecf20Sopenharmony_ci case CPU_R5500: 1508c2ecf20Sopenharmony_ci case CPU_TX49XX: 1518c2ecf20Sopenharmony_ci /* These processors only support the Pref_Load. */ 1528c2ecf20Sopenharmony_ci pref_bias_copy_load = 256; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci case CPU_R10000: 1568c2ecf20Sopenharmony_ci case CPU_R12000: 1578c2ecf20Sopenharmony_ci case CPU_R14000: 1588c2ecf20Sopenharmony_ci case CPU_R16000: 1598c2ecf20Sopenharmony_ci /* 1608c2ecf20Sopenharmony_ci * Those values have been experimentally tuned for an 1618c2ecf20Sopenharmony_ci * Origin 200. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci pref_bias_clear_store = 512; 1648c2ecf20Sopenharmony_ci pref_bias_copy_load = 256; 1658c2ecf20Sopenharmony_ci pref_bias_copy_store = 256; 1668c2ecf20Sopenharmony_ci pref_src_mode = Pref_LoadStreamed; 1678c2ecf20Sopenharmony_ci pref_dst_mode = Pref_StoreStreamed; 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci case CPU_SB1: 1718c2ecf20Sopenharmony_ci case CPU_SB1A: 1728c2ecf20Sopenharmony_ci pref_bias_clear_store = 128; 1738c2ecf20Sopenharmony_ci pref_bias_copy_load = 128; 1748c2ecf20Sopenharmony_ci pref_bias_copy_store = 128; 1758c2ecf20Sopenharmony_ci /* 1768c2ecf20Sopenharmony_ci * SB1 pass1 Pref_LoadStreamed/Pref_StoreStreamed 1778c2ecf20Sopenharmony_ci * hints are broken. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci if (current_cpu_type() == CPU_SB1 && 1808c2ecf20Sopenharmony_ci (current_cpu_data.processor_id & 0xff) < 0x02) { 1818c2ecf20Sopenharmony_ci pref_src_mode = Pref_Load; 1828c2ecf20Sopenharmony_ci pref_dst_mode = Pref_Store; 1838c2ecf20Sopenharmony_ci } else { 1848c2ecf20Sopenharmony_ci pref_src_mode = Pref_LoadStreamed; 1858c2ecf20Sopenharmony_ci pref_dst_mode = Pref_StoreStreamed; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci case CPU_LOONGSON64: 1908c2ecf20Sopenharmony_ci /* Loongson-3 only support the Pref_Load/Pref_Store. */ 1918c2ecf20Sopenharmony_ci pref_bias_clear_store = 128; 1928c2ecf20Sopenharmony_ci pref_bias_copy_load = 128; 1938c2ecf20Sopenharmony_ci pref_bias_copy_store = 128; 1948c2ecf20Sopenharmony_ci pref_src_mode = Pref_Load; 1958c2ecf20Sopenharmony_ci pref_dst_mode = Pref_Store; 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci default: 1998c2ecf20Sopenharmony_ci pref_bias_clear_store = 128; 2008c2ecf20Sopenharmony_ci pref_bias_copy_load = 256; 2018c2ecf20Sopenharmony_ci pref_bias_copy_store = 128; 2028c2ecf20Sopenharmony_ci pref_src_mode = Pref_LoadStreamed; 2038c2ecf20Sopenharmony_ci if (cpu_has_mips_r6) 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * Bit 30 (Pref_PrepareForStore) has been 2068c2ecf20Sopenharmony_ci * removed from MIPS R6. Use bit 5 2078c2ecf20Sopenharmony_ci * (Pref_StoreStreamed). 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci pref_dst_mode = Pref_StoreStreamed; 2108c2ecf20Sopenharmony_ci else 2118c2ecf20Sopenharmony_ci pref_dst_mode = Pref_PrepareForStore; 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } else { 2158c2ecf20Sopenharmony_ci if (cpu_has_cache_cdex_s) 2168c2ecf20Sopenharmony_ci cache_line_size = cpu_scache_line_size(); 2178c2ecf20Sopenharmony_ci else if (cpu_has_cache_cdex_p) 2188c2ecf20Sopenharmony_ci cache_line_size = cpu_dcache_line_size(); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * Too much unrolling will overflow the available space in 2228c2ecf20Sopenharmony_ci * clear_space_array / copy_page_array. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci half_clear_loop_size = min(16 * clear_word_size, 2258c2ecf20Sopenharmony_ci max(cache_line_size >> 1, 2268c2ecf20Sopenharmony_ci 4 * clear_word_size)); 2278c2ecf20Sopenharmony_ci half_copy_loop_size = min(16 * copy_word_size, 2288c2ecf20Sopenharmony_ci max(cache_line_size >> 1, 2298c2ecf20Sopenharmony_ci 4 * copy_word_size)); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic void build_clear_store(u32 **buf, int off) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) { 2358c2ecf20Sopenharmony_ci uasm_i_sd(buf, ZERO, off, A0); 2368c2ecf20Sopenharmony_ci } else { 2378c2ecf20Sopenharmony_ci uasm_i_sw(buf, ZERO, off, A0); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic inline void build_clear_pref(u32 **buf, int off) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci if (off & cache_line_mask()) 2448c2ecf20Sopenharmony_ci return; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (pref_bias_clear_store) { 2478c2ecf20Sopenharmony_ci _uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off, 2488c2ecf20Sopenharmony_ci A0); 2498c2ecf20Sopenharmony_ci } else if (cache_line_size == (half_clear_loop_size << 1)) { 2508c2ecf20Sopenharmony_ci if (cpu_has_cache_cdex_s) { 2518c2ecf20Sopenharmony_ci uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); 2528c2ecf20Sopenharmony_ci } else if (cpu_has_cache_cdex_p) { 2538c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V1_HIT_CACHEOP) && 2548c2ecf20Sopenharmony_ci cpu_is_r4600_v1_x()) { 2558c2ecf20Sopenharmony_ci uasm_i_nop(buf); 2568c2ecf20Sopenharmony_ci uasm_i_nop(buf); 2578c2ecf20Sopenharmony_ci uasm_i_nop(buf); 2588c2ecf20Sopenharmony_ci uasm_i_nop(buf); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && 2628c2ecf20Sopenharmony_ci cpu_is_r4600_v2_x()) 2638c2ecf20Sopenharmony_ci uasm_i_lw(buf, ZERO, ZERO, AT); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciextern u32 __clear_page_start; 2718c2ecf20Sopenharmony_ciextern u32 __clear_page_end; 2728c2ecf20Sopenharmony_ciextern u32 __copy_page_start; 2738c2ecf20Sopenharmony_ciextern u32 __copy_page_end; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_civoid build_clear_page(void) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int off; 2788c2ecf20Sopenharmony_ci u32 *buf = &__clear_page_start; 2798c2ecf20Sopenharmony_ci struct uasm_label *l = labels; 2808c2ecf20Sopenharmony_ci struct uasm_reloc *r = relocs; 2818c2ecf20Sopenharmony_ci int i; 2828c2ecf20Sopenharmony_ci static atomic_t run_once = ATOMIC_INIT(0); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (atomic_xchg(&run_once, 1)) { 2858c2ecf20Sopenharmony_ci return; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci memset(labels, 0, sizeof(labels)); 2898c2ecf20Sopenharmony_ci memset(relocs, 0, sizeof(relocs)); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci set_prefetch_parameters(); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* 2948c2ecf20Sopenharmony_ci * This algorithm makes the following assumptions: 2958c2ecf20Sopenharmony_ci * - The prefetch bias is a multiple of 2 words. 2968c2ecf20Sopenharmony_ci * - The prefetch bias is less than one page. 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ci BUG_ON(pref_bias_clear_store % (2 * clear_word_size)); 2998c2ecf20Sopenharmony_ci BUG_ON(PAGE_SIZE < pref_bias_clear_store); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci off = PAGE_SIZE - pref_bias_clear_store; 3028c2ecf20Sopenharmony_ci if (off > 0xffff || !pref_bias_clear_store) 3038c2ecf20Sopenharmony_ci pg_addiu(&buf, A2, A0, off); 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci uasm_i_ori(&buf, A2, A0, off); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x()) 3088c2ecf20Sopenharmony_ci uasm_i_lui(&buf, AT, uasm_rel_hi(0xa0000000)); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci off = cache_line_size ? min(8, pref_bias_clear_store / cache_line_size) 3118c2ecf20Sopenharmony_ci * cache_line_size : 0; 3128c2ecf20Sopenharmony_ci while (off) { 3138c2ecf20Sopenharmony_ci build_clear_pref(&buf, -off); 3148c2ecf20Sopenharmony_ci off -= cache_line_size; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci uasm_l_clear_pref(&l, buf); 3178c2ecf20Sopenharmony_ci do { 3188c2ecf20Sopenharmony_ci build_clear_pref(&buf, off); 3198c2ecf20Sopenharmony_ci build_clear_store(&buf, off); 3208c2ecf20Sopenharmony_ci off += clear_word_size; 3218c2ecf20Sopenharmony_ci } while (off < half_clear_loop_size); 3228c2ecf20Sopenharmony_ci pg_addiu(&buf, A0, A0, 2 * off); 3238c2ecf20Sopenharmony_ci off = -off; 3248c2ecf20Sopenharmony_ci do { 3258c2ecf20Sopenharmony_ci build_clear_pref(&buf, off); 3268c2ecf20Sopenharmony_ci if (off == -clear_word_size) 3278c2ecf20Sopenharmony_ci uasm_il_bne(&buf, &r, A0, A2, label_clear_pref); 3288c2ecf20Sopenharmony_ci build_clear_store(&buf, off); 3298c2ecf20Sopenharmony_ci off += clear_word_size; 3308c2ecf20Sopenharmony_ci } while (off < 0); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (pref_bias_clear_store) { 3338c2ecf20Sopenharmony_ci pg_addiu(&buf, A2, A0, pref_bias_clear_store); 3348c2ecf20Sopenharmony_ci uasm_l_clear_nopref(&l, buf); 3358c2ecf20Sopenharmony_ci off = 0; 3368c2ecf20Sopenharmony_ci do { 3378c2ecf20Sopenharmony_ci build_clear_store(&buf, off); 3388c2ecf20Sopenharmony_ci off += clear_word_size; 3398c2ecf20Sopenharmony_ci } while (off < half_clear_loop_size); 3408c2ecf20Sopenharmony_ci pg_addiu(&buf, A0, A0, 2 * off); 3418c2ecf20Sopenharmony_ci off = -off; 3428c2ecf20Sopenharmony_ci do { 3438c2ecf20Sopenharmony_ci if (off == -clear_word_size) 3448c2ecf20Sopenharmony_ci uasm_il_bne(&buf, &r, A0, A2, 3458c2ecf20Sopenharmony_ci label_clear_nopref); 3468c2ecf20Sopenharmony_ci build_clear_store(&buf, off); 3478c2ecf20Sopenharmony_ci off += clear_word_size; 3488c2ecf20Sopenharmony_ci } while (off < 0); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci uasm_i_jr(&buf, RA); 3528c2ecf20Sopenharmony_ci uasm_i_nop(&buf); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci BUG_ON(buf > &__clear_page_end); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci uasm_resolve_relocs(relocs, labels); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci pr_debug("Synthesized clear page handler (%u instructions).\n", 3598c2ecf20Sopenharmony_ci (u32)(buf - &__clear_page_start)); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci pr_debug("\t.set push\n"); 3628c2ecf20Sopenharmony_ci pr_debug("\t.set noreorder\n"); 3638c2ecf20Sopenharmony_ci for (i = 0; i < (buf - &__clear_page_start); i++) 3648c2ecf20Sopenharmony_ci pr_debug("\t.word 0x%08x\n", (&__clear_page_start)[i]); 3658c2ecf20Sopenharmony_ci pr_debug("\t.set pop\n"); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void build_copy_load(u32 **buf, int reg, int off) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci if (cpu_has_64bit_gp_regs) { 3718c2ecf20Sopenharmony_ci uasm_i_ld(buf, reg, off, A1); 3728c2ecf20Sopenharmony_ci } else { 3738c2ecf20Sopenharmony_ci uasm_i_lw(buf, reg, off, A1); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void build_copy_store(u32 **buf, int reg, int off) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci if (cpu_has_64bit_gp_regs) { 3808c2ecf20Sopenharmony_ci uasm_i_sd(buf, reg, off, A0); 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci uasm_i_sw(buf, reg, off, A0); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic inline void build_copy_load_pref(u32 **buf, int off) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci if (off & cache_line_mask()) 3898c2ecf20Sopenharmony_ci return; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (pref_bias_copy_load) 3928c2ecf20Sopenharmony_ci _uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic inline void build_copy_store_pref(u32 **buf, int off) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci if (off & cache_line_mask()) 3988c2ecf20Sopenharmony_ci return; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (pref_bias_copy_store) { 4018c2ecf20Sopenharmony_ci _uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off, 4028c2ecf20Sopenharmony_ci A0); 4038c2ecf20Sopenharmony_ci } else if (cache_line_size == (half_copy_loop_size << 1)) { 4048c2ecf20Sopenharmony_ci if (cpu_has_cache_cdex_s) { 4058c2ecf20Sopenharmony_ci uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); 4068c2ecf20Sopenharmony_ci } else if (cpu_has_cache_cdex_p) { 4078c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V1_HIT_CACHEOP) && 4088c2ecf20Sopenharmony_ci cpu_is_r4600_v1_x()) { 4098c2ecf20Sopenharmony_ci uasm_i_nop(buf); 4108c2ecf20Sopenharmony_ci uasm_i_nop(buf); 4118c2ecf20Sopenharmony_ci uasm_i_nop(buf); 4128c2ecf20Sopenharmony_ci uasm_i_nop(buf); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && 4168c2ecf20Sopenharmony_ci cpu_is_r4600_v2_x()) 4178c2ecf20Sopenharmony_ci uasm_i_lw(buf, ZERO, ZERO, AT); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_civoid build_copy_page(void) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci int off; 4278c2ecf20Sopenharmony_ci u32 *buf = &__copy_page_start; 4288c2ecf20Sopenharmony_ci struct uasm_label *l = labels; 4298c2ecf20Sopenharmony_ci struct uasm_reloc *r = relocs; 4308c2ecf20Sopenharmony_ci int i; 4318c2ecf20Sopenharmony_ci static atomic_t run_once = ATOMIC_INIT(0); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (atomic_xchg(&run_once, 1)) { 4348c2ecf20Sopenharmony_ci return; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci memset(labels, 0, sizeof(labels)); 4388c2ecf20Sopenharmony_ci memset(relocs, 0, sizeof(relocs)); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci set_prefetch_parameters(); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* 4438c2ecf20Sopenharmony_ci * This algorithm makes the following assumptions: 4448c2ecf20Sopenharmony_ci * - All prefetch biases are multiples of 8 words. 4458c2ecf20Sopenharmony_ci * - The prefetch biases are less than one page. 4468c2ecf20Sopenharmony_ci * - The store prefetch bias isn't greater than the load 4478c2ecf20Sopenharmony_ci * prefetch bias. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci BUG_ON(pref_bias_copy_load % (8 * copy_word_size)); 4508c2ecf20Sopenharmony_ci BUG_ON(pref_bias_copy_store % (8 * copy_word_size)); 4518c2ecf20Sopenharmony_ci BUG_ON(PAGE_SIZE < pref_bias_copy_load); 4528c2ecf20Sopenharmony_ci BUG_ON(pref_bias_copy_store > pref_bias_copy_load); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci off = PAGE_SIZE - pref_bias_copy_load; 4558c2ecf20Sopenharmony_ci if (off > 0xffff || !pref_bias_copy_load) 4568c2ecf20Sopenharmony_ci pg_addiu(&buf, A2, A0, off); 4578c2ecf20Sopenharmony_ci else 4588c2ecf20Sopenharmony_ci uasm_i_ori(&buf, A2, A0, off); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && cpu_is_r4600_v2_x()) 4618c2ecf20Sopenharmony_ci uasm_i_lui(&buf, AT, uasm_rel_hi(0xa0000000)); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci off = cache_line_size ? min(8, pref_bias_copy_load / cache_line_size) * 4648c2ecf20Sopenharmony_ci cache_line_size : 0; 4658c2ecf20Sopenharmony_ci while (off) { 4668c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, -off); 4678c2ecf20Sopenharmony_ci off -= cache_line_size; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci off = cache_line_size ? min(8, pref_bias_copy_store / cache_line_size) * 4708c2ecf20Sopenharmony_ci cache_line_size : 0; 4718c2ecf20Sopenharmony_ci while (off) { 4728c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, -off); 4738c2ecf20Sopenharmony_ci off -= cache_line_size; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci uasm_l_copy_pref_both(&l, buf); 4768c2ecf20Sopenharmony_ci do { 4778c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off); 4788c2ecf20Sopenharmony_ci build_copy_load(&buf, T0, off); 4798c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off + copy_word_size); 4808c2ecf20Sopenharmony_ci build_copy_load(&buf, T1, off + copy_word_size); 4818c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off + 2 * copy_word_size); 4828c2ecf20Sopenharmony_ci build_copy_load(&buf, T2, off + 2 * copy_word_size); 4838c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off + 3 * copy_word_size); 4848c2ecf20Sopenharmony_ci build_copy_load(&buf, T3, off + 3 * copy_word_size); 4858c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off); 4868c2ecf20Sopenharmony_ci build_copy_store(&buf, T0, off); 4878c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + copy_word_size); 4888c2ecf20Sopenharmony_ci build_copy_store(&buf, T1, off + copy_word_size); 4898c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 2 * copy_word_size); 4908c2ecf20Sopenharmony_ci build_copy_store(&buf, T2, off + 2 * copy_word_size); 4918c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 3 * copy_word_size); 4928c2ecf20Sopenharmony_ci build_copy_store(&buf, T3, off + 3 * copy_word_size); 4938c2ecf20Sopenharmony_ci off += 4 * copy_word_size; 4948c2ecf20Sopenharmony_ci } while (off < half_copy_loop_size); 4958c2ecf20Sopenharmony_ci pg_addiu(&buf, A1, A1, 2 * off); 4968c2ecf20Sopenharmony_ci pg_addiu(&buf, A0, A0, 2 * off); 4978c2ecf20Sopenharmony_ci off = -off; 4988c2ecf20Sopenharmony_ci do { 4998c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off); 5008c2ecf20Sopenharmony_ci build_copy_load(&buf, T0, off); 5018c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off + copy_word_size); 5028c2ecf20Sopenharmony_ci build_copy_load(&buf, T1, off + copy_word_size); 5038c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off + 2 * copy_word_size); 5048c2ecf20Sopenharmony_ci build_copy_load(&buf, T2, off + 2 * copy_word_size); 5058c2ecf20Sopenharmony_ci build_copy_load_pref(&buf, off + 3 * copy_word_size); 5068c2ecf20Sopenharmony_ci build_copy_load(&buf, T3, off + 3 * copy_word_size); 5078c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off); 5088c2ecf20Sopenharmony_ci build_copy_store(&buf, T0, off); 5098c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + copy_word_size); 5108c2ecf20Sopenharmony_ci build_copy_store(&buf, T1, off + copy_word_size); 5118c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 2 * copy_word_size); 5128c2ecf20Sopenharmony_ci build_copy_store(&buf, T2, off + 2 * copy_word_size); 5138c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 3 * copy_word_size); 5148c2ecf20Sopenharmony_ci if (off == -(4 * copy_word_size)) 5158c2ecf20Sopenharmony_ci uasm_il_bne(&buf, &r, A2, A0, label_copy_pref_both); 5168c2ecf20Sopenharmony_ci build_copy_store(&buf, T3, off + 3 * copy_word_size); 5178c2ecf20Sopenharmony_ci off += 4 * copy_word_size; 5188c2ecf20Sopenharmony_ci } while (off < 0); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (pref_bias_copy_load - pref_bias_copy_store) { 5218c2ecf20Sopenharmony_ci pg_addiu(&buf, A2, A0, 5228c2ecf20Sopenharmony_ci pref_bias_copy_load - pref_bias_copy_store); 5238c2ecf20Sopenharmony_ci uasm_l_copy_pref_store(&l, buf); 5248c2ecf20Sopenharmony_ci off = 0; 5258c2ecf20Sopenharmony_ci do { 5268c2ecf20Sopenharmony_ci build_copy_load(&buf, T0, off); 5278c2ecf20Sopenharmony_ci build_copy_load(&buf, T1, off + copy_word_size); 5288c2ecf20Sopenharmony_ci build_copy_load(&buf, T2, off + 2 * copy_word_size); 5298c2ecf20Sopenharmony_ci build_copy_load(&buf, T3, off + 3 * copy_word_size); 5308c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off); 5318c2ecf20Sopenharmony_ci build_copy_store(&buf, T0, off); 5328c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + copy_word_size); 5338c2ecf20Sopenharmony_ci build_copy_store(&buf, T1, off + copy_word_size); 5348c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 2 * copy_word_size); 5358c2ecf20Sopenharmony_ci build_copy_store(&buf, T2, off + 2 * copy_word_size); 5368c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 3 * copy_word_size); 5378c2ecf20Sopenharmony_ci build_copy_store(&buf, T3, off + 3 * copy_word_size); 5388c2ecf20Sopenharmony_ci off += 4 * copy_word_size; 5398c2ecf20Sopenharmony_ci } while (off < half_copy_loop_size); 5408c2ecf20Sopenharmony_ci pg_addiu(&buf, A1, A1, 2 * off); 5418c2ecf20Sopenharmony_ci pg_addiu(&buf, A0, A0, 2 * off); 5428c2ecf20Sopenharmony_ci off = -off; 5438c2ecf20Sopenharmony_ci do { 5448c2ecf20Sopenharmony_ci build_copy_load(&buf, T0, off); 5458c2ecf20Sopenharmony_ci build_copy_load(&buf, T1, off + copy_word_size); 5468c2ecf20Sopenharmony_ci build_copy_load(&buf, T2, off + 2 * copy_word_size); 5478c2ecf20Sopenharmony_ci build_copy_load(&buf, T3, off + 3 * copy_word_size); 5488c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off); 5498c2ecf20Sopenharmony_ci build_copy_store(&buf, T0, off); 5508c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + copy_word_size); 5518c2ecf20Sopenharmony_ci build_copy_store(&buf, T1, off + copy_word_size); 5528c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 2 * copy_word_size); 5538c2ecf20Sopenharmony_ci build_copy_store(&buf, T2, off + 2 * copy_word_size); 5548c2ecf20Sopenharmony_ci build_copy_store_pref(&buf, off + 3 * copy_word_size); 5558c2ecf20Sopenharmony_ci if (off == -(4 * copy_word_size)) 5568c2ecf20Sopenharmony_ci uasm_il_bne(&buf, &r, A2, A0, 5578c2ecf20Sopenharmony_ci label_copy_pref_store); 5588c2ecf20Sopenharmony_ci build_copy_store(&buf, T3, off + 3 * copy_word_size); 5598c2ecf20Sopenharmony_ci off += 4 * copy_word_size; 5608c2ecf20Sopenharmony_ci } while (off < 0); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (pref_bias_copy_store) { 5648c2ecf20Sopenharmony_ci pg_addiu(&buf, A2, A0, pref_bias_copy_store); 5658c2ecf20Sopenharmony_ci uasm_l_copy_nopref(&l, buf); 5668c2ecf20Sopenharmony_ci off = 0; 5678c2ecf20Sopenharmony_ci do { 5688c2ecf20Sopenharmony_ci build_copy_load(&buf, T0, off); 5698c2ecf20Sopenharmony_ci build_copy_load(&buf, T1, off + copy_word_size); 5708c2ecf20Sopenharmony_ci build_copy_load(&buf, T2, off + 2 * copy_word_size); 5718c2ecf20Sopenharmony_ci build_copy_load(&buf, T3, off + 3 * copy_word_size); 5728c2ecf20Sopenharmony_ci build_copy_store(&buf, T0, off); 5738c2ecf20Sopenharmony_ci build_copy_store(&buf, T1, off + copy_word_size); 5748c2ecf20Sopenharmony_ci build_copy_store(&buf, T2, off + 2 * copy_word_size); 5758c2ecf20Sopenharmony_ci build_copy_store(&buf, T3, off + 3 * copy_word_size); 5768c2ecf20Sopenharmony_ci off += 4 * copy_word_size; 5778c2ecf20Sopenharmony_ci } while (off < half_copy_loop_size); 5788c2ecf20Sopenharmony_ci pg_addiu(&buf, A1, A1, 2 * off); 5798c2ecf20Sopenharmony_ci pg_addiu(&buf, A0, A0, 2 * off); 5808c2ecf20Sopenharmony_ci off = -off; 5818c2ecf20Sopenharmony_ci do { 5828c2ecf20Sopenharmony_ci build_copy_load(&buf, T0, off); 5838c2ecf20Sopenharmony_ci build_copy_load(&buf, T1, off + copy_word_size); 5848c2ecf20Sopenharmony_ci build_copy_load(&buf, T2, off + 2 * copy_word_size); 5858c2ecf20Sopenharmony_ci build_copy_load(&buf, T3, off + 3 * copy_word_size); 5868c2ecf20Sopenharmony_ci build_copy_store(&buf, T0, off); 5878c2ecf20Sopenharmony_ci build_copy_store(&buf, T1, off + copy_word_size); 5888c2ecf20Sopenharmony_ci build_copy_store(&buf, T2, off + 2 * copy_word_size); 5898c2ecf20Sopenharmony_ci if (off == -(4 * copy_word_size)) 5908c2ecf20Sopenharmony_ci uasm_il_bne(&buf, &r, A2, A0, 5918c2ecf20Sopenharmony_ci label_copy_nopref); 5928c2ecf20Sopenharmony_ci build_copy_store(&buf, T3, off + 3 * copy_word_size); 5938c2ecf20Sopenharmony_ci off += 4 * copy_word_size; 5948c2ecf20Sopenharmony_ci } while (off < 0); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci uasm_i_jr(&buf, RA); 5988c2ecf20Sopenharmony_ci uasm_i_nop(&buf); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci BUG_ON(buf > &__copy_page_end); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci uasm_resolve_relocs(relocs, labels); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci pr_debug("Synthesized copy page handler (%u instructions).\n", 6058c2ecf20Sopenharmony_ci (u32)(buf - &__copy_page_start)); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci pr_debug("\t.set push\n"); 6088c2ecf20Sopenharmony_ci pr_debug("\t.set noreorder\n"); 6098c2ecf20Sopenharmony_ci for (i = 0; i < (buf - &__copy_page_start); i++) 6108c2ecf20Sopenharmony_ci pr_debug("\t.word 0x%08x\n", (&__copy_page_start)[i]); 6118c2ecf20Sopenharmony_ci pr_debug("\t.set pop\n"); 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci#ifdef CONFIG_SIBYTE_DMA_PAGEOPS 6158c2ecf20Sopenharmony_ciextern void clear_page_cpu(void *page); 6168c2ecf20Sopenharmony_ciextern void copy_page_cpu(void *to, void *from); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* 6198c2ecf20Sopenharmony_ci * Pad descriptors to cacheline, since each is exclusively owned by a 6208c2ecf20Sopenharmony_ci * particular CPU. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_cistruct dmadscr { 6238c2ecf20Sopenharmony_ci u64 dscr_a; 6248c2ecf20Sopenharmony_ci u64 dscr_b; 6258c2ecf20Sopenharmony_ci u64 pad_a; 6268c2ecf20Sopenharmony_ci u64 pad_b; 6278c2ecf20Sopenharmony_ci} ____cacheline_aligned_in_smp page_descr[DM_NUM_CHANNELS]; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_civoid clear_page(void *page) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci u64 to_phys = CPHYSADDR((unsigned long)page); 6328c2ecf20Sopenharmony_ci unsigned int cpu = smp_processor_id(); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* if the page is not in KSEG0, use old way */ 6358c2ecf20Sopenharmony_ci if ((long)KSEGX((unsigned long)page) != (long)CKSEG0) 6368c2ecf20Sopenharmony_ci return clear_page_cpu(page); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM | 6398c2ecf20Sopenharmony_ci M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT; 6408c2ecf20Sopenharmony_ci page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); 6418c2ecf20Sopenharmony_ci __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * Don't really want to do it this way, but there's no 6458c2ecf20Sopenharmony_ci * reliable way to delay completion detection. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_ci while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) 6488c2ecf20Sopenharmony_ci & M_DM_DSCR_BASE_INTERRUPT)) 6498c2ecf20Sopenharmony_ci ; 6508c2ecf20Sopenharmony_ci __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clear_page); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_civoid copy_page(void *to, void *from) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci u64 from_phys = CPHYSADDR((unsigned long)from); 6578c2ecf20Sopenharmony_ci u64 to_phys = CPHYSADDR((unsigned long)to); 6588c2ecf20Sopenharmony_ci unsigned int cpu = smp_processor_id(); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* if any page is not in KSEG0, use old way */ 6618c2ecf20Sopenharmony_ci if ((long)KSEGX((unsigned long)to) != (long)CKSEG0 6628c2ecf20Sopenharmony_ci || (long)KSEGX((unsigned long)from) != (long)CKSEG0) 6638c2ecf20Sopenharmony_ci return copy_page_cpu(to, from); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST | 6668c2ecf20Sopenharmony_ci M_DM_DSCRA_INTERRUPT; 6678c2ecf20Sopenharmony_ci page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); 6688c2ecf20Sopenharmony_ci __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* 6718c2ecf20Sopenharmony_ci * Don't really want to do it this way, but there's no 6728c2ecf20Sopenharmony_ci * reliable way to delay completion detection. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_ci while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) 6758c2ecf20Sopenharmony_ci & M_DM_DSCR_BASE_INTERRUPT)) 6768c2ecf20Sopenharmony_ci ; 6778c2ecf20Sopenharmony_ci __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(copy_page); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci#endif /* CONFIG_SIBYTE_DMA_PAGEOPS */ 682