Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2753a6d authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds
Browse files

uml: tickless support



Enable tickless support.

CONFIG_TICK_ONESHOT and CONFIG_NO_HZ are enabled.

itimer_clockevent gets CLOCK_EVT_FEAT_ONESHOT and an implementation of
.set_next_event.

CONFIG_UML_REAL_TIME_CLOCK goes away because it only makes sense when there is
a clock ticking away all the time.  timer_handler now just calls do_IRQ once
without trying to figure out how many ticks to emulate.

The idle loop now needs to turn ticking on and off.

Userspace ticks keep happening as usual.  However, the userspace loop keep
track of when the next wakeup should happen and suppresses process ticks until
that happens.

Signed-off-by: default avatarJeff Dike <jdike@linux.intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 791a644a
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -250,18 +250,6 @@ config KERNEL_STACK_ORDER
	  be 1 << order pages.  The default is OK unless you're running Valgrind
	  on UML, in which case, set this to 3.

config UML_REAL_TIME_CLOCK
	bool "Real-time Clock"
	default y
	help
	  This option makes UML time deltas match wall clock deltas.  This
	  should normally be enabled.  The exception would be if you are
	  debugging with UML and spend long times with UML stopped at a
	  breakpoint.  In this case, when UML is restarted, it will call the
	  timer enough times to make up for the time spent at the breakpoint.
	  This could result in a noticeable lag.  If this is a problem, then
	  disable this option.

endmenu

source "init/Kconfig"
+2 −3
Original line number Diff line number Diff line
@@ -73,8 +73,8 @@ CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_TICK_ONESHOT is not set
# CONFIG_NO_HZ is not set
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_LD_SCRIPT_DYN=y
CONFIG_NET=y
@@ -87,7 +87,6 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_NEST_LEVEL=0
# CONFIG_HIGHMEM is not set
CONFIG_KERNEL_STACK_ORDER=0
CONFIG_UML_REAL_TIME_CLOCK=y

#
# Code maturity level options
+1 −0
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@ extern void os_dump_core(void);
extern int switch_timers(int to_real);
extern void idle_sleep(int secs);
extern int set_interval(void);
extern int timer_one_shot(int ticks);
extern void disable_timer(void);
extern void uml_idle_timer(void);
extern unsigned long long os_nsecs(void);
+3 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include "linux/ptrace.h"
#include "linux/random.h"
#include "linux/sched.h"
#include "linux/tick.h"
#include "linux/threads.h"
#include "asm/pgtable.h"
#include "asm/uaccess.h"
@@ -244,9 +245,11 @@ void default_idle(void)
		if (need_resched())
			schedule();

		tick_nohz_stop_sched_tick();
		switch_timers(1);
		idle_sleep(10);
		switch_timers(0);
		tick_nohz_restart_sched_tick();
	}
}

+10 −35
Original line number Diff line number Diff line
@@ -20,41 +20,12 @@ unsigned long long sched_clock(void)
	return (unsigned long long)jiffies_64 * (1000000000 / HZ);
}

#ifdef CONFIG_UML_REAL_TIME_CLOCK
static unsigned long long prev_nsecs[NR_CPUS];
static long long delta[NR_CPUS];		/* Deviation per interval */
#endif

void timer_handler(int sig, struct uml_pt_regs *regs)
{
	unsigned long long ticks = 0;
	unsigned long flags;
#ifdef CONFIG_UML_REAL_TIME_CLOCK
	int c = cpu();
	if (prev_nsecs[c]) {
		/* We've had 1 tick */
		unsigned long long nsecs = os_nsecs();

		delta[c] += nsecs - prev_nsecs[c];
		prev_nsecs[c] = nsecs;

		/* Protect against the host clock being set backwards */
		if (delta[c] < 0)
			delta[c] = 0;

		ticks += (delta[c] * HZ) / BILLION;
		delta[c] -= (ticks * BILLION) / HZ;
	}
	else prev_nsecs[c] = os_nsecs();
#else
	ticks = 1;
#endif

	local_irq_save(flags);
	while (ticks > 0) {
	do_IRQ(TIMER_IRQ, regs);
		ticks--;
	}
	local_irq_restore(flags);
}

@@ -68,10 +39,8 @@ static void itimer_set_mode(enum clock_event_mode mode,

	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_UNUSED:
		disable_timer();
		break;
	case CLOCK_EVT_MODE_ONESHOT:
		BUG();
		disable_timer();
		break;

	case CLOCK_EVT_MODE_RESUME:
@@ -79,13 +48,19 @@ static void itimer_set_mode(enum clock_event_mode mode,
	}
}

static int itimer_next_event(unsigned long delta,
			     struct clock_event_device *evt)
{
	return timer_one_shot(delta + 1);
}

static struct clock_event_device itimer_clockevent = {
	.name		= "itimer",
	.rating		= 250,
	.cpumask	= CPU_MASK_ALL,
	.features	= CLOCK_EVT_FEAT_PERIODIC,
	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
	.set_mode	= itimer_set_mode,
	.set_next_event = NULL,
	.set_next_event = itimer_next_event,
	.shift		= 32,
	.irq		= 0,
};
Loading