mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
parent
db90656483
commit
40a5eabf88
@ -28,6 +28,8 @@ unsigned long long lx_emul_time_counter(void);
|
||||
|
||||
void lx_emul_time_handle(void);
|
||||
|
||||
void lx_emul_force_jiffies_update(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -131,3 +131,112 @@ void lx_emul_register_of_clk_initcall(char const *compat, void *fn)
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The functions lx_emul_force_jiffies_update, lx_clockevents_program_event
|
||||
* and lx_clockevents_program_event implemented here are stripped down
|
||||
* versions of the Linux internal time handling code, when clock is used in
|
||||
* periodic mode.
|
||||
*
|
||||
* Normally time proceeds due to
|
||||
* -> lx_emul/shadow/kernel/sched/core.c calls lx_emul_time_handle()
|
||||
* -> repos/dde_linux/src/lib/lx_emul/clocksource.c:lx_emul_time_handle() calls
|
||||
* -> dde_clock_event_device->event_handle() == tick_handle_periodic()
|
||||
* -> kernel/time/tick-common.c -> tick_handle_periodic()
|
||||
* -> kernel/time/clockevents.c -> clockevents_program_event()
|
||||
* -> which fast forwards jiffies in a loop until it matches wall clock
|
||||
*
|
||||
* lx_emul_force_jiffies_update can be used to update jiffies to current,
|
||||
* before invoking schedule_timeout(), which expects current jiffies values.
|
||||
* Without current jiffies, the programmed timeouts are too short, which leads
|
||||
* to timeouts firing too early.
|
||||
*/
|
||||
|
||||
|
||||
/* kernel/time/timekeeping.h */
|
||||
extern int timekeeping_valid_for_hres(void);
|
||||
extern void do_timer(unsigned long ticks);
|
||||
|
||||
|
||||
/**
|
||||
* based on kernel/time/clockevents.c clockevents_program_event()
|
||||
*/
|
||||
static int lx_clockevents_program_event(struct clock_event_device *dev,
|
||||
ktime_t expires)
|
||||
{
|
||||
int64_t delta;
|
||||
|
||||
if (WARN_ON_ONCE(expires < 0))
|
||||
return 0;
|
||||
|
||||
dev->next_event = expires;
|
||||
|
||||
if (clockevent_state_shutdown(dev))
|
||||
return 0;
|
||||
|
||||
if (dev->features & CLOCK_EVT_FEAT_KTIME)
|
||||
return 0;
|
||||
|
||||
delta = ktime_to_ns(ktime_sub(expires, ktime_get()));
|
||||
if (delta <= 0) {
|
||||
int res = -ETIME;
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* private kernel/time header needed for internal functions
|
||||
* used in lx_emul_force_jiffies_update
|
||||
*/
|
||||
#include <../kernel/time/tick-internal.h>
|
||||
|
||||
/**
|
||||
* based on kernel/time/tick-common.c tick_handle_periodic()
|
||||
*/
|
||||
void lx_emul_force_jiffies_update(void)
|
||||
{
|
||||
struct clock_event_device *dev = dde_clock_event_device;
|
||||
|
||||
ktime_t next = dev->next_event;
|
||||
|
||||
#if defined(CONFIG_HIGH_RES_TIMERS) || defined(CONFIG_NO_HZ_COMMON)
|
||||
/*
|
||||
* The cpu might have transitioned to HIGHRES or NOHZ mode via
|
||||
* update_process_times() -> run_local_timers() ->
|
||||
* hrtimer_run_queues().
|
||||
*/
|
||||
if (dev->event_handler != tick_handle_periodic)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!clockevent_state_oneshot(dev))
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Setup the next period for devices, which do not have
|
||||
* periodic mode:
|
||||
*/
|
||||
next = ktime_add_ns(next, TICK_NSEC);
|
||||
|
||||
if (!lx_clockevents_program_event(dev, next))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Have to be careful here. If we're in oneshot mode,
|
||||
* before we call tick_periodic() in a loop, we need
|
||||
* to be sure we're using a real hardware clocksource.
|
||||
* Otherwise we could get trapped in an infinite
|
||||
* loop, as the tick_periodic() increments jiffies,
|
||||
* which then will increment time, possibly causing
|
||||
* the loop to trigger again and again.
|
||||
*/
|
||||
if (timekeeping_valid_for_hres()) {
|
||||
do_timer(1); /* tick_periodic(cpu); */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ SRC_C += $(notdir $(wildcard $(REL_PRG_DIR)/generated_dummies.c))
|
||||
SRC_C += fb.c
|
||||
SRC_C += lx_user.c
|
||||
SRC_C += gem.c
|
||||
SRC_C += timeout.c
|
||||
SRC_C += common_dummies.c
|
||||
SRC_C += lx_emul/spec/x86/pci.c
|
||||
SRC_C += lx_emul/shadow/mm/page_alloc.c
|
||||
@ -38,6 +39,12 @@ INC_DIR += $(LX_SRC_DIR)/drivers/gpu/drm/i915
|
||||
|
||||
CC_C_OPT += -Wno-unused-label
|
||||
|
||||
#
|
||||
# Original symbol is renamed to __real_* and references to original symbol
|
||||
# are replaced by __wrap_*. Used to shadow schedule_timeout, see timeout.c
|
||||
#
|
||||
LD_OPT += --wrap=schedule_timeout
|
||||
|
||||
#
|
||||
# Genode C-API backends
|
||||
#
|
||||
|
33
repos/pc/src/drivers/framebuffer/intel/pc/timeout.c
Normal file
33
repos/pc/src/drivers/framebuffer/intel/pc/timeout.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* \brief Wrapper to update jiffies before invoking schedule_timeout().
|
||||
* Schedule_timeout() expects that the jiffie value is current,
|
||||
* in order to setup the timeouts. Without current jiffies,
|
||||
* the programmed timeouts are too short, which leads to timeouts
|
||||
* firing too early. The Intel driver uses this mechanism frequently
|
||||
* by utilizing wait_queue_timeout*() in order to wait for hardware
|
||||
* state changes, e.g. connectors hotplug. The schedule_timeout is
|
||||
* shadowed by the Linker feature '--wrap'. This code can be removed
|
||||
* as soon as the timeout handling is implemented by lx_emul/lx_kit
|
||||
* instead of using the original Linux sources of kernel/time/timer.c.
|
||||
* \author Alexander Boettcher
|
||||
* \date 2022-04-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <lx_emul/time.h>
|
||||
|
||||
|
||||
signed long __real_schedule_timeout(signed long timeout);
|
||||
|
||||
|
||||
signed long __wrap_schedule_timeout(signed long timeout)
|
||||
{
|
||||
lx_emul_force_jiffies_update();
|
||||
return __real_schedule_timeout(timeout);
|
||||
}
|
Loading…
Reference in New Issue
Block a user