- rewrite x86 nmi dispatcher so that establish and disesablish are safe
on a running system. - adapt existing users of the api. (elan) - adapt tprof_pmi driver to use the api.
This commit is contained in:
parent
3076c08525
commit
4b64c2cb3d
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: trap.c,v 1.53 2008/11/14 15:03:44 ad Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.54 2009/02/24 06:03:54 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
|
||||
|
@ -68,16 +68,11 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.53 2008/11/14 15:03:44 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.54 2009/02/24 06:03:54 yamt Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_kgdb.h"
|
||||
#include "opt_xen.h"
|
||||
#if !defined(XEN)
|
||||
#include "tprof.h"
|
||||
#else /* !defined(XEN) */
|
||||
#define NTPROF 0
|
||||
#endif /* !defined(XEN) */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -97,10 +92,6 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.53 2008/11/14 15:03:44 ad Exp $");
|
|||
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#if NTPROF > 0
|
||||
#include <x86/tprof.h>
|
||||
#endif /* NTPROF > 0 */
|
||||
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/psl.h>
|
||||
|
@ -111,6 +102,8 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.53 2008/11/14 15:03:44 ad Exp $");
|
|||
#include <machine/db_machdep.h>
|
||||
#endif
|
||||
|
||||
#include <x86/nmi.h>
|
||||
|
||||
#ifndef XEN
|
||||
#include "isa.h"
|
||||
#endif
|
||||
|
@ -595,10 +588,10 @@ faultcommon:
|
|||
break;
|
||||
|
||||
case T_NMI:
|
||||
#if NTPROF > 0
|
||||
if (tprof_pmi_nmi(frame))
|
||||
#if !defined(XEN)
|
||||
if (nmi_dispatch(frame))
|
||||
return;
|
||||
#endif /* NTPROF > 0 */
|
||||
#endif /* !defined(XEN) */
|
||||
#if NISA > 0
|
||||
#if defined(KGDB) || defined(DDB)
|
||||
/* NMI can be hooked up to a pushbutton for debugging */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: trap.c,v 1.241 2008/10/15 06:51:17 wrstuden Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.242 2009/02/24 06:03:54 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2000, 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -68,7 +68,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.241 2008/10/15 06:51:17 wrstuden Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.242 2009/02/24 06:03:54 yamt Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_kgdb.h"
|
||||
|
@ -78,11 +78,6 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.241 2008/10/15 06:51:17 wrstuden Exp $");
|
|||
#include "opt_kvm86.h"
|
||||
#include "opt_kstack_dr0.h"
|
||||
#include "opt_xen.h"
|
||||
#if !defined(XEN)
|
||||
#include "tprof.h"
|
||||
#else /* defined(XEN) */
|
||||
#define NTPROF 0
|
||||
#endif /* defined(XEN) */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -102,10 +97,6 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.241 2008/10/15 06:51:17 wrstuden Exp $");
|
|||
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#if NTPROF > 0
|
||||
#include <x86/tprof.h>
|
||||
#endif /* NTPROF > 0 */
|
||||
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/reg.h>
|
||||
|
@ -120,6 +111,8 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.241 2008/10/15 06:51:17 wrstuden Exp $");
|
|||
#include <machine/mca_machdep.h>
|
||||
#endif
|
||||
|
||||
#include <x86/nmi.h>
|
||||
|
||||
#include "isa.h"
|
||||
|
||||
#ifdef KGDB
|
||||
|
@ -768,12 +761,8 @@ copyfault:
|
|||
break;
|
||||
|
||||
case T_NMI:
|
||||
#if NTPROF > 0
|
||||
if (tprof_pmi_nmi(frame))
|
||||
return;
|
||||
#endif /* NTPROF > 0 */
|
||||
#if !defined(XEN)
|
||||
if (nmi_dispatch())
|
||||
if (nmi_dispatch(frame))
|
||||
return;
|
||||
#if (NISA > 0 || NMCA > 0)
|
||||
#if defined(KGDB) || defined(DDB)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: elan520.c,v 1.37 2009/02/06 01:40:36 dyoung Exp $ */
|
||||
/* $NetBSD: elan520.c,v 1.38 2009/02/24 06:03:54 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
|
@ -40,7 +40,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: elan520.c,v 1.37 2009/02/06 01:40:36 dyoung Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: elan520.c,v 1.38 2009/02/24 06:03:54 yamt Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -55,6 +55,8 @@ __KERNEL_RCSID(0, "$NetBSD: elan520.c,v 1.37 2009/02/06 01:40:36 dyoung Exp $");
|
|||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <x86/nmi.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/pci/pcidevs.h>
|
||||
|
@ -421,6 +423,13 @@ elanpar_intr(void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elanpar_nmi(const struct trapframe *tf, void *arg)
|
||||
{
|
||||
|
||||
return elanpar_intr(arg);
|
||||
}
|
||||
|
||||
static int
|
||||
elanpex_intr(void *arg)
|
||||
{
|
||||
|
@ -521,6 +530,13 @@ elanpex_intr(void *arg)
|
|||
return fatal ? 0 : (handled ? 1 : 0);
|
||||
}
|
||||
|
||||
static int
|
||||
elanpex_nmi(const struct trapframe *tf, void *arg)
|
||||
{
|
||||
|
||||
return elanpex_intr(arg);
|
||||
}
|
||||
|
||||
#define elansc_print_1(__dev, __sc, __reg) \
|
||||
do { \
|
||||
aprint_debug_dev(__dev, \
|
||||
|
@ -1004,7 +1020,7 @@ elanpex_intr_establish(device_t self, struct elansc_softc *sc)
|
|||
tgtirq |= MMCR_HBTGTIRQCTL_T_DPER_IRQ_ENB;
|
||||
|
||||
if (elansc_pcinmi) {
|
||||
sc->sc_eih = nmi_establish(elanpex_intr, sc);
|
||||
sc->sc_eih = nmi_establish(elanpex_nmi, sc);
|
||||
|
||||
/* Activate NMI instead of maskable interrupts for
|
||||
* all PCI exceptions:
|
||||
|
@ -1134,7 +1150,7 @@ elanpar_intr_establish(device_t self, struct elansc_softc *sc)
|
|||
|
||||
/* establish interrupt */
|
||||
if (elansc_wpvnmi)
|
||||
sc->sc_pih = nmi_establish(elanpar_intr, sc);
|
||||
sc->sc_pih = nmi_establish(elanpar_nmi, sc);
|
||||
else
|
||||
sc->sc_pih = elansc_intr_establish(self, elanpar_intr, sc);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.x86,v 1.45 2009/02/17 01:42:51 jmcneill Exp $
|
||||
# $NetBSD: files.x86,v 1.46 2009/02/24 06:03:54 yamt Exp $
|
||||
|
||||
# options for MP configuration through the MP spec
|
||||
defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI
|
||||
|
@ -50,6 +50,7 @@ file arch/x86/x86/genfb_machdep.c
|
|||
file arch/x86/x86/identcpu.c
|
||||
file arch/x86/x86/i8259.c
|
||||
file arch/x86/x86/intr.c
|
||||
file arch/x86/x86/nmi.c
|
||||
file arch/x86/x86/idt.c
|
||||
file arch/x86/x86/ipi.c
|
||||
file arch/x86/x86/msr_ipifuncs.c
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: intr.h,v 1.35 2008/05/30 19:03:10 ad Exp $ */
|
||||
/* $NetBSD: intr.h,v 1.36 2009/02/24 06:03:54 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -161,9 +161,6 @@ struct cpu_info;
|
|||
struct pcibus_attach_args;
|
||||
|
||||
void intr_default_setup(void);
|
||||
void *nmi_establish(int (*)(void *), void *);
|
||||
bool nmi_disestablish(void *);
|
||||
int nmi_dispatch(void);
|
||||
int x86_nmi(void);
|
||||
void *intr_establish(int, struct pic *, int, int, int, int (*)(void *), void *, bool);
|
||||
void intr_disestablish(struct intrhand *);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* $Id: nmi.h,v 1.1 2009/02/24 06:03:54 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c)2009 YAMAMOTO Takashi,
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _X86_NMI_H_
|
||||
#define _X86_NMI_H_
|
||||
|
||||
typedef struct nmi_handler nmi_handler_t;
|
||||
struct trapframe;
|
||||
|
||||
nmi_handler_t *nmi_establish(int (*)(const struct trapframe *, void *), void *);
|
||||
void nmi_disestablish(nmi_handler_t *);
|
||||
int nmi_dispatch(const struct trapframe *);
|
||||
void nmi_init(void);
|
||||
|
||||
#endif /* _X86_NMI_H_ */
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: tprof.h,v 1.1 2008/01/01 21:28:39 yamt Exp $ */
|
||||
/* $NetBSD: tprof.h,v 1.2 2009/02/24 06:03:54 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c)2008 YAMAMOTO Takashi,
|
||||
|
@ -29,7 +29,6 @@
|
|||
#ifndef _X86_TPROF_H_
|
||||
#define _X86_TPROF_H_
|
||||
|
||||
struct trapframe;
|
||||
int tprof_pmi_nmi(const struct trapframe *);
|
||||
/* XXX nothing */
|
||||
|
||||
#endif /* _X86_TPROF_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: intr.c,v 1.58 2008/12/17 20:51:33 cegger Exp $ */
|
||||
/* $NetBSD: intr.c,v 1.59 2009/02/24 06:03:55 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -133,7 +133,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.58 2008/12/17 20:51:33 cegger Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.59 2009/02/24 06:03:55 yamt Exp $");
|
||||
|
||||
#include "opt_multiprocessor.h"
|
||||
#include "opt_acpi.h"
|
||||
|
@ -144,11 +144,13 @@ __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.58 2008/12/17 20:51:33 cegger Exp $");
|
|||
#include <sys/syslog.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/intr.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/xcall.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
|
@ -190,7 +192,6 @@ static int intr_find_pcibridge(int, pcitag_t *, pci_chipset_tag_t *);
|
|||
#endif
|
||||
|
||||
kmutex_t x86_intr_lock;
|
||||
bool x86_intr_lock_initted;
|
||||
|
||||
/*
|
||||
* Fill in default interrupt table (in case of spurious interrupt
|
||||
|
@ -217,61 +218,6 @@ intr_default_setup(void)
|
|||
i8259_default_setup();
|
||||
}
|
||||
|
||||
struct nmi_handler {
|
||||
int (*n_func)(void *);
|
||||
void *n_arg;
|
||||
SLIST_ENTRY(nmi_handler) n_next;
|
||||
};
|
||||
|
||||
SLIST_HEAD(nmi_handler_head, nmi_handler) nmi_handlers =
|
||||
SLIST_HEAD_INITIALIZER(nmi_handler_head);
|
||||
|
||||
void *
|
||||
nmi_establish(int (*func)(void *), void *arg)
|
||||
{
|
||||
struct nmi_handler *n;
|
||||
|
||||
n = malloc(sizeof(*n), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
|
||||
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
|
||||
n->n_func = func;
|
||||
n->n_arg = arg;
|
||||
SLIST_INSERT_HEAD(&nmi_handlers, n, n_next);
|
||||
KASSERT(SLIST_FIRST(&nmi_handlers) == n);
|
||||
return n;
|
||||
}
|
||||
|
||||
bool
|
||||
nmi_disestablish(void *n0)
|
||||
{
|
||||
struct nmi_handler *n;
|
||||
|
||||
SLIST_FOREACH(n, &nmi_handlers, n_next) {
|
||||
if (n == n0)
|
||||
break;
|
||||
}
|
||||
if (n == NULL)
|
||||
return false;
|
||||
SLIST_REMOVE(&nmi_handlers, n, nmi_handler, n_next);
|
||||
free(n, M_DEVBUF);
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
nmi_dispatch(void)
|
||||
{
|
||||
int handled = 0;
|
||||
struct nmi_handler *n;
|
||||
|
||||
SLIST_FOREACH(n, &nmi_handlers, n_next) {
|
||||
if ((*n->n_func)(n->n_arg))
|
||||
handled = 1;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a NMI, possibly a machine check.
|
||||
* return true to panic system, false to ignore.
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
/* $Id: nmi.c,v 1.1 2009/02/24 06:03:55 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c)2009 YAMAMOTO Takashi,
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: nmi.c,v 1.1 2009/02/24 06:03:55 yamt Exp $");
|
||||
|
||||
/*
|
||||
* nmi dispatcher.
|
||||
*
|
||||
* XXX no need to be nmi-specific.
|
||||
* actual assumptions are:
|
||||
* - dispatch() is called with preemption disabled.
|
||||
* - handlers never block.
|
||||
* - establish() and disestablish() are called within a thread context.
|
||||
* (thus can block)
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/xcall.h>
|
||||
|
||||
#include <x86/nmi.h>
|
||||
|
||||
struct nmi_handler {
|
||||
int (*n_func)(const struct trapframe *, void *);
|
||||
void *n_arg;
|
||||
struct nmi_handler *n_next;
|
||||
};
|
||||
|
||||
static kmutex_t nmi_list_lock; /* serialize establish and disestablish */
|
||||
static nmi_handler_t *nmi_handlers; /* list of handlers */
|
||||
|
||||
/*
|
||||
* nmi_establish: establish an nmi handler
|
||||
*
|
||||
* => can block.
|
||||
* => returns an opaque handle.
|
||||
*/
|
||||
|
||||
nmi_handler_t *
|
||||
nmi_establish(int (*func)(const struct trapframe *, void *), void *arg)
|
||||
{
|
||||
struct nmi_handler *n;
|
||||
|
||||
n = kmem_alloc(sizeof(*n), KM_SLEEP);
|
||||
if (n == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
n->n_func = func;
|
||||
n->n_arg = arg;
|
||||
|
||||
/*
|
||||
* put it into the list.
|
||||
*/
|
||||
|
||||
mutex_enter(&nmi_list_lock);
|
||||
n->n_next = nmi_handlers;
|
||||
membar_producer(); /* n->n_next should be visible before nmi_handlers */
|
||||
nmi_handlers = n; /* atomic store */
|
||||
mutex_exit(&nmi_list_lock);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* nmi_disestablish: disestablish an nmi handler.
|
||||
*
|
||||
* => can block.
|
||||
* => take an opaque handle. it must be one returned by nmi_establish.
|
||||
*/
|
||||
|
||||
void
|
||||
nmi_disestablish(nmi_handler_t *handle)
|
||||
{
|
||||
nmi_handler_t *n;
|
||||
nmi_handler_t **pp;
|
||||
|
||||
KASSERT(handle != NULL);
|
||||
|
||||
/*
|
||||
* remove the handler from the list.
|
||||
*/
|
||||
|
||||
mutex_enter(&nmi_list_lock);
|
||||
for (pp = &nmi_handlers, n = *pp; n != NULL; n = *pp) {
|
||||
if (n == handle) {
|
||||
break;
|
||||
}
|
||||
pp = &n->n_next;
|
||||
}
|
||||
#if defined(DIAGNOSTIC)
|
||||
if (n == NULL) {
|
||||
mutex_exit(&nmi_list_lock);
|
||||
panic("%s: invalid handle %p", __func__, handle);
|
||||
}
|
||||
#endif /* defined(DIAGNOSTIC) */
|
||||
*pp = n->n_next; /* atomic store */
|
||||
mutex_exit(&nmi_list_lock); /* mutex_exit implies a store fence */
|
||||
|
||||
/*
|
||||
* before freeing 'n', ensure that no other cpus are
|
||||
* in the middle of nmi_dispatch.
|
||||
*/
|
||||
|
||||
if (!mp_online) {
|
||||
uint64_t h;
|
||||
|
||||
h = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
|
||||
xc_wait(h);
|
||||
}
|
||||
|
||||
kmem_free(n, sizeof(*n));
|
||||
}
|
||||
|
||||
/*
|
||||
* nmi_dispatch: dispatch an nmi.
|
||||
*
|
||||
* => called by interrupts, thus preempt disabled.
|
||||
*/
|
||||
|
||||
int
|
||||
nmi_dispatch(const struct trapframe *tf)
|
||||
{
|
||||
const struct nmi_handler *n;
|
||||
int handled = 0;
|
||||
|
||||
for (n = nmi_handlers; /* atomic load */
|
||||
n != NULL;
|
||||
n = n->n_next) { /* atomic load */
|
||||
handled |= (*n->n_func)(tf, n->n_arg);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void
|
||||
nmi_init(void)
|
||||
{
|
||||
|
||||
mutex_init(&nmi_list_lock, MUTEX_DEFAULT, IPL_NONE);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: tprof_pmi.c,v 1.3 2008/05/11 22:51:02 yamt Exp $ */
|
||||
/* $NetBSD: tprof_pmi.c,v 1.4 2009/02/24 06:03:55 yamt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c)2008 YAMAMOTO Takashi,
|
||||
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: tprof_pmi.c,v 1.3 2008/05/11 22:51:02 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: tprof_pmi.c,v 1.4 2009/02/24 06:03:55 yamt Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -39,6 +39,8 @@ __KERNEL_RCSID(0, "$NetBSD: tprof_pmi.c,v 1.3 2008/05/11 22:51:02 yamt Exp $");
|
|||
#include <dev/tprof/tprof.h>
|
||||
|
||||
#include <x86/tprof.h>
|
||||
#include <x86/nmi.h>
|
||||
|
||||
#include <machine/db_machdep.h> /* PC_REGS */
|
||||
#include <machine/cpuvar.h> /* cpu_vendor */
|
||||
#include <machine/cputypes.h> /* CPUVENDER_* */
|
||||
|
@ -99,6 +101,8 @@ static uint64_t counter_val = 5000000;
|
|||
static uint64_t counter_reset_val;
|
||||
static uint32_t tprof_pmi_lapic_saved[MAXCPUS];
|
||||
|
||||
static nmi_handler_t *tprof_pmi_nmi_handle;
|
||||
|
||||
static void
|
||||
tprof_pmi_start_cpu(void *arg1, void *arg2)
|
||||
{
|
||||
|
@ -150,55 +154,16 @@ tprof_pmi_stop_cpu(void *arg1, void *arg2)
|
|||
i82489_writereg(LAPIC_PCINT, tprof_pmi_lapic_saved[cpu_index(ci)]);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
tprof_backend_estimate_freq(void)
|
||||
{
|
||||
uint64_t cpufreq = curcpu()->ci_data.cpu_cc_freq;
|
||||
uint64_t freq = 10000;
|
||||
|
||||
counter_val = cpufreq / freq;
|
||||
if (counter_val == 0) {
|
||||
counter_val = UINT64_C(4000000000) / freq;
|
||||
return freq;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
int
|
||||
tprof_backend_start(void)
|
||||
{
|
||||
struct cpu_info * const ci = curcpu();
|
||||
uint64_t xc;
|
||||
|
||||
if (!(cpu_vendor == CPUVENDOR_INTEL &&
|
||||
CPUID2FAMILY(ci->ci_signature) == 15)) {
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
counter_reset_val = - counter_val + 1;
|
||||
xc = xc_broadcast(0, tprof_pmi_start_cpu, NULL, NULL);
|
||||
xc_wait(xc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
tprof_backend_stop(void)
|
||||
{
|
||||
uint64_t xc;
|
||||
|
||||
xc = xc_broadcast(0, tprof_pmi_stop_cpu, NULL, NULL);
|
||||
xc_wait(xc);
|
||||
}
|
||||
|
||||
int
|
||||
tprof_pmi_nmi(const struct trapframe *tf)
|
||||
static int
|
||||
tprof_pmi_nmi(const struct trapframe *tf, void *dummy)
|
||||
{
|
||||
struct cpu_info * const ci = curcpu();
|
||||
const struct msrs *msr;
|
||||
uint32_t pcint;
|
||||
uint64_t cccr;
|
||||
|
||||
KASSERT(dummy == NULL);
|
||||
|
||||
if (ci->ci_smtid >= 2) {
|
||||
/* not ours */
|
||||
return 0;
|
||||
|
@ -226,3 +191,51 @@ tprof_pmi_nmi(const struct trapframe *tf)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
tprof_backend_estimate_freq(void)
|
||||
{
|
||||
uint64_t cpufreq = curcpu()->ci_data.cpu_cc_freq;
|
||||
uint64_t freq = 10000;
|
||||
|
||||
counter_val = cpufreq / freq;
|
||||
if (counter_val == 0) {
|
||||
counter_val = UINT64_C(4000000000) / freq;
|
||||
return freq;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
int
|
||||
tprof_backend_start(void)
|
||||
{
|
||||
struct cpu_info * const ci = curcpu();
|
||||
uint64_t xc;
|
||||
|
||||
if (!(cpu_vendor == CPUVENDOR_INTEL &&
|
||||
CPUID2FAMILY(ci->ci_signature) == 15)) {
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
KASSERT(tprof_pmi_nmi_handle == NULL);
|
||||
tprof_pmi_nmi_handle = nmi_establish(tprof_pmi_nmi, NULL);
|
||||
|
||||
counter_reset_val = - counter_val + 1;
|
||||
xc = xc_broadcast(0, tprof_pmi_start_cpu, NULL, NULL);
|
||||
xc_wait(xc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
tprof_backend_stop(void)
|
||||
{
|
||||
uint64_t xc;
|
||||
|
||||
xc = xc_broadcast(0, tprof_pmi_stop_cpu, NULL, NULL);
|
||||
xc_wait(xc);
|
||||
|
||||
KASSERT(tprof_pmi_nmi_handle != NULL);
|
||||
nmi_disestablish(tprof_pmi_nmi_handle);
|
||||
tprof_pmi_nmi_handle = NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue