c6e22f9e3e
This patch updates percpu related symbols in xen such that percpu symbols are unique and don't clash with local symbols. This serves two purposes of decreasing the possibility of global percpu symbol collision and allowing dropping per_cpu__ prefix from percpu symbols. * arch/x86/xen/smp.c, arch/x86/xen/time.c, arch/ia64/xen/irq_xen.c: add xen_ prefix to percpu variables * arch/ia64/xen/time.c: add xen_ prefix to percpu variables, drop processed_ prefix and make them static Partly based on Rusty Russell's "alloc_percpu: rename percpu vars which cause name clashes" patch. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Jeremy Fitzhardinge <jeremy@xensource.com> Cc: Chris Wright <chrisw@sous-sol.org>
261 lines
6.6 KiB
C
261 lines
6.6 KiB
C
/******************************************************************************
|
|
* arch/ia64/xen/time.c
|
|
*
|
|
* Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
|
|
* VA Linux Systems Japan K.K.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/kernel_stat.h>
|
|
#include <linux/posix-timers.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/clocksource.h>
|
|
|
|
#include <asm/timex.h>
|
|
|
|
#include <asm/xen/hypervisor.h>
|
|
|
|
#include <xen/interface/vcpu.h>
|
|
|
|
#include "../kernel/fsyscall_gtod_data.h"
|
|
|
|
static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
|
|
static DEFINE_PER_CPU(unsigned long, xen_stolen_time);
|
|
static DEFINE_PER_CPU(unsigned long, xen_blocked_time);
|
|
|
|
/* taken from i386/kernel/time-xen.c */
|
|
static void xen_init_missing_ticks_accounting(int cpu)
|
|
{
|
|
struct vcpu_register_runstate_memory_area area;
|
|
struct vcpu_runstate_info *runstate = &per_cpu(xen_runstate, cpu);
|
|
int rc;
|
|
|
|
memset(runstate, 0, sizeof(*runstate));
|
|
|
|
area.addr.v = runstate;
|
|
rc = HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu,
|
|
&area);
|
|
WARN_ON(rc && rc != -ENOSYS);
|
|
|
|
per_cpu(xen_blocked_time, cpu) = runstate->time[RUNSTATE_blocked];
|
|
per_cpu(xen_stolen_time, cpu) = runstate->time[RUNSTATE_runnable]
|
|
+ runstate->time[RUNSTATE_offline];
|
|
}
|
|
|
|
/*
|
|
* Runstate accounting
|
|
*/
|
|
/* stolen from arch/x86/xen/time.c */
|
|
static void get_runstate_snapshot(struct vcpu_runstate_info *res)
|
|
{
|
|
u64 state_time;
|
|
struct vcpu_runstate_info *state;
|
|
|
|
BUG_ON(preemptible());
|
|
|
|
state = &__get_cpu_var(xen_runstate);
|
|
|
|
/*
|
|
* The runstate info is always updated by the hypervisor on
|
|
* the current CPU, so there's no need to use anything
|
|
* stronger than a compiler barrier when fetching it.
|
|
*/
|
|
do {
|
|
state_time = state->state_entry_time;
|
|
rmb();
|
|
*res = *state;
|
|
rmb();
|
|
} while (state->state_entry_time != state_time);
|
|
}
|
|
|
|
#define NS_PER_TICK (1000000000LL/HZ)
|
|
|
|
static unsigned long
|
|
consider_steal_time(unsigned long new_itm)
|
|
{
|
|
unsigned long stolen, blocked;
|
|
unsigned long delta_itm = 0, stolentick = 0;
|
|
int cpu = smp_processor_id();
|
|
struct vcpu_runstate_info runstate;
|
|
struct task_struct *p = current;
|
|
|
|
get_runstate_snapshot(&runstate);
|
|
|
|
/*
|
|
* Check for vcpu migration effect
|
|
* In this case, itc value is reversed.
|
|
* This causes huge stolen value.
|
|
* This function just checks and reject this effect.
|
|
*/
|
|
if (!time_after_eq(runstate.time[RUNSTATE_blocked],
|
|
per_cpu(xen_blocked_time, cpu)))
|
|
blocked = 0;
|
|
|
|
if (!time_after_eq(runstate.time[RUNSTATE_runnable] +
|
|
runstate.time[RUNSTATE_offline],
|
|
per_cpu(xen_stolen_time, cpu)))
|
|
stolen = 0;
|
|
|
|
if (!time_after(delta_itm + new_itm, ia64_get_itc()))
|
|
stolentick = ia64_get_itc() - new_itm;
|
|
|
|
do_div(stolentick, NS_PER_TICK);
|
|
stolentick++;
|
|
|
|
do_div(stolen, NS_PER_TICK);
|
|
|
|
if (stolen > stolentick)
|
|
stolen = stolentick;
|
|
|
|
stolentick -= stolen;
|
|
do_div(blocked, NS_PER_TICK);
|
|
|
|
if (blocked > stolentick)
|
|
blocked = stolentick;
|
|
|
|
if (stolen > 0 || blocked > 0) {
|
|
account_steal_ticks(stolen);
|
|
account_idle_ticks(blocked);
|
|
run_local_timers();
|
|
|
|
rcu_check_callbacks(cpu, user_mode(get_irq_regs()));
|
|
|
|
scheduler_tick();
|
|
run_posix_cpu_timers(p);
|
|
delta_itm += local_cpu_data->itm_delta * (stolen + blocked);
|
|
|
|
if (cpu == time_keeper_id) {
|
|
write_seqlock(&xtime_lock);
|
|
do_timer(stolen + blocked);
|
|
local_cpu_data->itm_next = delta_itm + new_itm;
|
|
write_sequnlock(&xtime_lock);
|
|
} else {
|
|
local_cpu_data->itm_next = delta_itm + new_itm;
|
|
}
|
|
per_cpu(xen_stolen_time, cpu) += NS_PER_TICK * stolen;
|
|
per_cpu(xen_blocked_time, cpu) += NS_PER_TICK * blocked;
|
|
}
|
|
return delta_itm;
|
|
}
|
|
|
|
static int xen_do_steal_accounting(unsigned long *new_itm)
|
|
{
|
|
unsigned long delta_itm;
|
|
delta_itm = consider_steal_time(*new_itm);
|
|
*new_itm += delta_itm;
|
|
if (time_after(*new_itm, ia64_get_itc()) && delta_itm)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void xen_itc_jitter_data_reset(void)
|
|
{
|
|
u64 lcycle, ret;
|
|
|
|
do {
|
|
lcycle = itc_jitter_data.itc_lastcycle;
|
|
ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, 0);
|
|
} while (unlikely(ret != lcycle));
|
|
}
|
|
|
|
/* based on xen_sched_clock() in arch/x86/xen/time.c. */
|
|
/*
|
|
* This relies on HAVE_UNSTABLE_SCHED_CLOCK. If it can't be defined,
|
|
* something similar logic should be implemented here.
|
|
*/
|
|
/*
|
|
* Xen sched_clock implementation. Returns the number of unstolen
|
|
* nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
|
|
* states.
|
|
*/
|
|
static unsigned long long xen_sched_clock(void)
|
|
{
|
|
struct vcpu_runstate_info runstate;
|
|
|
|
unsigned long long now;
|
|
unsigned long long offset;
|
|
unsigned long long ret;
|
|
|
|
/*
|
|
* Ideally sched_clock should be called on a per-cpu basis
|
|
* anyway, so preempt should already be disabled, but that's
|
|
* not current practice at the moment.
|
|
*/
|
|
preempt_disable();
|
|
|
|
/*
|
|
* both ia64_native_sched_clock() and xen's runstate are
|
|
* based on mAR.ITC. So difference of them makes sense.
|
|
*/
|
|
now = ia64_native_sched_clock();
|
|
|
|
get_runstate_snapshot(&runstate);
|
|
|
|
WARN_ON(runstate.state != RUNSTATE_running);
|
|
|
|
offset = 0;
|
|
if (now > runstate.state_entry_time)
|
|
offset = now - runstate.state_entry_time;
|
|
ret = runstate.time[RUNSTATE_blocked] +
|
|
runstate.time[RUNSTATE_running] +
|
|
offset;
|
|
|
|
preempt_enable();
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct pv_time_ops xen_time_ops __initdata = {
|
|
.init_missing_ticks_accounting = xen_init_missing_ticks_accounting,
|
|
.do_steal_accounting = xen_do_steal_accounting,
|
|
.clocksource_resume = xen_itc_jitter_data_reset,
|
|
.sched_clock = xen_sched_clock,
|
|
};
|
|
|
|
/* Called after suspend, to resume time. */
|
|
static void xen_local_tick_resume(void)
|
|
{
|
|
/* Just trigger a tick. */
|
|
ia64_cpu_local_tick();
|
|
touch_softlockup_watchdog();
|
|
}
|
|
|
|
void
|
|
xen_timer_resume(void)
|
|
{
|
|
unsigned int cpu;
|
|
|
|
xen_local_tick_resume();
|
|
|
|
for_each_online_cpu(cpu)
|
|
xen_init_missing_ticks_accounting(cpu);
|
|
}
|
|
|
|
static void ia64_cpu_local_tick_fn(void *unused)
|
|
{
|
|
xen_local_tick_resume();
|
|
xen_init_missing_ticks_accounting(smp_processor_id());
|
|
}
|
|
|
|
void
|
|
xen_timer_resume_on_aps(void)
|
|
{
|
|
smp_call_function(&ia64_cpu_local_tick_fn, NULL, 1);
|
|
}
|