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

Commit 2fbe7b25 authored by Don Zickus's avatar Don Zickus Committed by Andi Kleen
Browse files

[PATCH] i386/x86-64: Remove un/set_nmi_callback and reserve/release_lapic_nmi functions



Removes the un/set_nmi_callback and reserve/release_lapic_nmi functions as
they are no longer needed.  The various subsystems are modified to register
with the die_notifier instead.

Also includes compile fixes by Andrew Morton.

Signed-off-by: default avatarDon Zickus <dzickus@redhat.com>
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
parent 957dc87c
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#include <asm/nmi.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
#include <asm/kdebug.h>

#include <mach_ipi.h>


@@ -93,9 +95,18 @@ static void crash_save_self(struct pt_regs *regs)
#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
static atomic_t waiting_for_crash_ipi;

static int crash_nmi_callback(struct pt_regs *regs, int cpu)
static int crash_nmi_callback(struct notifier_block *self,
			unsigned long val, void *data)
{
	struct pt_regs *regs;
	struct pt_regs fixed_regs;
	int cpu;

	if (val != DIE_NMI)
		return NOTIFY_OK;

	regs = ((struct die_args *)data)->regs;
	cpu = raw_smp_processor_id();

	/* Don't do anything if this handler is invoked on crashing cpu.
	 * Otherwise, system will completely hang. Crashing cpu can get
@@ -125,13 +136,18 @@ static void smp_send_nmi_allbutself(void)
	send_IPI_allbutself(NMI_VECTOR);
}

static struct notifier_block crash_nmi_nb = {
	.notifier_call = crash_nmi_callback,
};

static void nmi_shootdown_cpus(void)
{
	unsigned long msecs;

	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
	/* Would it be better to replace the trap vector here? */
	set_nmi_callback(crash_nmi_callback);
	if (register_die_notifier(&crash_nmi_nb))
		return;		/* return what? */
	/* Ensure the new callback function is set before sending
	 * out the NMI
	 */
+11 −74
Original line number Diff line number Diff line
@@ -42,20 +42,6 @@ static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[3]);
 */
#define NMI_MAX_COUNTER_BITS 66

/*
 * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
 * - it may be reserved by some other driver, or not
 * - when not reserved by some other driver, it may be used for
 *   the NMI watchdog, or not
 *
 * This is maintained separately from nmi_active because the NMI
 * watchdog may also be driven from the I/O APIC timer.
 */
static DEFINE_SPINLOCK(lapic_nmi_owner_lock);
static unsigned int lapic_nmi_owner;
#define LAPIC_NMI_WATCHDOG	(1<<0)
#define LAPIC_NMI_RESERVED	(1<<1)

/* nmi_active:
 * >0: the lapic NMI watchdog is active, but can be disabled
 * <0: the lapic NMI watchdog has not been set up, and cannot
@@ -325,33 +311,6 @@ static void enable_lapic_nmi_watchdog(void)
	touch_nmi_watchdog();
}

int reserve_lapic_nmi(void)
{
	unsigned int old_owner;

	spin_lock(&lapic_nmi_owner_lock);
	old_owner = lapic_nmi_owner;
	lapic_nmi_owner |= LAPIC_NMI_RESERVED;
	spin_unlock(&lapic_nmi_owner_lock);
	if (old_owner & LAPIC_NMI_RESERVED)
		return -EBUSY;
	if (old_owner & LAPIC_NMI_WATCHDOG)
		disable_lapic_nmi_watchdog();
	return 0;
}

void release_lapic_nmi(void)
{
	unsigned int new_owner;

	spin_lock(&lapic_nmi_owner_lock);
	new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
	lapic_nmi_owner = new_owner;
	spin_unlock(&lapic_nmi_owner_lock);
	if (new_owner & LAPIC_NMI_WATCHDOG)
		enable_lapic_nmi_watchdog();
}

void disable_timer_nmi_watchdog(void)
{
	BUG_ON(nmi_watchdog != NMI_IO_APIC);
@@ -866,6 +825,15 @@ int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
	return rc;
}

int do_nmi_callback(struct pt_regs * regs, int cpu)
{
#ifdef CONFIG_SYSCTL
	if (unknown_nmi_panic)
		return unknown_nmi_panic_callback(regs, cpu);
#endif
	return 0;
}

#ifdef CONFIG_SYSCTL

static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
@@ -873,37 +841,8 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
	unsigned char reason = get_nmi_reason();
	char buf[64];

	if (!(reason & 0xc0)) {
	sprintf(buf, "NMI received for unknown reason %02x\n", reason);
	die_nmi(regs, buf);
	}
	return 0;
}

/*
 * proc handler for /proc/sys/kernel/unknown_nmi_panic
 */
int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file,
			void __user *buffer, size_t *length, loff_t *ppos)
{
	int old_state;

	old_state = unknown_nmi_panic;
	proc_dointvec(table, write, file, buffer, length, ppos);
	if (!!old_state == !!unknown_nmi_panic)
		return 0;

	if (unknown_nmi_panic) {
		if (reserve_lapic_nmi() < 0) {
			unknown_nmi_panic = 0;
			return -EBUSY;
		} else {
			set_nmi_callback(unknown_nmi_panic_callback);
		}
	} else {
		release_lapic_nmi();
		unset_nmi_callback();
	}
	return 0;
}

@@ -917,7 +856,5 @@ EXPORT_SYMBOL(reserve_perfctr_nmi);
EXPORT_SYMBOL(release_perfctr_nmi);
EXPORT_SYMBOL(reserve_evntsel_nmi);
EXPORT_SYMBOL(release_evntsel_nmi);
EXPORT_SYMBOL(reserve_lapic_nmi);
EXPORT_SYMBOL(release_lapic_nmi);
EXPORT_SYMBOL(disable_timer_nmi_watchdog);
EXPORT_SYMBOL(enable_timer_nmi_watchdog);
+2 −21
Original line number Diff line number Diff line
@@ -706,13 +706,6 @@ void die_nmi (struct pt_regs *regs, const char *msg)
	do_exit(SIGSEGV);
}

static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
{
	return 0;
}

static nmi_callback_t nmi_callback = dummy_nmi_callback;

static void default_do_nmi(struct pt_regs * regs)
{
	unsigned char reason = 0;
@@ -732,9 +725,10 @@ static void default_do_nmi(struct pt_regs * regs)
		 */
		if (nmi_watchdog_tick(regs, reason))
			return;
		if (!do_nmi_callback(regs, smp_processor_id()))
#endif
		if (!rcu_dereference(nmi_callback)(regs, smp_processor_id()))
			unknown_nmi_error(reason, regs);

		return;
	}
	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
@@ -765,19 +759,6 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code)
	nmi_exit();
}

void set_nmi_callback(nmi_callback_t callback)
{
	vmalloc_sync_all();
	rcu_assign_pointer(nmi_callback, callback);
}
EXPORT_SYMBOL_GPL(set_nmi_callback);

void unset_nmi_callback(void)
{
	nmi_callback = dummy_nmi_callback;
}
EXPORT_SYMBOL_GPL(unset_nmi_callback);

#ifdef CONFIG_KPROBES
fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
{
+30 −17
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <asm/nmi.h>
#include <asm/msr.h>
#include <asm/apic.h>
#include <asm/kdebug.h>
 
#include "op_counter.h"
#include "op_x86_model.h"
@@ -82,12 +83,23 @@ static void exit_driverfs(void)
#define exit_driverfs() do { } while (0)
#endif /* CONFIG_PM */


static int nmi_callback(struct pt_regs * regs, int cpu)
int profile_exceptions_notify(struct notifier_block *self,
				unsigned long val, void *data)
{
	return model->check_ctrs(regs, &cpu_msrs[cpu]);
}
	struct die_args *args = (struct die_args *)data;
	int ret = NOTIFY_DONE;
	int cpu = smp_processor_id();

	switch(val) {
	case DIE_NMI:
		if (model->check_ctrs(args->regs, &cpu_msrs[cpu]))
			ret = NOTIFY_STOP;
		break;
	default:
		break;
	}
	return ret;
}

static void nmi_cpu_save_registers(struct op_msrs * msrs)
{
@@ -174,27 +186,29 @@ static void nmi_cpu_setup(void * dummy)
	apic_write(APIC_LVTPC, APIC_DM_NMI);
}

static struct notifier_block profile_exceptions_nb = {
	.notifier_call = profile_exceptions_notify,
	.next = NULL,
	.priority = 0
};

static int nmi_setup(void)
{
	int err=0;

	if (!allocate_msrs())
		return -ENOMEM;

	/* We walk a thin line between law and rape here.
	 * We need to be careful to install our NMI handler
	 * without actually triggering any NMIs as this will
	 * break the core code horrifically.
	 */
	if (reserve_lapic_nmi() < 0) {
	if ((err = register_die_notifier(&profile_exceptions_nb))){
		free_msrs();
		return -EBUSY;
		return err;
	}

	/* We need to serialize save and setup for HT because the subset
	 * of msrs are distinct for save and setup operations
	 */
	on_each_cpu(nmi_save_registers, NULL, 0, 1);
	on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
	set_nmi_callback(nmi_callback);
	nmi_enabled = 1;
	return 0;
}
@@ -250,8 +264,7 @@ static void nmi_shutdown(void)
{
	nmi_enabled = 0;
	on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
	unset_nmi_callback();
	release_lapic_nmi();
	unregister_die_notifier(&profile_exceptions_nb);
	free_msrs();
}

+25 −8
Original line number Diff line number Diff line
@@ -17,32 +17,49 @@
#include <asm/nmi.h>
#include <asm/apic.h>
#include <asm/ptrace.h>
#include <asm/kdebug.h>
 
static int nmi_timer_callback(struct pt_regs * regs, int cpu)
int profile_timer_exceptions_notify(struct notifier_block *self,
				unsigned long val, void *data)
{
	oprofile_add_sample(regs, 0);
	return 1;
	struct die_args *args = (struct die_args *)data;
	int ret = NOTIFY_DONE;

	switch(val) {
	case DIE_NMI:
		oprofile_add_sample(args->regs, 0);
		ret = NOTIFY_STOP;
		break;
	default:
		break;
	}
	return ret;
}

static struct notifier_block profile_timer_exceptions_nb = {
	.notifier_call = profile_timer_exceptions_notify,
	.next = NULL,
	.priority = 0
};

static int timer_start(void)
{
	disable_timer_nmi_watchdog();
	set_nmi_callback(nmi_timer_callback);
	if (register_die_notifier(&profile_timer_exceptions_nb))
		return 1;
	return 0;
}


static void timer_stop(void)
{
	enable_timer_nmi_watchdog();
	unset_nmi_callback();
	unregister_die_notifier(&profile_timer_exceptions_nb);
	synchronize_sched();  /* Allow already-started NMIs to complete. */
}


int __init op_nmi_timer_init(struct oprofile_operations * ops)
{
	if (atomic_read(&nmi_active) <= 0)
	if ((nmi_watchdog != NMI_IO_APIC) || (atomic_read(&nmi_active) <= 0))
		return -ENODEV;

	ops->start = timer_start;
Loading