Module Name: src Committed By: maxv Date: Mon Jul 16 06:18:31 UTC 2018
Modified Files: src/sys/arch/x86/conf: files.x86 src/sys/modules/tprof_amdpmi: Makefile src/sys/modules/tprof_pmi: Makefile Added Files: src/sys/dev/tprof: tprof_x86_amd.c tprof_x86_intel.c Removed Files: src/sys/arch/x86/x86: tprof_amdpmi.c tprof_pmi.c Log Message: Move arch/x86/x86/tprof_pmi.c arch/x86/x86/tprof_amdpmi.c into dev/tprof/tprof_x86_intel.c dev/tprof/tprof_x86_amd.c To generate a diff of this commit: cvs rdiff -u -r1.102 -r1.103 src/sys/arch/x86/conf/files.x86 cvs rdiff -u -r1.9 -r0 src/sys/arch/x86/x86/tprof_amdpmi.c cvs rdiff -u -r1.16 -r0 src/sys/arch/x86/x86/tprof_pmi.c cvs rdiff -u -r0 -r1.1 src/sys/dev/tprof/tprof_x86_amd.c \ src/sys/dev/tprof/tprof_x86_intel.c cvs rdiff -u -r1.1 -r1.2 src/sys/modules/tprof_amdpmi/Makefile cvs rdiff -u -r1.1 -r1.2 src/sys/modules/tprof_pmi/Makefile Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/x86/conf/files.x86 diff -u src/sys/arch/x86/conf/files.x86:1.102 src/sys/arch/x86/conf/files.x86:1.103 --- src/sys/arch/x86/conf/files.x86:1.102 Fri Jul 13 09:37:32 2018 +++ src/sys/arch/x86/conf/files.x86 Mon Jul 16 06:18:31 2018 @@ -1,4 +1,4 @@ -# $NetBSD: files.x86,v 1.102 2018/07/13 09:37:32 maxv Exp $ +# $NetBSD: files.x86,v 1.103 2018/07/16 06:18:31 maxv Exp $ # options for MP configuration through the MP spec defflag opt_mpbios.h MPBIOS MPDEBUG MPBIOS_SCANPCI @@ -149,9 +149,6 @@ file arch/x86/x86/ipmi.c ipmi needs-fla file arch/x86/x86/vga_post.c vga_post -file arch/x86/x86/tprof_pmi.c tprof_pmi -file arch/x86/x86/tprof_amdpmi.c tprof_amdpmi - file arch/x86/pci/pci_machdep.c pci #file arch/x86/pci/pci_ranges.c pci file arch/x86/pci/pci_intr_machdep.c pci Index: src/sys/modules/tprof_amdpmi/Makefile diff -u src/sys/modules/tprof_amdpmi/Makefile:1.1 src/sys/modules/tprof_amdpmi/Makefile:1.2 --- src/sys/modules/tprof_amdpmi/Makefile:1.1 Sun Feb 6 02:28:50 2011 +++ src/sys/modules/tprof_amdpmi/Makefile Mon Jul 16 06:18:31 2018 @@ -1,12 +1,12 @@ -# $NetBSD: Makefile,v 1.1 2011/02/06 02:28:50 yamt Exp $ +# $NetBSD: Makefile,v 1.2 2018/07/16 06:18:31 maxv Exp $ .include "../Makefile.inc" CPPFLAGS+= -.PATH: ${S}/arch/x86/x86 +.PATH: ${S}/dev/tprof KMOD= tprof_amdpmi -SRCS= tprof_amdpmi.c +SRCS= tprof_x86_amd.c .include <bsd.kmodule.mk> Index: src/sys/modules/tprof_pmi/Makefile diff -u src/sys/modules/tprof_pmi/Makefile:1.1 src/sys/modules/tprof_pmi/Makefile:1.2 --- src/sys/modules/tprof_pmi/Makefile:1.1 Tue Mar 10 14:49:50 2009 +++ src/sys/modules/tprof_pmi/Makefile Mon Jul 16 06:18:31 2018 @@ -1,12 +1,12 @@ -# $NetBSD: Makefile,v 1.1 2009/03/10 14:49:50 yamt Exp $ +# $NetBSD: Makefile,v 1.2 2018/07/16 06:18:31 maxv Exp $ .include "../Makefile.inc" CPPFLAGS+= -.PATH: ${S}/arch/x86/x86 +.PATH: ${S}/dev/tprof KMOD= tprof_pmi -SRCS= tprof_pmi.c +SRCS= tprof_x86_intel.c .include <bsd.kmodule.mk> Added files: Index: src/sys/dev/tprof/tprof_x86_amd.c diff -u /dev/null src/sys/dev/tprof/tprof_x86_amd.c:1.1 --- /dev/null Mon Jul 16 06:18:31 2018 +++ src/sys/dev/tprof/tprof_x86_amd.c Mon Jul 16 06:18:31 2018 @@ -0,0 +1,272 @@ +/* $NetBSD: tprof_x86_amd.c,v 1.1 2018/07/16 06:18:31 maxv Exp $ */ + +/* + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Maxime Villard. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c)2008,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: tprof_x86_amd.c,v 1.1 2018/07/16 06:18:31 maxv Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> + +#include <sys/cpu.h> +#include <sys/xcall.h> + +#include <dev/tprof/tprof.h> + +#include <uvm/uvm.h> /* VM_MIN_KERNEL_ADDRESS */ + +#include <x86/nmi.h> + +#include <machine/cpufunc.h> +#include <machine/cputypes.h> /* CPUVENDOR_* */ +#include <machine/cpuvar.h> /* cpu_vendor */ +#include <machine/i82489reg.h> +#include <machine/i82489var.h> + +#define NCTRS 4 + +#define PERFEVTSEL(i) (0xc0010000 + (i)) +#define PERFCTR(i) (0xc0010004 + (i)) + +#define PESR_EVENT_MASK_LO __BITS(0, 7) +#define PESR_UNIT_MASK __BITS(8, 15) +#define PESR_USR __BIT(16) +#define PESR_OS __BIT(17) +#define PESR_E __BIT(18) +#define PESR_PC __BIT(19) +#define PESR_INT __BIT(20) + /* bit 21 reserved */ +#define PESR_EN __BIT(22) +#define PESR_INV __BIT(23) +#define PESR_COUNTER_MASK __BITS(24, 31) +#define PESR_EVENT_MASK_HI __BITS(32, 35) + /* bit 36-39 reserved */ +#define PESR_GO __BIT(40) +#define PESR_HO __BIT(41) + /* bit 42-63 reserved */ + +/* + * Documents: + * http://support.amd.com/TechDocs/32559.pdf + * http://developer.amd.com/wordpress/media/2012/10/Basic_Performance_Measurements.pdf + */ + +static int ctrno = 0; +static uint64_t counter_val = 5000000; +static uint64_t counter_reset_val; +static uint32_t amd_lapic_saved[MAXCPUS]; +static nmi_handler_t *amd_nmi_handle; +static tprof_param_t amd_param; + +static void +tprof_amd_start_cpu(void *arg1, void *arg2) +{ + struct cpu_info * const ci = curcpu(); + uint64_t pesr; + uint64_t event_lo; + uint64_t event_hi; + + event_hi = amd_param.p_event >> 8; + event_lo = amd_param.p_event & 0xff; + pesr = + ((amd_param.p_flags & TPROF_PARAM_USER) ? PESR_USR : 0) | + ((amd_param.p_flags & TPROF_PARAM_KERN) ? PESR_OS : 0) | + PESR_INT | + __SHIFTIN(event_lo, PESR_EVENT_MASK_LO) | + __SHIFTIN(event_hi, PESR_EVENT_MASK_HI) | + __SHIFTIN(0, PESR_COUNTER_MASK) | + __SHIFTIN(amd_param.p_unit, PESR_UNIT_MASK); + + wrmsr(PERFCTR(ctrno), counter_reset_val); + wrmsr(PERFEVTSEL(ctrno), pesr); + + amd_lapic_saved[cpu_index(ci)] = lapic_readreg(LAPIC_PCINT); + lapic_writereg(LAPIC_PCINT, LAPIC_DLMODE_NMI); + + wrmsr(PERFEVTSEL(ctrno), pesr | PESR_EN); +} + +static void +tprof_amd_stop_cpu(void *arg1, void *arg2) +{ + struct cpu_info * const ci = curcpu(); + + wrmsr(PERFEVTSEL(ctrno), 0); + + lapic_writereg(LAPIC_PCINT, amd_lapic_saved[cpu_index(ci)]); +} + +static int +tprof_amd_nmi(const struct trapframe *tf, void *dummy) +{ + tprof_frame_info_t tfi; + uint64_t ctr; + + KASSERT(dummy == NULL); + + /* check if it's for us */ + ctr = rdmsr(PERFCTR(ctrno)); + if ((ctr & (UINT64_C(1) << 63)) != 0) { /* check if overflowed */ + /* not ours */ + return 0; + } + + /* record a sample */ +#if defined(__x86_64__) + tfi.tfi_pc = tf->tf_rip; +#else + tfi.tfi_pc = tf->tf_eip; +#endif + tfi.tfi_inkernel = tfi.tfi_pc >= VM_MIN_KERNEL_ADDRESS; + tprof_sample(NULL, &tfi); + + /* reset counter */ + wrmsr(PERFCTR(ctrno), counter_reset_val); + + return 1; +} + +static uint64_t +tprof_amd_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; +} + +static uint32_t +tprof_amd_ident(void) +{ + struct cpu_info *ci = curcpu(); + + if (cpu_vendor != CPUVENDOR_AMD) { + return TPROF_IDENT_NONE; + } + + switch (CPUID_TO_FAMILY(ci->ci_signature)) { + case 0x10: + return TPROF_IDENT_AMD_GENERIC; + } + + return TPROF_IDENT_NONE; +} + +static int +tprof_amd_start(const tprof_param_t *param) +{ + uint64_t xc; + + if (tprof_amd_ident() == TPROF_IDENT_NONE) { + return ENOTSUP; + } + + KASSERT(amd_nmi_handle == NULL); + amd_nmi_handle = nmi_establish(tprof_amd_nmi, NULL); + + counter_reset_val = - counter_val + 1; + memcpy(&amd_param, param, sizeof(*param)); + + xc = xc_broadcast(0, tprof_amd_start_cpu, NULL, NULL); + xc_wait(xc); + + return 0; +} + +static void +tprof_amd_stop(const tprof_param_t *param) +{ + uint64_t xc; + + xc = xc_broadcast(0, tprof_amd_stop_cpu, NULL, NULL); + xc_wait(xc); + + KASSERT(amd_nmi_handle != NULL); + nmi_disestablish(amd_nmi_handle); + amd_nmi_handle = NULL; +} + +static const tprof_backend_ops_t tprof_amd_ops = { + .tbo_estimate_freq = tprof_amd_estimate_freq, + .tbo_ident = tprof_amd_ident, + .tbo_start = tprof_amd_start, + .tbo_stop = tprof_amd_stop, +}; + +MODULE(MODULE_CLASS_DRIVER, tprof_amdpmi, "tprof"); + +static int +tprof_amdpmi_modcmd(modcmd_t cmd, void *arg) +{ + + switch (cmd) { + case MODULE_CMD_INIT: + return tprof_backend_register("tprof_amd", &tprof_amd_ops, + TPROF_BACKEND_VERSION); + + case MODULE_CMD_FINI: + return tprof_backend_unregister("tprof_amd"); + + default: + return ENOTTY; + } +} Index: src/sys/dev/tprof/tprof_x86_intel.c diff -u /dev/null src/sys/dev/tprof/tprof_x86_intel.c:1.1 --- /dev/null Mon Jul 16 06:18:31 2018 +++ src/sys/dev/tprof/tprof_x86_intel.c Mon Jul 16 06:18:31 2018 @@ -0,0 +1,268 @@ +/* $NetBSD: tprof_x86_intel.c,v 1.1 2018/07/16 06:18:31 maxv Exp $ */ + +/* + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Maxime Villard. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c)2008,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: tprof_x86_intel.c,v 1.1 2018/07/16 06:18:31 maxv Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/module.h> + +#include <sys/cpu.h> +#include <sys/xcall.h> + +#include <dev/tprof/tprof.h> + +#include <uvm/uvm.h> /* VM_MIN_KERNEL_ADDRESS */ + +#include <x86/nmi.h> + +#include <machine/cpufunc.h> +#include <machine/cputypes.h> /* CPUVENDOR_* */ +#include <machine/cpuvar.h> /* cpu_vendor */ +#include <machine/i82489reg.h> +#include <machine/i82489var.h> + +#define PERFEVTSEL_EVENT_SELECT __BITS(0, 7) +#define PERFEVTSEL_UNIT_MASK __BITS(8, 15) +#define PERFEVTSEL_USR __BIT(16) +#define PERFEVTSEL_OS __BIT(17) +#define PERFEVTSEL_E __BIT(18) +#define PERFEVTSEL_PC __BIT(19) +#define PERFEVTSEL_INT __BIT(20) +#define PERFEVTSEL_EN __BIT(22) +#define PERFEVTSEL_INV __BIT(23) +#define PERFEVTSEL_COUNTER_MASK __BITS(24, 31) + +#define CPUID_0A_VERSION __BITS(0, 7) +#define CPUID_0A_NCOUNTERS __BITS(8, 15) +#define CPUID_0A_BITWIDTH __BITS(16, 23) + +static uint64_t counter_bitwidth; +static uint64_t counter_val = 5000000; +static uint64_t counter_reset_val; + +static uint32_t intel_lapic_saved[MAXCPUS]; +static nmi_handler_t *intel_nmi_handle; +static tprof_param_t intel_param; + +static void +tprof_intel_start_cpu(void *arg1, void *arg2) +{ + struct cpu_info * const ci = curcpu(); + uint64_t evtval; + + evtval = + __SHIFTIN(intel_param.p_event, PERFEVTSEL_EVENT_SELECT) | + __SHIFTIN(intel_param.p_unit, PERFEVTSEL_UNIT_MASK) | + ((intel_param.p_flags & TPROF_PARAM_USER) ? PERFEVTSEL_USR : 0) | + ((intel_param.p_flags & TPROF_PARAM_KERN) ? PERFEVTSEL_OS : 0) | + PERFEVTSEL_INT | + PERFEVTSEL_EN; + + wrmsr(MSR_PERFCTR0, counter_reset_val); + wrmsr(MSR_EVNTSEL0, evtval); + + intel_lapic_saved[cpu_index(ci)] = lapic_readreg(LAPIC_PCINT); + lapic_writereg(LAPIC_PCINT, LAPIC_DLMODE_NMI); +} + +static void +tprof_intel_stop_cpu(void *arg1, void *arg2) +{ + struct cpu_info * const ci = curcpu(); + + wrmsr(MSR_EVNTSEL0, 0); + wrmsr(MSR_PERFCTR0, 0); + + lapic_writereg(LAPIC_PCINT, intel_lapic_saved[cpu_index(ci)]); +} + +static int +tprof_intel_nmi(const struct trapframe *tf, void *dummy) +{ + uint32_t pcint; + uint64_t ctr; + tprof_frame_info_t tfi; + + KASSERT(dummy == NULL); + + ctr = rdmsr(MSR_PERFCTR0); + /* If the highest bit is non zero, then it's not for us. */ + if ((ctr & __BIT(counter_bitwidth-1)) != 0) { + return 0; + } + + /* record a sample */ +#if defined(__x86_64__) + tfi.tfi_pc = tf->tf_rip; +#else + tfi.tfi_pc = tf->tf_eip; +#endif + tfi.tfi_inkernel = tfi.tfi_pc >= VM_MIN_KERNEL_ADDRESS; + tprof_sample(NULL, &tfi); + + /* reset counter */ + wrmsr(MSR_PERFCTR0, counter_reset_val); + + /* unmask PMI */ + pcint = lapic_readreg(LAPIC_PCINT); + KASSERT((pcint & LAPIC_LVT_MASKED) != 0); + lapic_writereg(LAPIC_PCINT, pcint & ~LAPIC_LVT_MASKED); + + return 1; +} + +static uint64_t +tprof_intel_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; +} + +static uint32_t +tprof_intel_ident(void) +{ + uint32_t descs[4]; + + if (cpu_vendor != CPUVENDOR_INTEL) { + return TPROF_IDENT_NONE; + } + + if (cpuid_level < 0x0A) { + return TPROF_IDENT_NONE; + } + x86_cpuid(0x0A, descs); + if ((descs[0] & CPUID_0A_VERSION) == 0) { + return TPROF_IDENT_NONE; + } + if ((descs[0] & CPUID_0A_NCOUNTERS) == 0) { + return TPROF_IDENT_NONE; + } + + counter_bitwidth = __SHIFTOUT(descs[0], CPUID_0A_BITWIDTH); + + return TPROF_IDENT_INTEL_GENERIC; +} + +static int +tprof_intel_start(const tprof_param_t *param) +{ + uint64_t xc; + + if (tprof_intel_ident() == TPROF_IDENT_NONE) { + return ENOTSUP; + } + + KASSERT(intel_nmi_handle == NULL); + intel_nmi_handle = nmi_establish(tprof_intel_nmi, NULL); + + counter_reset_val = - counter_val + 1; + memcpy(&intel_param, param, sizeof(*param)); + + xc = xc_broadcast(0, tprof_intel_start_cpu, NULL, NULL); + xc_wait(xc); + + return 0; +} + +static void +tprof_intel_stop(const tprof_param_t *param) +{ + uint64_t xc; + + xc = xc_broadcast(0, tprof_intel_stop_cpu, NULL, NULL); + xc_wait(xc); + + KASSERT(intel_nmi_handle != NULL); + nmi_disestablish(intel_nmi_handle); + intel_nmi_handle = NULL; +} + +static const tprof_backend_ops_t tprof_intel_ops = { + .tbo_estimate_freq = tprof_intel_estimate_freq, + .tbo_ident = tprof_intel_ident, + .tbo_start = tprof_intel_start, + .tbo_stop = tprof_intel_stop, +}; + +MODULE(MODULE_CLASS_DRIVER, tprof_pmi, "tprof"); + +static int +tprof_pmi_modcmd(modcmd_t cmd, void *arg) +{ + + switch (cmd) { + case MODULE_CMD_INIT: + return tprof_backend_register("tprof_pmi", &tprof_intel_ops, + TPROF_BACKEND_VERSION); + + case MODULE_CMD_FINI: + return tprof_backend_unregister("tprof_pmi"); + + default: + return ENOTTY; + } +}