LCOV - code coverage report
Current view: top level - kernel/time - tick-broadcast-hrtimer.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 14 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 4 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Emulate a local clock event device via a pseudo clock device.
       4             :  */
       5             : #include <linux/cpu.h>
       6             : #include <linux/err.h>
       7             : #include <linux/hrtimer.h>
       8             : #include <linux/interrupt.h>
       9             : #include <linux/percpu.h>
      10             : #include <linux/profile.h>
      11             : #include <linux/clockchips.h>
      12             : #include <linux/sched.h>
      13             : #include <linux/smp.h>
      14             : #include <linux/module.h>
      15             : 
      16             : #include "tick-internal.h"
      17             : 
      18             : static struct hrtimer bctimer;
      19             : 
      20           0 : static int bc_shutdown(struct clock_event_device *evt)
      21             : {
      22             :         /*
      23             :          * Note, we cannot cancel the timer here as we might
      24             :          * run into the following live lock scenario:
      25             :          *
      26             :          * cpu 0                cpu1
      27             :          * lock(broadcast_lock);
      28             :          *                      hrtimer_interrupt()
      29             :          *                      bc_handler()
      30             :          *                         tick_handle_oneshot_broadcast();
      31             :          *                          lock(broadcast_lock);
      32             :          * hrtimer_cancel()
      33             :          *  wait_for_callback()
      34             :          */
      35           0 :         hrtimer_try_to_cancel(&bctimer);
      36           0 :         return 0;
      37             : }
      38             : 
      39             : /*
      40             :  * This is called from the guts of the broadcast code when the cpu
      41             :  * which is about to enter idle has the earliest broadcast timer event.
      42             :  */
      43           0 : static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
      44             : {
      45             :         /*
      46             :          * This is called either from enter/exit idle code or from the
      47             :          * broadcast handler. In all cases tick_broadcast_lock is held.
      48             :          *
      49             :          * hrtimer_cancel() cannot be called here neither from the
      50             :          * broadcast handler nor from the enter/exit idle code. The idle
      51             :          * code can run into the problem described in bc_shutdown() and the
      52             :          * broadcast handler cannot wait for itself to complete for obvious
      53             :          * reasons.
      54             :          *
      55             :          * Each caller tries to arm the hrtimer on its own CPU, but if the
      56             :          * hrtimer callbback function is currently running, then
      57             :          * hrtimer_start() cannot move it and the timer stays on the CPU on
      58             :          * which it is assigned at the moment.
      59             :          *
      60             :          * As this can be called from idle code, the hrtimer_start()
      61             :          * invocation has to be wrapped with RCU_NONIDLE() as
      62             :          * hrtimer_start() can call into tracing.
      63             :          */
      64           0 :         RCU_NONIDLE( {
      65             :                 hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED_HARD);
      66             :                 /*
      67             :                  * The core tick broadcast mode expects bc->bound_on to be set
      68             :                  * correctly to prevent a CPU which has the broadcast hrtimer
      69             :                  * armed from going deep idle.
      70             :                  *
      71             :                  * As tick_broadcast_lock is held, nothing can change the cpu
      72             :                  * base which was just established in hrtimer_start() above. So
      73             :                  * the below access is safe even without holding the hrtimer
      74             :                  * base lock.
      75             :                  */
      76             :                 bc->bound_on = bctimer.base->cpu_base->cpu;
      77             :         } );
      78           0 :         return 0;
      79             : }
      80             : 
      81             : static struct clock_event_device ce_broadcast_hrtimer = {
      82             :         .name                   = "bc_hrtimer",
      83             :         .set_state_shutdown     = bc_shutdown,
      84             :         .set_next_ktime         = bc_set_next,
      85             :         .features               = CLOCK_EVT_FEAT_ONESHOT |
      86             :                                   CLOCK_EVT_FEAT_KTIME |
      87             :                                   CLOCK_EVT_FEAT_HRTIMER,
      88             :         .rating                 = 0,
      89             :         .bound_on               = -1,
      90             :         .min_delta_ns           = 1,
      91             :         .max_delta_ns           = KTIME_MAX,
      92             :         .min_delta_ticks        = 1,
      93             :         .max_delta_ticks        = ULONG_MAX,
      94             :         .mult                   = 1,
      95             :         .shift                  = 0,
      96             :         .cpumask                = cpu_possible_mask,
      97             : };
      98             : 
      99           0 : static enum hrtimer_restart bc_handler(struct hrtimer *t)
     100             : {
     101           0 :         ce_broadcast_hrtimer.event_handler(&ce_broadcast_hrtimer);
     102             : 
     103           0 :         return HRTIMER_NORESTART;
     104             : }
     105             : 
     106           0 : void tick_setup_hrtimer_broadcast(void)
     107             : {
     108           0 :         hrtimer_init(&bctimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
     109           0 :         bctimer.function = bc_handler;
     110           0 :         clockevents_register_device(&ce_broadcast_hrtimer);
     111           0 : }

Generated by: LCOV version 1.14