NetBSD-5.0.2/sys/arch/x86/x86/msr_ipifuncs.c

Compare this file to the similar file:
Show the results in this format:

/* $NetBSD: msr_ipifuncs.c,v 1.15 2008/01/04 21:17:45 ad Exp $ */

/*-
 * Copyright (c) 2007 Juan Romero Pardines.
 * 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 ``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 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 handler to make 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.15 2008/01/04 21:17:45 ad Exp $");

#include "opt_multiprocessor.h"

#include <sys/param.h>
#include <sys/mutex.h>
#include <sys/atomic.h>
#include <sys/cpu.h>

#include <x86/cpu_msr.h>

#include <machine/intrdefs.h>
#include <machine/cpufunc.h>

static kmutex_t msr_mtx;
static volatile uint64_t msr_setvalue, msr_setmask;
static volatile int msr_type, msr_read;
static volatile u_int 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.
 */
void
msr_write_ipi(struct cpu_info *ci)
{
	uint64_t msr = 0;

	/* Read the MSR requested and apply the mask if defined. */
	if (msr_read)
		msr = rdmsr(msr_type);

	if (msr_setmask)
		msr &= ~msr_setmask;

	/* Ok, assign value now.*/
	if (msr_read)
		msr |= msr_setvalue;
	else
		msr = msr_setvalue;

	/* Write it now */
	wrmsr(msr_type, msr);

	/* This cpu has finished making all tasks, update the counter. */
	atomic_inc_uint(&msr_runcount);
}

/*
 * Main function. Assigns values provided by the driver into the global
 * variables, necessary for the IPI handler.
 */
void
msr_cpu_broadcast(struct msr_cpu_broadcast *mcb)
{

	if (!mcb->msr_type)
		panic("msr_type not defined");

	/* 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 = 0;

	/* Assign requested MSR type, value and mask. */
	msr_type = mcb->msr_type;
	msr_setvalue = mcb->msr_value;
	msr_setmask = mcb->msr_mask;
	msr_read = mcb->msr_read;

	/* 
	 * Issue a full memory barrier, to make sure the operations
	 * are done in a serialized way.
	 */
	membar_sync();

	/* 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

	while (msr_runcount < ncpu)
		x86_pause();

	/* We're done, so unlock. */
	mutex_exit(&msr_mtx);
}

/* 
 * Initializes the mutex very early in the boot process
 * for future access.
 */
void
msr_cpu_broadcast_initmtx(void)
{

	mutex_init(&msr_mtx, MUTEX_DEFAULT, IPL_NONE);
}