1 // SPDX-License-Identifier: GPL-2.0-only << 2 /* 1 /* 3 * Copyright (C) 2012 Regents of the Universit !! 2 * This file is subject to the terms and conditions of the GNU General Public >> 3 * License. See the file "COPYING" in the main directory of this archive >> 4 * for more details. >> 5 * >> 6 * Copyright (C) 1994 by Waldorf Electronics >> 7 * Copyright (C) 1995 - 2000, 01, 03 by Ralf Baechle >> 8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. >> 9 * Copyright (C) 2007, 2014 Maciej W. Rozycki 4 */ 10 */ 5 << 6 #include <linux/delay.h> 11 #include <linux/delay.h> 7 #include <linux/math.h> << 8 #include <linux/param.h> << 9 #include <linux/timex.h> << 10 #include <linux/types.h> << 11 #include <linux/export.h> 12 #include <linux/export.h> >> 13 #include <linux/param.h> >> 14 #include <linux/smp.h> >> 15 #include <linux/stringify.h> 12 16 13 #include <asm/processor.h> !! 17 #include <asm/asm.h> 14 !! 18 #include <asm/compiler.h> 15 /* << 16 * This is copies from arch/arm/include/asm/de << 17 * << 18 * Loop (or tick) based delay: << 19 * << 20 * loops = loops_per_jiffy * jiffies_per_sec * << 21 * << 22 * where: << 23 * << 24 * jiffies_per_sec = HZ << 25 * us_per_sec = 1000000 << 26 * << 27 * Therefore the constant part is HZ / 1000000 << 28 * fractional number. To make this usable with << 29 * scale up this constant by 2^31, perform the << 30 * and scale the result back down by 2^31 with << 31 * << 32 * loops = (loops_per_jiffy * delay_us * UDELA << 33 * << 34 * where: << 35 * << 36 * UDELAY_MULT = 2^31 * HZ / 1000000 << 37 * = (2^31 / 1000000) * HZ << 38 * = 2147.483648 * HZ << 39 * = 2147 * HZ + 483648 * HZ / 100 << 40 * << 41 * 31 is the biggest scale shift value that wo << 42 * delay_us * UDELAY_MULT assuming HZ <= 1000 << 43 */ << 44 #define MAX_UDELAY_US 2000 << 45 #define MAX_UDELAY_HZ 1000 << 46 #define UDELAY_MULT (2147UL * HZ + 483648U << 47 #define UDELAY_SHIFT 31 << 48 19 49 #if HZ > MAX_UDELAY_HZ !! 20 #ifndef CONFIG_CPU_DADDI_WORKAROUNDS 50 #error "HZ > MAX_UDELAY_HZ" !! 21 #define GCC_DADDI_IMM_ASM() "I" >> 22 #else >> 23 #define GCC_DADDI_IMM_ASM() "r" 51 #endif 24 #endif 52 25 >> 26 #ifndef CONFIG_HAVE_PLAT_DELAY >> 27 >> 28 void __delay(unsigned long loops) >> 29 { >> 30 __asm__ __volatile__ ( >> 31 " .set noreorder \n" >> 32 " .align 3 \n" >> 33 "1: bnez %0, 1b \n" >> 34 " " __stringify(LONG_SUBU) " %0, %1 \n" >> 35 " .set reorder \n" >> 36 : "=r" (loops) >> 37 : GCC_DADDI_IMM_ASM() (1), "" (loops)); >> 38 } >> 39 EXPORT_SYMBOL(__delay); >> 40 53 /* 41 /* 54 * RISC-V supports both UDELAY and NDELAY. Th !! 42 * Division by multiplication: you don't have to worry about 55 * but with different constants. I added 10 b !! 43 * loss of precision. 56 * the result is that I need a 64-bit multiply << 57 * platforms. << 58 * << 59 * NDELAY_MULT = 2^41 * HZ / 1000000000 << 60 * = (2^41 / 1000000000) * HZ << 61 * = 2199.02325555 * HZ << 62 * = 2199 * HZ + 23255550 * HZ / 1 << 63 * 44 * 64 * The maximum here is to avoid 64-bit overflo !! 45 * Use only for very small delays ( < 1 msec). Should probably use a 65 * won't happen. !! 46 * lookup table, really, as the multiplications take much too long with >> 47 * short delays. This is a "reasonable" implementation, though (and the >> 48 * first constant multiplications gets optimized away if the delay is >> 49 * a constant) 66 */ 50 */ 67 #define MAX_NDELAY_NS (1ULL << 42) << 68 #define MAX_NDELAY_HZ MAX_UDELAY_HZ << 69 #define NDELAY_MULT ((unsigned long long)( << 70 #define NDELAY_SHIFT 41 << 71 51 72 #if HZ > MAX_NDELAY_HZ !! 52 void __udelay(unsigned long us) 73 #error "HZ > MAX_NDELAY_HZ" << 74 #endif << 75 << 76 void __delay(unsigned long cycles) << 77 { 53 { 78 u64 t0 = get_cycles(); !! 54 unsigned int lpj = raw_current_cpu_data.udelay_val; 79 55 80 while ((unsigned long)(get_cycles() - !! 56 __delay((us * 0x000010c7ull * HZ * lpj) >> 32); 81 cpu_relax(); << 82 } 57 } 83 EXPORT_SYMBOL(__delay); !! 58 EXPORT_SYMBOL(__udelay); 84 59 85 void udelay(unsigned long usecs) !! 60 void __ndelay(unsigned long ns) 86 { 61 { 87 u64 ucycles = (u64)usecs * lpj_fine * !! 62 unsigned int lpj = raw_current_cpu_data.udelay_val; 88 u64 n; << 89 << 90 if (unlikely(usecs > MAX_UDELAY_US)) { << 91 n = (u64)usecs * riscv_timebas << 92 do_div(n, 1000000); << 93 << 94 __delay(n); << 95 return; << 96 } << 97 63 98 __delay(ucycles >> UDELAY_SHIFT); !! 64 __delay((ns * 0x00000005ull * HZ * lpj) >> 32); 99 } 65 } 100 EXPORT_SYMBOL(udelay); !! 66 EXPORT_SYMBOL(__ndelay); 101 67 102 void ndelay(unsigned long nsecs) !! 68 #endif 103 { << 104 /* << 105 * This doesn't bother checking for ov << 106 * an hour) of delay. << 107 */ << 108 unsigned long long ncycles = nsecs * l << 109 __delay(ncycles >> NDELAY_SHIFT); << 110 } << 111 EXPORT_SYMBOL(ndelay); << 112 69
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.