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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/cmn_err.h> 29 #include <sys/errno.h> 30 #include <sys/log.h> 31 #include <sys/systm.h> 32 #include <sys/modctl.h> 33 #include <sys/errorq.h> 34 #include <sys/controlregs.h> 35 #include <sys/fm/util.h> 36 #include <sys/fm/protocol.h> 37 #include <sys/sysevent.h> 38 #include <sys/pghw.h> 39 #include <sys/cyclic.h> 40 #include <sys/pci_cfgspace.h> 41 #include <sys/mc_intel.h> 42 #include <sys/cpu_module_impl.h> 43 #include <sys/smbios.h> 44 #include <sys/pci.h> 45 #include "intel_nhm.h" 46 #include "nhm_log.h" 47 48 errorq_t *nhm_queue; 49 kmutex_t nhm_mutex; 50 uint32_t nhm_chipset; 51 52 nhm_dimm_t **nhm_dimms; 53 54 uint64_t nhm_memory_on_ctl[MAX_MEMORY_CONTROLLERS]; 55 int nhm_patrol_scrub; 56 int nhm_demand_scrub; 57 int nhm_no_smbios; 58 int nhm_smbios_serial; 59 int nhm_smbios_manufacturer; 60 int nhm_smbios_part_number; 61 int nhm_smbios_version; 62 int nhm_smbios_label; 63 64 extern char ecc_enabled; 65 extern void mem_reg_init(void); 66 67 static void 68 check_serial_number() 69 { 70 nhm_dimm_t *dimmp, *tp; 71 nhm_dimm_t **dimmpp, **tpp; 72 nhm_dimm_t **end; 73 int not_unique; 74 75 end = &nhm_dimms[MAX_MEMORY_CONTROLLERS * 76 CHANNELS_PER_MEMORY_CONTROLLER * MAX_DIMMS_PER_CHANNEL]; 77 for (dimmpp = nhm_dimms; dimmpp < end; dimmpp++) { 78 dimmp = *dimmpp; 79 if (dimmp == NULL) 80 continue; 81 not_unique = 0; 82 for (tpp = dimmpp + 1; tpp < end; tpp++) { 83 tp = *tpp; 84 if (tp == NULL) 85 continue; 86 if (strncmp(dimmp->serial_number, tp->serial_number, 87 sizeof (dimmp->serial_number)) == 0) { 88 not_unique = 1; 89 tp->serial_number[0] = 0; 90 } 91 } 92 if (not_unique) 93 dimmp->serial_number[0] = 0; 94 } 95 } 96 97 static void 98 dimm_manufacture_data(smbios_hdl_t *shp, id_t id, nhm_dimm_t *dimmp) 99 { 100 smbios_info_t cd; 101 102 if (smbios_info_common(shp, id, &cd) == 0) { 103 if (cd.smbi_serial && nhm_smbios_serial) { 104 (void) strncpy(dimmp->serial_number, cd.smbi_serial, 105 sizeof (dimmp->serial_number)); 106 } 107 if (cd.smbi_manufacturer && nhm_smbios_manufacturer) { 108 (void) strncpy(dimmp->manufacturer, 109 cd.smbi_manufacturer, 110 sizeof (dimmp->manufacturer)); 111 } 112 if (cd.smbi_part && nhm_smbios_part_number) { 113 (void) strncpy(dimmp->part_number, cd.smbi_part, 114 sizeof (dimmp->part_number)); 115 } 116 if (cd.smbi_version && nhm_smbios_version) { 117 (void) strncpy(dimmp->revision, cd.smbi_version, 118 sizeof (dimmp->revision)); 119 } 120 } 121 } 122 123 struct dimm_slot { 124 int controller; 125 int channel; 126 int dimm; 127 int max_dimm; 128 }; 129 130 static int 131 dimm_label(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg) 132 { 133 nhm_dimm_t *dimmp; 134 smbios_memdevice_t md; 135 int slot; 136 int last_slot; 137 struct dimm_slot *dsp = (struct dimm_slot *)arg; 138 139 slot = (dsp->controller * CHANNELS_PER_MEMORY_CONTROLLER * 140 MAX_DIMMS_PER_CHANNEL) + (dsp->channel * MAX_DIMMS_PER_CHANNEL) + 141 dsp->dimm; 142 last_slot = MAX_MEMORY_CONTROLLERS * CHANNELS_PER_MEMORY_CONTROLLER * 143 MAX_DIMMS_PER_CHANNEL; 144 if (slot >= last_slot) 145 return (0); 146 dimmp = nhm_dimms[slot]; 147 if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) { 148 if (smbios_info_memdevice(shp, sp->smbstr_id, 149 &md) == 0 && md.smbmd_dloc != NULL) { 150 if (dimmp == NULL && md.smbmd_size) { 151 /* skip non existent slot */ 152 dsp->channel++; 153 if (dsp->dimm == 2) 154 dsp->max_dimm = 2; 155 dsp->dimm = 0; 156 slot = (dsp->controller * 157 CHANNELS_PER_MEMORY_CONTROLLER * 158 MAX_DIMMS_PER_CHANNEL) + 159 (dsp->channel * MAX_DIMMS_PER_CHANNEL); 160 if (slot >= last_slot) 161 return (0); 162 163 dimmp = nhm_dimms[slot]; 164 165 if (dimmp == NULL) { 166 dsp->channel++; 167 if (dsp->channel == 168 CHANNELS_PER_MEMORY_CONTROLLER) { 169 dsp->channel = 0; 170 dsp->controller++; 171 } 172 slot = (dsp->controller * 173 CHANNELS_PER_MEMORY_CONTROLLER * 174 MAX_DIMMS_PER_CHANNEL) + 175 (dsp->channel * 176 MAX_DIMMS_PER_CHANNEL); 177 if (slot >= last_slot) 178 return (0); 179 dimmp = nhm_dimms[slot]; 180 } 181 } 182 if (dimmp) { 183 if (nhm_smbios_label) 184 (void) snprintf(dimmp->label, 185 sizeof (dimmp->label), "%s", 186 md.smbmd_dloc); 187 dimm_manufacture_data(shp, sp->smbstr_id, 188 dimmp); 189 } 190 } 191 dsp->dimm++; 192 if (dsp->dimm == dsp->max_dimm) { 193 dsp->dimm = 0; 194 dsp->channel++; 195 if (dsp->channel == CHANNELS_PER_MEMORY_CONTROLLER) { 196 dsp->channel = 0; 197 dsp->controller++; 198 } 199 } 200 } 201 return (0); 202 } 203 204 void 205 nhm_smbios() 206 { 207 struct dimm_slot ds; 208 209 if (ksmbios != NULL && nhm_no_smbios == 0) { 210 ds.dimm = 0; 211 ds.channel = 0; 212 ds.controller = 0; 213 ds.max_dimm = MAX_DIMMS_PER_CHANNEL; 214 (void) smbios_iter(ksmbios, dimm_label, &ds); 215 check_serial_number(); 216 } 217 } 218 219 static void 220 dimm_prop(nhm_dimm_t *dimmp, uint32_t dod) 221 { 222 dimmp->dimm_size = DIMMSIZE(dod); 223 dimmp->nranks = NUMRANK(dod); 224 dimmp->nbanks = NUMBANK(dod); 225 dimmp->ncolumn = NUMCOL(dod); 226 dimmp->nrow = NUMROW(dod); 227 dimmp->width = DIMMWIDTH; 228 } 229 230 void 231 nhm_scrubber_enable() 232 { 233 uint32_t mc_ssrcontrol; 234 uint32_t mc_dimm_clk_ratio_status; 235 uint64_t cycle_time; 236 uint32_t interval; 237 uint32_t id; 238 int i; 239 int hw_scrub = 0; 240 241 if (ecc_enabled && (nhm_patrol_scrub || nhm_demand_scrub)) { 242 for (i = 0; i < MAX_MEMORY_CONTROLLERS; i++) { 243 id = MC_CPU_RAS_RD(i); 244 if ((id != NHM_CPU_RAS && id != NHM_JF_CPU_RAS && 245 id != NHM_WM_CPU_RAS) || nhm_memory_on_ctl[i] == 0) 246 continue; 247 mc_ssrcontrol = MC_SSR_CONTROL_RD(i); 248 if (nhm_demand_scrub && 249 (mc_ssrcontrol & DEMAND_SCRUB_ENABLE) == 0) { 250 mc_ssrcontrol |= DEMAND_SCRUB_ENABLE; 251 MC_SSR_CONTROL_WR(i, mc_ssrcontrol); 252 } 253 if (nhm_patrol_scrub == 0) 254 continue; 255 if (SSR_MODE(mc_ssrcontrol) == SSR_IDLE) { 256 mc_dimm_clk_ratio_status = 257 MC_DIMM_CLK_RATIO_STATUS(i); 258 cycle_time = 259 MAX_DIMM_CLK_RATIO(mc_dimm_clk_ratio_status) 260 * 80000000; 261 interval = (uint32_t)((36400ULL * cycle_time) / 262 (nhm_memory_on_ctl[i]/64)); 263 MC_SCRUB_CONTROL_WR(i, STARTSCRUB | interval); 264 MC_SSR_CONTROL_WR(i, mc_ssrcontrol | SSR_SCRUB); 265 } else if (SSR_MODE(mc_ssrcontrol) == SSR_SPARE) { 266 hw_scrub = 0; 267 break; 268 } 269 hw_scrub = 1; 270 } 271 if (hw_scrub) 272 cmi_mc_sw_memscrub_disable(); 273 } 274 } 275 276 void 277 init_dimms() 278 { 279 int i, j, k; 280 nhm_dimm_t **dimmpp; 281 nhm_dimm_t *dimmp; 282 uint32_t dod; 283 uint32_t did; 284 285 nhm_dimms = (nhm_dimm_t **)kmem_zalloc(sizeof (nhm_dimm_t *) * 286 MAX_MEMORY_CONTROLLERS * CHANNELS_PER_MEMORY_CONTROLLER * 287 MAX_DIMMS_PER_CHANNEL, KM_SLEEP); 288 dimmpp = nhm_dimms; 289 for (i = 0; i < MAX_MEMORY_CONTROLLERS; i++) { 290 did = CPU_ID_RD(i); 291 if (did != NHM_EP_CPU && did != NHM_WS_CPU && 292 did != NHM_JF_CPU && did != NHM_WM_CPU) { 293 dimmpp += CHANNELS_PER_MEMORY_CONTROLLER * 294 MAX_DIMMS_PER_CHANNEL; 295 continue; 296 } 297 for (j = 0; j < CHANNELS_PER_MEMORY_CONTROLLER; j++) { 298 for (k = 0; k < MAX_DIMMS_PER_CHANNEL; k++) { 299 dod = MC_DOD_RD(i, j, k); 300 if (DIMMPRESENT(dod)) { 301 dimmp = (nhm_dimm_t *) 302 kmem_zalloc(sizeof (nhm_dimm_t), 303 KM_SLEEP); 304 dimm_prop(dimmp, dod); 305 (void) snprintf(dimmp->label, 306 sizeof (dimmp->label), 307 "Socket %d channel %d dimm %d", 308 i, j, k); 309 *dimmpp = dimmp; 310 nhm_memory_on_ctl[i] += 311 dimmp->dimm_size; 312 } 313 dimmpp++; 314 } 315 } 316 } 317 } 318 319 320 int 321 nhm_init(void) 322 { 323 int slot; 324 325 /* return ENOTSUP if there is no PCI config space support. */ 326 if (pci_getl_func == NULL) 327 return (ENOTSUP); 328 for (slot = 0; slot < MAX_CPU_NODES; slot++) { 329 nhm_chipset = CPU_ID_RD(slot); 330 if (nhm_chipset == NHM_EP_CPU || nhm_chipset == NHM_WS_CPU || 331 nhm_chipset == NHM_JF_CPU || nhm_chipset == NHM_WM_CPU) 332 break; 333 } 334 if (slot == MAX_CPU_NODES) { 335 return (ENOTSUP); 336 } 337 mem_reg_init(); 338 return (0); 339 } 340 341 int 342 nhm_reinit(void) 343 { 344 mem_reg_init(); 345 return (0); 346 } 347 348 int 349 nhm_dev_init() 350 { 351 return (0); 352 } 353 354 void 355 nhm_dev_reinit() 356 { 357 } 358 359 void 360 nhm_unload() 361 { 362 } 363