7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * CDDL HEADER START
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * The contents of this file are subject to the terms of the
3ad553a7dabf3c8bcb69dd1ceeb13938fa526aedgavinm * Common Development and Distribution License (the "License").
3ad553a7dabf3c8bcb69dd1ceeb13938fa526aedgavinm * You may not use this file except in compliance with the License.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * or http://www.opensolaris.org/os/licensing.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * See the License for the specific language governing permissions
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * and limitations under the License.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * When distributing Covered Code, include this CDDL HEADER in each
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If applicable, add the following below this CDDL HEADER, with the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * fields enclosed by brackets "[]" replaced with your own identifying
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * information: Portions Copyright [yyyy] [name of copyright owner]
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * CDDL HEADER END
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*
e3d60c9bd991a9826cbfa63b10595d44e123b9c4Adrian Frost * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Use is subject to license terms.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Copyright (c) 2010, Intel Corporation.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * All rights reserved.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Generic x86 CPU Module
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * This CPU module is used for generic x86 CPUs when Solaris has no other
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * CPU-specific support module available. Code in this module should be the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * absolute bare-bones support and must be cognizant of both Intel and AMD etc.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/types.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/cpu_module_impl.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/cpuvar.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/kmem.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/modctl.h>
20c794b39650d115e17a15983b6b82e46238cf45gavinm#include <sys/pghw.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "gcpu.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
20c794b39650d115e17a15983b6b82e46238cf45gavinm/*
20c794b39650d115e17a15983b6b82e46238cf45gavinm * Prevent generic cpu support from loading.
20c794b39650d115e17a15983b6b82e46238cf45gavinm */
20c794b39650d115e17a15983b6b82e46238cf45gavinmint gcpu_disable = 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
20c794b39650d115e17a15983b6b82e46238cf45gavinm#define GCPU_MAX_CHIPID 32
20c794b39650d115e17a15983b6b82e46238cf45gavinmstatic struct gcpu_chipshared *gcpu_shared[GCPU_MAX_CHIPID];
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
20c794b39650d115e17a15983b6b82e46238cf45gavinm/*
20c794b39650d115e17a15983b6b82e46238cf45gavinm * Our cmi_init entry point, called during startup of each cpu instance.
20c794b39650d115e17a15983b6b82e46238cf45gavinm */
20c794b39650d115e17a15983b6b82e46238cf45gavinmint
20c794b39650d115e17a15983b6b82e46238cf45gavinmgcpu_init(cmi_hdl_t hdl, void **datap)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
20c794b39650d115e17a15983b6b82e46238cf45gavinm uint_t chipid = cmi_hdl_chipid(hdl);
20c794b39650d115e17a15983b6b82e46238cf45gavinm struct gcpu_chipshared *sp, *osp;
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_data_t *gcpu;
20c794b39650d115e17a15983b6b82e46238cf45gavinm
20c794b39650d115e17a15983b6b82e46238cf45gavinm if (gcpu_disable || chipid >= GCPU_MAX_CHIPID)
20c794b39650d115e17a15983b6b82e46238cf45gavinm return (ENOTSUP);
20c794b39650d115e17a15983b6b82e46238cf45gavinm
20c794b39650d115e17a15983b6b82e46238cf45gavinm /*
20c794b39650d115e17a15983b6b82e46238cf45gavinm * Allocate the state structure for this cpu. We will only
20c794b39650d115e17a15983b6b82e46238cf45gavinm * allocate the bank logout areas in gcpu_mca_init once we
20c794b39650d115e17a15983b6b82e46238cf45gavinm * know how many banks there are.
20c794b39650d115e17a15983b6b82e46238cf45gavinm */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu = *datap = kmem_zalloc(sizeof (gcpu_data_t), KM_SLEEP);
20c794b39650d115e17a15983b6b82e46238cf45gavinm cmi_hdl_hold(hdl); /* release in gcpu_fini */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu->gcpu_hdl = hdl;
20c794b39650d115e17a15983b6b82e46238cf45gavinm
20c794b39650d115e17a15983b6b82e46238cf45gavinm /*
20c794b39650d115e17a15983b6b82e46238cf45gavinm * Allocate a chipshared structure if no sibling cpu has already
20c794b39650d115e17a15983b6b82e46238cf45gavinm * allocated it, but allow for the fact that a sibling core may
20c794b39650d115e17a15983b6b82e46238cf45gavinm * be starting up in parallel.
20c794b39650d115e17a15983b6b82e46238cf45gavinm */
20c794b39650d115e17a15983b6b82e46238cf45gavinm if ((sp = gcpu_shared[chipid]) == NULL) {
20c794b39650d115e17a15983b6b82e46238cf45gavinm sp = kmem_zalloc(sizeof (struct gcpu_chipshared), KM_SLEEP);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_init(&sp->gcpus_poll_lock, NULL, MUTEX_DRIVER, NULL);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_init(&sp->gcpus_cfglock, NULL, MUTEX_DRIVER, NULL);
20c794b39650d115e17a15983b6b82e46238cf45gavinm osp = atomic_cas_ptr(&gcpu_shared[chipid], NULL, sp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (osp != NULL) {
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_destroy(&sp->gcpus_cfglock);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu mutex_destroy(&sp->gcpus_poll_lock);
20c794b39650d115e17a15983b6b82e46238cf45gavinm kmem_free(sp, sizeof (struct gcpu_chipshared));
20c794b39650d115e17a15983b6b82e46238cf45gavinm sp = osp;
20c794b39650d115e17a15983b6b82e46238cf45gavinm }
20c794b39650d115e17a15983b6b82e46238cf45gavinm }
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu atomic_inc_32(&sp->gcpus_actv_cnt);
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu->gcpu_shared = sp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu/*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * deconfigure gcpu_init()
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liuvoid
a31148363f598def767ac48c5d82e1572e44b935Gerry Liugcpu_fini(cmi_hdl_t hdl)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu uint_t chipid = cmi_hdl_chipid(hdl);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu struct gcpu_chipshared *sp;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (gcpu_disable || chipid >= GCPU_MAX_CHIPID)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu return;
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu gcpu_mca_fini(hdl);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Keep shared data in cache for reuse.
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu sp = gcpu_shared[chipid];
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(sp != NULL);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu atomic_dec_32(&sp->gcpus_actv_cnt);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (gcpu != NULL)
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu kmem_free(gcpu, sizeof (gcpu_data_t));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /* Release reference count held in gcpu_init(). */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu cmi_hdl_rele(hdl);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu}
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu
20c794b39650d115e17a15983b6b82e46238cf45gavinmvoid
20c794b39650d115e17a15983b6b82e46238cf45gavinmgcpu_post_startup(cmi_hdl_t hdl)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl);
20c794b39650d115e17a15983b6b82e46238cf45gavinm
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (gcpu_disable)
20c794b39650d115e17a15983b6b82e46238cf45gavinm return;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (gcpu != NULL)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye cms_post_startup(hdl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#ifdef __xpv
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye /*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * All cpu handles are initialized so we can begin polling now.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * Furthermore, our virq mechanism requires that everything
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * be run on cpu 0 so we can assure that by starting from here.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye gcpu_mca_poll_start(hdl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif
20c794b39650d115e17a15983b6b82e46238cf45gavinm}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
20c794b39650d115e17a15983b6b82e46238cf45gavinmvoid
20c794b39650d115e17a15983b6b82e46238cf45gavinmgcpu_post_mpstartup(cmi_hdl_t hdl)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye{
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (gcpu_disable)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye return;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye cms_post_mpstartup(hdl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#ifndef __xpv
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye /*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * All cpu handles are initialized only once all cpus
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * are started, so we can begin polling post mp startup.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_mca_poll_start(hdl);
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#ifdef __xpv
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#define GCPU_OP(ntvop, xpvop) xpvop
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#else
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#define GCPU_OP(ntvop, xpvop) ntvop
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye#endif
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yecmi_api_ver_t _cmi_api_version = CMI_API_VERSION_3;
20c794b39650d115e17a15983b6b82e46238cf45gavinm
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiconst cmi_ops_t _cmi_ops = {
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_init, /* cmi_init */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_post_startup, /* cmi_post_startup */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_post_mpstartup, /* cmi_post_mpstartup */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_faulted_enter, /* cmi_faulted_enter */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_faulted_exit, /* cmi_faulted_exit */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_mca_init, /* cmi_mca_init */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye GCPU_OP(gcpu_mca_trap, NULL), /* cmi_mca_trap */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye GCPU_OP(gcpu_cmci_trap, NULL), /* cmi_cmci_trap */
20c794b39650d115e17a15983b6b82e46238cf45gavinm gcpu_msrinject, /* cmi_msrinject */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye GCPU_OP(gcpu_hdl_poke, NULL), /* cmi_hdl_poke */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu gcpu_fini, /* cmi_fini */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye GCPU_OP(NULL, gcpu_xpv_panic_callback), /* cmi_panic_callback */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi};
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic struct modlcpu modlcpu = {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi &mod_cpuops,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "Generic x86 CPU Module"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi};
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic struct modlinkage modlinkage = {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi MODREV_1,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void *)&modlcpu,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi NULL
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi};
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiint
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi_init(void)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mod_install(&modlinkage));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiint
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi_info(struct modinfo *modinfop)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mod_info(&modlinkage, modinfop));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiint
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi_fini(void)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mod_remove(&modlinkage));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}