1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * The CPU module for the AMD Athlon64 and Opteron processors 31 */ 32 33 #include <sys/types.h> 34 #include <sys/cmn_err.h> 35 #include <sys/sunddi.h> 36 #include <sys/cpu_module_impl.h> 37 #include <sys/cpuvar.h> 38 #include <sys/x86_archext.h> 39 #include <sys/kmem.h> 40 #include <sys/modctl.h> 41 #include <sys/mc.h> 42 #include <sys/mca_x86.h> 43 44 #include "ao.h" 45 46 static struct ao_chipshared *ao_shared[CHIP_MAX_CHIPS]; 47 48 /* 49 * This cpu module supports AMD family 0xf revisions B/C/D/E/F/G. If 50 * a family 0xf cpu beyond the rev G model limit is detected then 51 * return ENOTSUP and let the generic x86 CPU module load instead. 52 */ 53 uint_t ao_model_limit = 0x6f; 54 55 static int 56 ao_init(cpu_t *cp, void **datap) 57 { 58 uint_t chipid = chip_plat_get_chipid(CPU); 59 struct ao_chipshared *sp, *osp; 60 ao_data_t *ao; 61 uint64_t cap; 62 63 if (cpuid_getmodel(cp) >= ao_model_limit) 64 return (ENOTSUP); 65 66 if (!(x86_feature & X86_MCA)) 67 return (ENOTSUP); 68 69 cap = rdmsr(IA32_MSR_MCG_CAP); 70 if (!(cap & MCG_CAP_CTL_P)) 71 return (ENOTSUP); 72 73 ao = *datap = kmem_zalloc(sizeof (ao_data_t), KM_SLEEP); 74 ao->ao_cpu = cp; 75 76 /* 77 * Allocate the chipshared structure if it appears not to have been 78 * allocated already (by a sibling core). Install the newly 79 * allocated pointer atomically in case a sibling core beats 80 * us to it. 81 */ 82 if ((sp = ao_shared[chipid]) == NULL) { 83 sp = kmem_zalloc(sizeof (struct ao_chipshared), KM_SLEEP); 84 osp = atomic_cas_ptr(&ao_shared[chipid], NULL, sp); 85 if (osp != NULL) { 86 kmem_free(sp, sizeof (struct ao_chipshared)); 87 sp = osp; 88 } 89 } 90 ao->ao_shared = sp; 91 92 return (0); 93 } 94 95 /*ARGSUSED*/ 96 static void 97 ao_post_mpstartup(void *data) 98 { 99 (void) ddi_install_driver("mc-amd"); 100 } 101 102 static void 103 ao_fini(void *data) 104 { 105 kmem_free(data, sizeof (ao_data_t)); 106 } 107 108 const cmi_ops_t _cmi_ops = { 109 ao_init, 110 ao_mca_post_init, 111 ao_post_mpstartup, 112 ao_fini, 113 ao_faulted_enter, 114 ao_faulted_exit, 115 ao_scrubber_enable, 116 ao_mca_init, 117 ao_mca_trap, 118 ao_mca_inject, 119 ao_mca_poke, 120 ao_mc_register, 121 ao_mc_getops 122 }; 123 124 static struct modlcpu modlcpu = { 125 &mod_cpuops, 126 "AMD Athlon64/Opteron CPU Module" 127 }; 128 129 static struct modlinkage modlinkage = { 130 MODREV_1, 131 (void *)&modlcpu, 132 NULL 133 }; 134 135 int 136 _init(void) 137 { 138 int err; 139 140 ao_mca_queue = errorq_create("ao_mca_queue", 141 ao_mca_drain, NULL, AO_MCA_MAX_ERRORS * (max_ncpus + 1), 142 sizeof (ao_cpu_logout_t), 1, ERRORQ_VITAL); 143 144 if (ao_mca_queue == NULL) 145 return (EAGAIN); /* errorq_create() logs a message for us */ 146 147 if ((err = mod_install(&modlinkage)) != 0) { 148 errorq_destroy(ao_mca_queue); 149 ao_mca_queue = NULL; 150 } 151 152 return (err); 153 } 154 155 int 156 _info(struct modinfo *modinfop) 157 { 158 return (mod_info(&modlinkage, modinfop)); 159 } 160 161 int 162 _fini(void) 163 { 164 int err; 165 166 if ((err = mod_remove(&modlinkage)) == 0) 167 errorq_destroy(ao_mca_queue); 168 169 return (err); 170 } 171