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;
+	}
+}

Reply via email to