/** * hrtimer_forward - forward the timer expiry * @timer: hrtimer to forward * @now: forward past this time * @interval: the interval to forward * * Forward the timer expiry so it will expire in the future. * Returns the number of overruns. */ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) { u64 orun = 1; ktime_t delta; delta = ktime_sub(now, hrtimer_get_expires(timer)); if (delta.tv64 < 0) return 0; if (interval.tv64 < timer->base->resolution.tv64) interval.tv64 = timer->base->resolution.tv64; if (unlikely(delta.tv64 >= interval.tv64)) { s64 incr = ktime_to_ns(interval); orun = ktime_divns(delta, incr); hrtimer_add_expires_ns(timer, incr * orun); if (hrtimer_get_expires_tv64(timer) > now.tv64) return orun; /* * This (and the ktime_add() below) is the * correction for exact: */ orun++; } hrtimer_add_expires(timer, interval); return orun; }
/** * hrtimer_forward - forward the timer expiry * @timer: hrtimer to forward * @now: forward past this time * @interval: the interval to forward * * Forward the timer expiry so it will expire in the future. * Returns the number of overruns. * * Can be safely called from the callback function of @timer. If * called from other contexts @timer must neither be enqueued nor * running the callback and the caller needs to take care of * serialization. * * Note: This only updates the timer expiry value and does not requeue * the timer. */ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) { u64 orun = 1; ktime_t delta; delta = ktime_sub(now, hrtimer_get_expires(timer)); if (delta < 0) return 0; if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED)) return 0; if (interval < hrtimer_resolution) interval = hrtimer_resolution; if (unlikely(delta >= interval)) { s64 incr = ktime_to_ns(interval); orun = ktime_divns(delta, incr); hrtimer_add_expires_ns(timer, incr * orun); if (hrtimer_get_expires_tv64(timer) > now) return orun; /* * This (and the ktime_add() below) is the * correction for exact: */ orun++; } hrtimer_add_expires(timer, interval); return orun; }
static enum hrtimer_restart kbasep_pm_do_gpu_poweroff_callback(struct hrtimer *timer) { kbase_device *kbdev; kbdev = container_of(timer, kbase_device, pm.gpu_poweroff_timer); /* It is safe for this call to do nothing if the work item is already queued. * The worker function will read the must up-to-date state of kbdev->pm.gpu_poweroff_pending * under lock. * * If a state change occurs while the worker function is processing, this * call will succeed as a work item can be requeued once it has started * processing. */ if (kbdev->pm.gpu_poweroff_pending) queue_work(kbdev->pm.gpu_poweroff_wq, &kbdev->pm.gpu_poweroff_work); if (kbdev->pm.shader_poweroff_pending) { unsigned long flags; spin_lock_irqsave(&kbdev->pm.power_change_lock, flags); if (kbdev->pm.shader_poweroff_pending) { kbdev->pm.shader_poweroff_pending_time--; KBASE_DEBUG_ASSERT(kbdev->pm.shader_poweroff_pending_time >= 0); if (kbdev->pm.shader_poweroff_pending_time == 0) { u64 prev_shader_state = kbdev->pm.desired_shader_state; kbdev->pm.desired_shader_state &= ~kbdev->pm.shader_poweroff_pending; kbdev->pm.shader_poweroff_pending = 0; if (prev_shader_state != kbdev->pm.desired_shader_state || kbdev->pm.ca_in_transition != MALI_FALSE) { mali_bool cores_are_available; KBASE_TIMELINE_PM_CHECKTRANS(kbdev, SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_START); cores_are_available = kbase_pm_check_transitions_nolock(kbdev); KBASE_TIMELINE_PM_CHECKTRANS(kbdev, SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_END); /* Don't need 'cores_are_available', because we don't return anything */ CSTD_UNUSED(cores_are_available); } } } spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags); } hrtimer_add_expires(timer, kbdev->pm.gpu_poweroff_time); return HRTIMER_RESTART; }
/* timr->it_lock is taken. */ static int common_timer_set(struct k_itimer *timr, int flags, struct itimerspec *new_setting, struct itimerspec *old_setting) { struct hrtimer *timer = &timr->it.real.timer; enum hrtimer_mode mode; if (old_setting) common_timer_get(timr, old_setting); /* disable the timer */ timr->it.real.interval.tv64 = 0; /* * careful here. If smp we could be in the "fire" routine which will * be spinning as we hold the lock. But this is ONLY an SMP issue. */ if (hrtimer_try_to_cancel(timer) < 0) return TIMER_RETRY; timr->it_requeue_pending = (timr->it_requeue_pending + 2) & ~REQUEUE_PENDING; timr->it_overrun_last = 0; /* switch off the timer when it_value is zero */ if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec) return 0; mode = flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); timr->it.real.timer.function = posix_timer_fn; hrtimer_set_expires(timer, timespec_to_ktime(new_setting->it_value)); /* Convert interval */ timr->it.real.interval = timespec_to_ktime(new_setting->it_interval); /* SIGEV_NONE timers are not queued ! See common_timer_get */ if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { /* Setup correct expiry time for relative timers */ if (mode == HRTIMER_MODE_REL) { hrtimer_add_expires(timer, timer->base->get_time()); } return 0; } hrtimer_start_expires(timer, mode); return 0; }
static int common_timer_set(struct k_itimer *timr, int flags, struct itimerspec *new_setting, struct itimerspec *old_setting) { struct hrtimer *timer = &timr->it.real.timer; enum hrtimer_mode mode; if (old_setting) common_timer_get(timr, old_setting); timr->it.real.interval.tv64 = 0; if (hrtimer_try_to_cancel(timer) < 0) return TIMER_RETRY; timr->it_requeue_pending = (timr->it_requeue_pending + 2) & ~REQUEUE_PENDING; timr->it_overrun_last = 0; if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec) return 0; mode = flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); timr->it.real.timer.function = posix_timer_fn; hrtimer_set_expires(timer, timespec_to_ktime(new_setting->it_value)); timr->it.real.interval = timespec_to_ktime(new_setting->it_interval); if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { if (mode == HRTIMER_MODE_REL) { hrtimer_add_expires(timer, timer->base->get_time()); } return 0; } hrtimer_start_expires(timer, mode); return 0; }