LCOV - code coverage report
Current view: top level - arch/arm/lib - delay.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 35 40 87.5 %
Date: 2020-09-30 20:25:40 Functions: 6 7 85.7 %
Branches: 13 20 65.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Delay loops based on the OpenRISC implementation.
       4                 :            :  *
       5                 :            :  * Copyright (C) 2012 ARM Limited
       6                 :            :  *
       7                 :            :  * Author: Will Deacon <will.deacon@arm.com>
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/clocksource.h>
      11                 :            : #include <linux/delay.h>
      12                 :            : #include <linux/init.h>
      13                 :            : #include <linux/kernel.h>
      14                 :            : #include <linux/module.h>
      15                 :            : #include <linux/timex.h>
      16                 :            : 
      17                 :            : /*
      18                 :            :  * Default to the loop-based delay implementation.
      19                 :            :  */
      20                 :            : struct arm_delay_ops arm_delay_ops __ro_after_init = {
      21                 :            :         .delay          = __loop_delay,
      22                 :            :         .const_udelay   = __loop_const_udelay,
      23                 :            :         .udelay         = __loop_udelay,
      24                 :            : };
      25                 :            : 
      26                 :            : static const struct delay_timer *delay_timer;
      27                 :            : static bool delay_calibrated;
      28                 :            : static u64 delay_res;
      29                 :            : 
      30                 :   18336871 : int read_current_timer(unsigned long *timer_val)
      31                 :            : {
      32   [ +  -  +  +  :  788374586 :         if (!delay_timer)
                   +  + ]
      33                 :            :                 return -ENXIO;
      34                 :            : 
      35                 :  788338103 :         *timer_val = delay_timer->read_current_timer();
      36                 :   18300940 :         return 0;
      37                 :            : }
      38                 :            : EXPORT_SYMBOL_GPL(read_current_timer);
      39                 :            : 
      40                 :            : static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
      41                 :            : {
      42                 :        207 :         return (cyc * mult) >> shift;
      43                 :            : }
      44                 :            : 
      45                 :     133465 : static void __timer_delay(unsigned long cycles)
      46                 :            : {
      47         [ +  - ]:     133466 :         cycles_t start = get_cycles();
      48                 :            : 
      49   [ +  +  +  + ]:  770037075 :         while ((get_cycles() - start) < cycles)
      50                 :  769770143 :                 cpu_relax();
      51                 :     133466 : }
      52                 :            : 
      53                 :     115954 : static void __timer_const_udelay(unsigned long xloops)
      54                 :            : {
      55                 :     133466 :         unsigned long long loops = xloops;
      56                 :     133466 :         loops *= arm_delay_ops.ticks_per_jiffy;
      57                 :     133466 :         __timer_delay(loops >> UDELAY_SHIFT);
      58                 :     115954 : }
      59                 :            : 
      60                 :      17512 : static void __timer_udelay(unsigned long usecs)
      61                 :            : {
      62                 :      17512 :         __timer_const_udelay(usecs * UDELAY_MULT);
      63                 :      17512 : }
      64                 :            : 
      65                 :        207 : void __init register_current_timer_delay(const struct delay_timer *timer)
      66                 :            : {
      67                 :            :         u32 new_mult, new_shift;
      68                 :            :         u64 res;
      69                 :            : 
      70                 :        207 :         clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq,
      71                 :            :                                NSEC_PER_SEC, 3600);
      72                 :        207 :         res = cyc_to_ns(1ULL, new_mult, new_shift);
      73                 :            : 
      74         [ -  + ]:        207 :         if (res > 1000) {
      75                 :          0 :                 pr_err("Ignoring delay timer %ps, which has insufficient resolution of %lluns\n",
      76                 :            :                         timer, res);
      77                 :        207 :                 return;
      78                 :            :         }
      79                 :            : 
      80   [ +  -  -  +  :        207 :         if (!delay_calibrated && (!delay_res || (res < delay_res))) {
                   #  # ]
      81                 :        207 :                 pr_info("Switching to timer-based delay loop, resolution %lluns\n", res);
      82                 :        207 :                 delay_timer                     = timer;
      83                 :        207 :                 lpj_fine                        = timer->freq / HZ;
      84                 :        207 :                 delay_res                       = res;
      85                 :            : 
      86                 :            :                 /* cpufreq may scale loops_per_jiffy, so keep a private copy */
      87                 :        207 :                 arm_delay_ops.ticks_per_jiffy   = lpj_fine;
      88                 :        207 :                 arm_delay_ops.delay             = __timer_delay;
      89                 :        207 :                 arm_delay_ops.const_udelay      = __timer_const_udelay;
      90                 :        207 :                 arm_delay_ops.udelay            = __timer_udelay;
      91                 :            :         } else {
      92                 :          0 :                 pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
      93                 :            :         }
      94                 :            : }
      95                 :            : 
      96                 :        621 : unsigned long calibrate_delay_is_known(void)
      97                 :            : {
      98                 :        621 :         delay_calibrated = true;
      99                 :        621 :         return lpj_fine;
     100                 :            : }
     101                 :            : 
     102                 :          0 : void calibration_delay_done(void)
     103                 :            : {
     104                 :          0 :         delay_calibrated = true;
     105                 :          0 : }

Generated by: LCOV version 1.14