MSR read and write IPI handlers for x86. A MSR will be read or written

in all CPUs available in the system. This adds another member
to struct cpu_info, ci_msr_rvalue; it will contain the value of the MSR
in a previous operation.

Tested with clockmod in UP and SMP by me, tested with est in SMP
by Daniel Carosone and Michael Van Elst.

Ok'ed by Andrew Doran and Matthew R. Green.
This commit is contained in:
xtraeme 2007-03-20 21:07:38 +00:00
parent ac2ed142c1
commit 32b7185652
11 changed files with 380 additions and 16 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipifuncs.c,v 1.7 2007/02/09 21:55:01 ad Exp $ */
/* $NetBSD: ipifuncs.c,v 1.8 2007/03/20 21:07:39 xtraeme Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -40,7 +40,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.7 2007/02/09 21:55:01 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.8 2007/03/20 21:07:39 xtraeme Exp $");
/*
* Interprocessor interrupt handlers.
@ -65,6 +65,8 @@ __KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.7 2007/02/09 21:55:01 ad Exp $");
#include <machine/gdt.h>
#include <machine/fpu.h>
#include <x86/cpu_msr.h>
#include <ddb/db_output.h>
void x86_64_ipi_halt(struct cpu_info *);
@ -87,6 +89,8 @@ void (*ipifunc[X86_NIPI])(struct cpu_info *) =
pmap_do_tlb_shootdown,
x86_64_reload_mtrr,
gdt_reload_cpu,
msr_read_ipi,
msr_write_ipi
};
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.52 2007/03/04 14:36:11 yamt Exp $ */
/* $NetBSD: machdep.c,v 1.53 2007/03/20 21:07:39 xtraeme Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007
@ -73,7 +73,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.52 2007/03/04 14:36:11 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.53 2007/03/20 21:07:39 xtraeme Exp $");
#include "opt_user_ldt.h"
#include "opt_ddb.h"
@ -135,6 +135,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.52 2007/03/04 14:36:11 yamt Exp $");
#include <machine/fpu.h>
#include <machine/mtrr.h>
#include <machine/mpbiosvar.h>
#include <x86/cpu_msr.h>
#include <x86/x86/tsc.h>
#include <dev/isa/isareg.h>
@ -1527,6 +1528,8 @@ init_x86_64(paddr_t first_avail)
splraise(IPL_IPI);
enable_intr();
x86_init();
/* Make sure maxproc is sane */
if (maxproc > cpu_maxproc())
maxproc = cpu_maxproc();

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.19 2007/03/16 18:52:03 xtraeme Exp $ */
/* $NetBSD: cpu.h,v 1.20 2007/03/20 21:07:40 xtraeme Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -106,6 +106,8 @@ struct cpu_info {
u_int32_t ci_signature;
u_int64_t ci_tsc_freq;
uint64_t ci_msr_rvalue; /* per-cpu msr returned value */
const struct cpu_functions *ci_func;
void (*cpu_setup)(struct cpu_info *);
void (*ci_info)(struct cpu_info *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipifuncs.c,v 1.14 2007/02/09 21:55:04 ad Exp $ */
/* $NetBSD: ipifuncs.c,v 1.15 2007/03/20 21:07:39 xtraeme Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -44,7 +44,7 @@
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.14 2007/02/09 21:55:04 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.15 2007/03/20 21:07:39 xtraeme Exp $");
#include "opt_ddb.h"
#include "opt_mtrr.h"
@ -56,6 +56,7 @@ __KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.14 2007/02/09 21:55:04 ad Exp $");
#include <uvm/uvm_extern.h>
#include <x86/cpu_msr.h>
#include <machine/intr.h>
#include <machine/atomic.h>
#include <machine/cpuvar.h>
@ -96,6 +97,8 @@ void (*ipifunc[X86_NIPI])(struct cpu_info *) =
pmap_do_tlb_shootdown,
i386_reload_mtrr,
gdt_reload_cpu,
msr_read_ipi,
msr_write_ipi
};
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.601 2007/03/07 21:43:43 thorpej Exp $ */
/* $NetBSD: machdep.c,v 1.602 2007/03/20 21:07:39 xtraeme Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006 The NetBSD Foundation, Inc.
@ -72,7 +72,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.601 2007/03/07 21:43:43 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.602 2007/03/20 21:07:39 xtraeme Exp $");
#include "opt_beep.h"
#include "opt_compat_ibcs2.h"
@ -131,6 +131,8 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.601 2007/03/07 21:43:43 thorpej Exp $"
#include <sys/sysctl.h>
#include <x86/cpu_msr.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/cpuvar.h>
@ -488,6 +490,8 @@ cpu_startup()
/* Safe for i/o port / memory space allocation to use malloc now. */
x86_bus_space_mallocok();
x86_init();
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.137 2007/03/18 07:21:41 xtraeme Exp $ */
/* $NetBSD: cpu.h,v 1.138 2007/03/20 21:07:39 xtraeme Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -141,6 +141,8 @@ struct cpu_info {
uint32_t ci_cpu_serial[3]; /* PIII serial number */
uint64_t ci_tsc_freq; /* cpu cycles/second */
uint64_t ci_msr_rvalue; /* per-cpu MSR returned value */
const struct cpu_functions *ci_func; /* start/stop functions */
void (*cpu_setup)(struct cpu_info *);
/* proc-dependant init */

View File

@ -1,4 +1,4 @@
# $NetBSD: files.x86,v 1.26 2007/03/15 00:28:57 xtraeme Exp $
# $NetBSD: files.x86,v 1.27 2007/03/20 21:07:38 xtraeme Exp $
# options for MP configuration through the MP spec
defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI
@ -31,6 +31,7 @@ file arch/x86/x86/i8259.c
file arch/x86/x86/intr.c
file arch/x86/x86/ipi.c multiprocessor
file arch/x86/x86/lock_machdep.c lockdebug
file arch/x86/x86/msr_ipifuncs.c
file arch/x86/x86/mtrr_i686.c mtrr
file arch/x86/x86/patch.c
file arch/x86/x86/softintr.c

View File

@ -0,0 +1,66 @@
/* $NetBSD: cpu_msr.h,v 1.1 2007/03/20 21:07:38 xtraeme Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Juan Romero Pardines.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 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.
*/
#ifndef _X86_CPU_MSR_H
#define _X86_CPU_MSR_H
#include <sys/param.h>
#include <sys/mutex.h>
#include <machine/intrdefs.h>
#include <machine/cpu.h>
#ifdef _KERNEL
#define MSR_CPU_BROADCAST_READ 0x0001
#define MSR_CPU_BROADCAST_WRITE 0x0002
struct msr_cpu_broadcast {
int msr_type;
uint64_t msr_value;
uint64_t msr_mask;
};
void x86_init(void);
void msr_read_ipi(struct cpu_info *);
void msr_write_ipi(struct cpu_info *);
void msr_cpu_broadcast_initmtx(void);
int msr_cpu_broadcast(struct msr_cpu_broadcast *, int);
#endif /* ! _KERNEL */
#endif /* ! _X86_CPU_MSR_H */

View File

@ -1,4 +1,4 @@
/* $NetBSD: intrdefs.h,v 1.5 2005/11/03 13:06:06 yamt Exp $ */
/* $NetBSD: intrdefs.h,v 1.6 2007/03/20 21:07:39 xtraeme Exp $ */
#ifndef _X86_INTRDEFS_H_
#define _X86_INTRDEFS_H_
@ -81,12 +81,15 @@
#define X86_IPI_TLB 0x00000010
#define X86_IPI_MTRR 0x00000020
#define X86_IPI_GDT 0x00000040
#define X86_IPI_READ_MSR 0x00000080
#define X86_IPI_WRITE_MSR 0x00000100
#define X86_NIPI 7
#define X86_NIPI 9
#define X86_IPI_NAMES { "halt IPI", "timeset IPI", "FPU flush IPI", \
"FPU synch IPI", "TLB shootdown IPI", \
"MTRR update IPI", "GDT update IPI" }
"MTRR update IPI", "GDT update IPI", \
"MSR read IPI", "MSR write IPI" }
#define IREENT_MAGIC 0x18041969

View File

@ -0,0 +1,265 @@
/* $NetBSD: msr_ipifuncs.c,v 1.1 2007/03/20 21:07:39 xtraeme Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Juan Romero Pardines.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 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.
*/
/*
* Generic IPI handlers to make reads and writes to a MSR on x86, in
* all CPUs available in the system.
*
* Thanks to Andrew Doran, Michael Van Elst and Quentin Garnier for
* help and information provided.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: msr_ipifuncs.c,v 1.1 2007/03/20 21:07:39 xtraeme Exp $");
#include "opt_multiprocessor.h"
#include <sys/param.h>
#include <sys/mutex.h>
#include <sys/lock.h>
#include <x86/cpu_msr.h>
#include <machine/cpu.h>
#include <machine/intrdefs.h>
/* #define MSR_CPU_BROADCAST_DEBUG */
#ifdef MSR_CPU_BROADCAST_DEBUG
#define DPRINTF(x) do { printf x; } while (/* CONSTCOND */ 0)
#else
#define DPRINTF(x)
#endif
static kmutex_t msr_mtx;
static volatile uint64_t msr_setvalue;
static volatile uint64_t msr_setmask;
static volatile int msr_type;
static volatile int msr_runcount;
static void msr_cpu_broadcast_main(struct msr_cpu_broadcast *, int);
/*
* This function will read the value of the MSR defined in msr_type
* and will return it in ci_msr_rvalue (per-cpu).
*/
void
msr_read_ipi(struct cpu_info *ci)
{
/* Assign current value for the MSR msr_type. */
ci->ci_msr_rvalue = rdmsr(msr_type);
/*
* Increement the counter atomically, this cpu has
* finished the operation correctly.
*/
__asm volatile ("lock; incl (%0)" :: "r" (&msr_runcount));
}
/*
* This function will write the value of msr_setvalue in the MSR msr_type
* and if a mask is provided, the value will be masked with msr_setmask,
* also will update ci->ci_msr_rvalue with the returned value of the MSR,
* to avoid another run of msr_read_ipi in the main function.
*/
void
msr_write_ipi(struct cpu_info *ci)
{
uint64_t msr;
/* Read the MSR requested and apply the mask if defined. */
msr = rdmsr(msr_type);
if (msr_setmask)
msr &= ~msr_setmask;
/* Ok, assign value now.*/
msr |= msr_setvalue;
/* Write it now */
wrmsr(msr_type, msr);
/* Update our per-cpu variable with the current value of the MSR. */
ci->ci_msr_rvalue = rdmsr(msr_type);
/* This cpu has finished making all tasks, update the counter. */
__asm volatile ("lock; incl (%0)" :: "r" (&msr_runcount));
}
/*
* Main function. Assigns values provided by the driver into the global
* variables, necessary for the IPI handlers. If mode is true, a write
* operation will be performed, otherwise a read operation.
*/
static void
msr_cpu_broadcast_main(struct msr_cpu_broadcast *mcb, int mode)
{
CPU_INFO_ITERATOR cii;
struct cpu_info *ci;
DPRINTF(("\n%s: ---- START ----\n", __func__));
/* We only want one CPU at a time sending these IPIs out. */
mutex_enter(&msr_mtx);
/* Initialize counter, the task has not run in any cpu yet. */
msr_runcount = msr_setmask = msr_setvalue = 0;
/* Assign requested MSR type, value and mask. */
msr_type = mcb->msr_type;
if (mode) {
msr_setvalue = mcb->msr_value;
msr_setmask = mcb->msr_mask;
}
/*
* Issue a full memory barrier, to make sure the operations
* are done in a serialized way.
*/
mb_memory();
if (mode) { /* Write mode */
DPRINTF(("%s: before write\n", __func__));
/* Run the IPI write handler in the CPUs. */
msr_write_ipi(curcpu());
#ifdef MULTIPROCESSOR
if (ncpu > 1)
x86_broadcast_ipi(X86_IPI_WRITE_MSR);
#endif
DPRINTF(("%s: after write\n", __func__));
} else { /* Read mode */
DPRINTF(("%s: before read\n", __func__));
/* Run the IPI read handler in the CPUs. */
msr_read_ipi(curcpu());
#ifdef MULTIPROCESSOR
if (ncpu > 1)
x86_broadcast_ipi(X86_IPI_READ_MSR);
#endif
DPRINTF(("%s: after read\n", __func__));
}
DPRINTF(("%s: before pause\n", __func__));
DPRINTF(("%s: msr_runcount=%d ncpu=%d\n", __func__,
msr_runcount, ncpu));
/* Spin until every CPU has run the handler. */
while (msr_runcount < ncpu)
x86_pause();
DPRINTF(("%s: after pause\n", __func__));
for (CPU_INFO_FOREACH(cii, ci)) {
DPRINTF(("%s: ci_msr_rvalue=0x%" PRIu64 "\n",
ci->ci_dev->dv_xname, ci->ci_msr_rvalue));
}
/* We're done, so unlock. */
mutex_exit(&msr_mtx);
DPRINTF(("%s: ----- END -----\n\n", __func__));
}
/*
* Initializes the mutex very early in the boot process
* for future access.
*/
void
msr_cpu_broadcast_initmtx(void)
{
mutex_init(&msr_mtx, MUTEX_DRIVER, IPL_NONE);
}
/*
* This is the function used by the drivers using this framework.
* The driver is reponsible to set apropiately its members:
*
* mcb->msr_type type of the MSR requested by the driver,
* e.g MSR_PERF_STATUS.
*
* mcb->msr_value value that will be set in the MSR, when a
* write operation is requested by the driver.
*
* mcb->msr_mask value that will be used to mask the returned
* value of the rdmsr(msr_type) call in the write
* operation.
*
* msr_type needs to be defined, otherwise EINVAL is returned.
*
* When calling this function, a mode must be selected. Currently
* two modes are implemented:
*
* MSR_CPU_BROADCAST_READ Performs a read operation.
*
* MSR_CPU_BROADCAST_WRITE Performs a write operation.
*
* If an invalid mode is specified, EINVAL is returned.
*/
int
msr_cpu_broadcast(struct msr_cpu_broadcast *mcb, int mode)
{
if (!mcb->msr_type) {
DPRINTF(("%s: msr_type is empty\n", __func__));
return EINVAL;
}
DPRINTF(("%s: mcb->msr_value=%" PRIu64 " mcb->msr_type=%d "
"mcb->msr_mask=%" PRIu64 "\n", __func__,
mcb->msr_value, mcb->msr_type, mcb->msr_mask));
switch (mode) {
case MSR_CPU_BROADCAST_READ:
msr_cpu_broadcast_main(mcb, false);
break;
case MSR_CPU_BROADCAST_WRITE:
msr_cpu_broadcast_main(mcb, true);
break;
default:
return EINVAL;
}
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: x86_machdep.c,v 1.8 2007/03/01 11:49:26 yamt Exp $ */
/* $NetBSD: x86_machdep.c,v 1.9 2007/03/20 21:07:39 xtraeme Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.8 2007/03/01 11:49:26 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.9 2007/03/20 21:07:39 xtraeme Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -46,6 +46,8 @@ __KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.8 2007/03/01 11:49:26 yamt Exp $")
#include <sys/errno.h>
#include <sys/kauth.h>
#include <x86/cpu_msr.h>
#include <machine/bootinfo.h>
#include <machine/vmparam.h>
@ -125,3 +127,12 @@ x86_pause(void)
{
__asm volatile("pause");
}
/*
* This function is to initialize the mutex used by x86/msr_ipifuncs.c.
*/
void
x86_init(void)
{
msr_cpu_broadcast_initmtx();
}