1 1772 jl139090 /* 2 1772 jl139090 * CDDL HEADER START 3 1772 jl139090 * 4 1772 jl139090 * The contents of this file are subject to the terms of the 5 1772 jl139090 * Common Development and Distribution License (the "License"). 6 1772 jl139090 * You may not use this file except in compliance with the License. 7 1772 jl139090 * 8 1772 jl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 1772 jl139090 * or http://www.opensolaris.org/os/licensing. 10 1772 jl139090 * See the License for the specific language governing permissions 11 1772 jl139090 * and limitations under the License. 12 1772 jl139090 * 13 1772 jl139090 * When distributing Covered Code, include this CDDL HEADER in each 14 1772 jl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 1772 jl139090 * If applicable, add the following below this CDDL HEADER, with the 16 1772 jl139090 * fields enclosed by brackets "[]" replaced with your own identifying 17 1772 jl139090 * information: Portions Copyright [yyyy] [name of copyright owner] 18 1772 jl139090 * 19 1772 jl139090 * CDDL HEADER END 20 1772 jl139090 */ 21 1772 jl139090 /* 22 10794 Mary * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 2241 huah * Use is subject to license terms. 24 2241 huah */ 25 2241 huah /* 26 6297 jl139090 * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2008 27 1772 jl139090 */ 28 1772 jl139090 29 1772 jl139090 30 1772 jl139090 #include <sys/types.h> 31 1772 jl139090 #include <sys/sysmacros.h> 32 1772 jl139090 #include <sys/conf.h> 33 1772 jl139090 #include <sys/modctl.h> 34 1772 jl139090 #include <sys/stat.h> 35 1772 jl139090 #include <sys/async.h> 36 2241 huah #include <sys/machcpuvar.h> 37 1772 jl139090 #include <sys/machsystm.h> 38 2214 av145390 #include <sys/promif.h> 39 1772 jl139090 #include <sys/ksynch.h> 40 1772 jl139090 #include <sys/ddi.h> 41 1772 jl139090 #include <sys/sunddi.h> 42 5080 wh31274 #include <sys/sunndi.h> 43 1772 jl139090 #include <sys/ddifm.h> 44 1772 jl139090 #include <sys/fm/protocol.h> 45 1772 jl139090 #include <sys/fm/util.h> 46 1772 jl139090 #include <sys/kmem.h> 47 1772 jl139090 #include <sys/fm/io/opl_mc_fm.h> 48 1772 jl139090 #include <sys/memlist.h> 49 1772 jl139090 #include <sys/param.h> 50 2214 av145390 #include <sys/disp.h> 51 1772 jl139090 #include <vm/page.h> 52 1772 jl139090 #include <sys/mc-opl.h> 53 2214 av145390 #include <sys/opl.h> 54 2214 av145390 #include <sys/opl_dimm.h> 55 2214 av145390 #include <sys/scfd/scfostoescf.h> 56 2494 hyw #include <sys/cpu_module.h> 57 2494 hyw #include <vm/seg_kmem.h> 58 2494 hyw #include <sys/vmem.h> 59 2494 hyw #include <vm/hat_sfmmu.h> 60 2494 hyw #include <sys/vmsystm.h> 61 2662 hyw #include <sys/membar.h> 62 6693 wh31274 #include <sys/mem.h> 63 1772 jl139090 64 1772 jl139090 /* 65 1772 jl139090 * Function prototypes 66 1772 jl139090 */ 67 1772 jl139090 static int mc_open(dev_t *, int, int, cred_t *); 68 1772 jl139090 static int mc_close(dev_t, int, int, cred_t *); 69 1772 jl139090 static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 70 1772 jl139090 static int mc_attach(dev_info_t *, ddi_attach_cmd_t); 71 1772 jl139090 static int mc_detach(dev_info_t *, ddi_detach_cmd_t); 72 1772 jl139090 73 2214 av145390 static int mc_poll_init(void); 74 2214 av145390 static void mc_poll_fini(void); 75 1772 jl139090 static int mc_board_add(mc_opl_t *mcp); 76 1772 jl139090 static int mc_board_del(mc_opl_t *mcp); 77 1772 jl139090 static int mc_suspend(mc_opl_t *mcp, uint32_t flag); 78 1772 jl139090 static int mc_resume(mc_opl_t *mcp, uint32_t flag); 79 2214 av145390 int opl_mc_suspend(void); 80 2214 av145390 int opl_mc_resume(void); 81 1772 jl139090 82 1772 jl139090 static void insert_mcp(mc_opl_t *mcp); 83 1772 jl139090 static void delete_mcp(mc_opl_t *mcp); 84 1772 jl139090 85 1772 jl139090 static int pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr); 86 1772 jl139090 87 2662 hyw static int mc_rangecheck_pa(mc_opl_t *mcp, uint64_t pa); 88 1772 jl139090 89 1772 jl139090 int mc_get_mem_unum(int, uint64_t, char *, int, int *); 90 2214 av145390 int mc_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *paddr); 91 2214 av145390 int mc_get_mem_offset(uint64_t paddr, uint64_t *offp); 92 2214 av145390 int mc_get_mem_sid(char *unum, char *buf, int buflen, int *lenp); 93 2214 av145390 int mc_get_mem_sid_dimm(mc_opl_t *mcp, char *dname, char *buf, 94 2214 av145390 int buflen, int *lenp); 95 2214 av145390 mc_dimm_info_t *mc_get_dimm_list(mc_opl_t *mcp); 96 2214 av145390 mc_dimm_info_t *mc_prepare_dimmlist(board_dimm_info_t *bd_dimmp); 97 2214 av145390 int mc_set_mem_sid(mc_opl_t *mcp, char *buf, int buflen, int lsb, int bank, 98 2214 av145390 uint32_t mf_type, uint32_t d_slot); 99 2214 av145390 static void mc_free_dimm_list(mc_dimm_info_t *d); 100 2214 av145390 static void mc_get_mlist(mc_opl_t *); 101 2214 av145390 static void mc_polling(void); 102 2214 av145390 static int mc_opl_get_physical_board(int); 103 5310 dhain 104 5310 dhain static void mc_clear_rewrite(mc_opl_t *mcp, int i); 105 5310 dhain static void mc_set_rewrite(mc_opl_t *mcp, int bank, uint32_t addr, int state); 106 6693 wh31274 static int mc_scf_log_event(mc_flt_page_t *flt_pag); 107 1772 jl139090 108 2214 av145390 #ifdef DEBUG 109 2214 av145390 static int mc_ioctl_debug(dev_t, int, intptr_t, int, cred_t *, int *); 110 2214 av145390 void mc_dump_dimm(char *buf, int dnamesz, int serialsz, int partnumsz); 111 2214 av145390 void mc_dump_dimm_info(board_dimm_info_t *bd_dimmp); 112 2214 av145390 #endif 113 1772 jl139090 114 1772 jl139090 #pragma weak opl_get_physical_board 115 1772 jl139090 extern int opl_get_physical_board(int); 116 2214 av145390 extern int plat_max_boards(void); 117 1772 jl139090 118 1772 jl139090 /* 119 1772 jl139090 * Configuration data structures 120 1772 jl139090 */ 121 1772 jl139090 static struct cb_ops mc_cb_ops = { 122 1772 jl139090 mc_open, /* open */ 123 1772 jl139090 mc_close, /* close */ 124 1772 jl139090 nulldev, /* strategy */ 125 1772 jl139090 nulldev, /* print */ 126 1772 jl139090 nodev, /* dump */ 127 1772 jl139090 nulldev, /* read */ 128 1772 jl139090 nulldev, /* write */ 129 1772 jl139090 mc_ioctl, /* ioctl */ 130 1772 jl139090 nodev, /* devmap */ 131 1772 jl139090 nodev, /* mmap */ 132 1772 jl139090 nodev, /* segmap */ 133 1772 jl139090 nochpoll, /* poll */ 134 1772 jl139090 ddi_prop_op, /* cb_prop_op */ 135 1772 jl139090 0, /* streamtab */ 136 1772 jl139090 D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ 137 1772 jl139090 CB_REV, /* rev */ 138 1772 jl139090 nodev, /* cb_aread */ 139 1772 jl139090 nodev /* cb_awrite */ 140 1772 jl139090 }; 141 1772 jl139090 142 1772 jl139090 static struct dev_ops mc_ops = { 143 1772 jl139090 DEVO_REV, /* rev */ 144 1772 jl139090 0, /* refcnt */ 145 1772 jl139090 ddi_getinfo_1to1, /* getinfo */ 146 1772 jl139090 nulldev, /* identify */ 147 1772 jl139090 nulldev, /* probe */ 148 1772 jl139090 mc_attach, /* attach */ 149 1772 jl139090 mc_detach, /* detach */ 150 1772 jl139090 nulldev, /* reset */ 151 1772 jl139090 &mc_cb_ops, /* cb_ops */ 152 1772 jl139090 (struct bus_ops *)0, /* bus_ops */ 153 7656 Sherry nulldev, /* power */ 154 7656 Sherry ddi_quiesce_not_needed, /* quiesce */ 155 1772 jl139090 }; 156 1772 jl139090 157 1772 jl139090 /* 158 1772 jl139090 * Driver globals 159 1772 jl139090 */ 160 1772 jl139090 161 2214 av145390 static enum { 162 6297 jl139090 MODEL_FF1, 163 6297 jl139090 MODEL_FF2, 164 6297 jl139090 MODEL_DC, 165 6297 jl139090 MODEL_IKKAKU 166 2214 av145390 } plat_model = MODEL_DC; /* The default behaviour is DC */ 167 1772 jl139090 168 2214 av145390 static struct plat_model_names { 169 2214 av145390 const char *unit_name; 170 2214 av145390 const char *mem_name; 171 2214 av145390 } model_names[] = { 172 2214 av145390 { "MBU_A", "MEMB" }, 173 2214 av145390 { "MBU_B", "MEMB" }, 174 6297 jl139090 { "CMU", "" }, 175 6297 jl139090 { "MBU_A", "" } 176 2214 av145390 }; 177 2214 av145390 178 2214 av145390 /* 179 2214 av145390 * The DIMM Names for DC platform. 180 2214 av145390 * The index into this table is made up of (bank, dslot), 181 2214 av145390 * Where dslot occupies bits 0-1 and bank occupies 2-4. 182 2214 av145390 */ 183 2214 av145390 static char *mc_dc_dimm_unum_table[OPL_MAX_DIMMS] = { 184 2214 av145390 /* --------CMUnn----------- */ 185 2214 av145390 /* --CS0-----|--CS1------ */ 186 2214 av145390 /* -H-|--L-- | -H- | -L-- */ 187 2501 raghuram "03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */ 188 2501 raghuram "13A", "12A", "13B", "12B", /* Bank 1 (MAC 0 bank 1) */ 189 2501 raghuram "23A", "22A", "23B", "22B", /* Bank 2 (MAC 1 bank 0) */ 190 2501 raghuram "33A", "32A", "33B", "32B", /* Bank 3 (MAC 1 bank 1) */ 191 2501 raghuram "01A", "00A", "01B", "00B", /* Bank 4 (MAC 2 bank 0) */ 192 2501 raghuram "11A", "10A", "11B", "10B", /* Bank 5 (MAC 2 bank 1) */ 193 2501 raghuram "21A", "20A", "21B", "20B", /* Bank 6 (MAC 3 bank 0) */ 194 2501 raghuram "31A", "30A", "31B", "30B" /* Bank 7 (MAC 3 bank 1) */ 195 2214 av145390 }; 196 2214 av145390 197 2214 av145390 /* 198 6297 jl139090 * The DIMM Names for FF1/FF2/IKKAKU platforms. 199 2214 av145390 * The index into this table is made up of (board, bank, dslot), 200 2214 av145390 * Where dslot occupies bits 0-1, bank occupies 2-4 and 201 2214 av145390 * board occupies the bit 5. 202 2214 av145390 */ 203 2214 av145390 static char *mc_ff_dimm_unum_table[2 * OPL_MAX_DIMMS] = { 204 2214 av145390 /* --------CMU0---------- */ 205 2214 av145390 /* --CS0-----|--CS1------ */ 206 2214 av145390 /* -H-|--L-- | -H- | -L-- */ 207 2501 raghuram "03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */ 208 2501 raghuram "01A", "00A", "01B", "00B", /* Bank 1 (MAC 0 bank 1) */ 209 2501 raghuram "13A", "12A", "13B", "12B", /* Bank 2 (MAC 1 bank 0) */ 210 2501 raghuram "11A", "10A", "11B", "10B", /* Bank 3 (MAC 1 bank 1) */ 211 2501 raghuram "23A", "22A", "23B", "22B", /* Bank 4 (MAC 2 bank 0) */ 212 2501 raghuram "21A", "20A", "21B", "20B", /* Bank 5 (MAC 2 bank 1) */ 213 2501 raghuram "33A", "32A", "33B", "32B", /* Bank 6 (MAC 3 bank 0) */ 214 2501 raghuram "31A", "30A", "31B", "30B", /* Bank 7 (MAC 3 bank 1) */ 215 2214 av145390 /* --------CMU1---------- */ 216 2214 av145390 /* --CS0-----|--CS1------ */ 217 2214 av145390 /* -H-|--L-- | -H- | -L-- */ 218 2501 raghuram "43A", "42A", "43B", "42B", /* Bank 0 (MAC 0 bank 0) */ 219 2501 raghuram "41A", "40A", "41B", "40B", /* Bank 1 (MAC 0 bank 1) */ 220 2501 raghuram "53A", "52A", "53B", "52B", /* Bank 2 (MAC 1 bank 0) */ 221 2501 raghuram "51A", "50A", "51B", "50B", /* Bank 3 (MAC 1 bank 1) */ 222 2501 raghuram "63A", "62A", "63B", "62B", /* Bank 4 (MAC 2 bank 0) */ 223 2501 raghuram "61A", "60A", "61B", "60B", /* Bank 5 (MAC 2 bank 1) */ 224 2501 raghuram "73A", "72A", "73B", "72B", /* Bank 6 (MAC 3 bank 0) */ 225 2501 raghuram "71A", "70A", "71B", "70B" /* Bank 7 (MAC 3 bank 1) */ 226 2214 av145390 }; 227 2214 av145390 228 2214 av145390 #define BD_BK_SLOT_TO_INDEX(bd, bk, s) \ 229 2214 av145390 (((bd & 0x01) << 5) | ((bk & 0x07) << 2) | (s & 0x03)) 230 2214 av145390 231 2214 av145390 #define INDEX_TO_BANK(i) (((i) & 0x1C) >> 2) 232 2214 av145390 #define INDEX_TO_SLOT(i) ((i) & 0x03) 233 3045 av145390 234 3045 av145390 #define SLOT_TO_CS(slot) ((slot & 0x3) >> 1) 235 2214 av145390 236 2214 av145390 /* Isolation unit size is 64 MB */ 237 2214 av145390 #define MC_ISOLATION_BSIZE (64 * 1024 * 1024) 238 2214 av145390 239 2214 av145390 #define MC_MAX_SPEEDS 7 240 2214 av145390 241 2214 av145390 typedef struct { 242 2214 av145390 uint32_t mc_speeds; 243 2214 av145390 uint32_t mc_period; 244 2214 av145390 } mc_scan_speed_t; 245 2214 av145390 246 2214 av145390 #define MC_CNTL_SPEED_SHIFT 26 247 2867 hyw 248 2867 hyw /* 249 2867 hyw * In mirror mode, we normalized the bank idx to "even" since 250 2867 hyw * the HW treats them as one unit w.r.t programming. 251 2867 hyw * This bank index will be the "effective" bank index. 252 2867 hyw * All mirrored bank state info on mc_period, mc_speedup_period 253 2867 hyw * will be stored in the even bank structure to avoid code duplication. 254 2867 hyw */ 255 2867 hyw #define MIRROR_IDX(bankidx) (bankidx & ~1) 256 2214 av145390 257 2214 av145390 static mc_scan_speed_t mc_scan_speeds[MC_MAX_SPEEDS] = { 258 2214 av145390 {0x6 << MC_CNTL_SPEED_SHIFT, 0}, 259 2214 av145390 {0x5 << MC_CNTL_SPEED_SHIFT, 32}, 260 2214 av145390 {0x4 << MC_CNTL_SPEED_SHIFT, 64}, 261 2214 av145390 {0x3 << MC_CNTL_SPEED_SHIFT, 128}, 262 2214 av145390 {0x2 << MC_CNTL_SPEED_SHIFT, 256}, 263 2214 av145390 {0x1 << MC_CNTL_SPEED_SHIFT, 512}, 264 2214 av145390 {0x0 << MC_CNTL_SPEED_SHIFT, 1024} 265 2214 av145390 }; 266 2214 av145390 267 2214 av145390 static uint32_t mc_max_speed = (0x6 << 26); 268 2214 av145390 269 2214 av145390 int mc_isolation_bsize = MC_ISOLATION_BSIZE; 270 2214 av145390 int mc_patrol_interval_sec = MC_PATROL_INTERVAL_SEC; 271 2214 av145390 int mc_max_scf_retry = 16; 272 2214 av145390 int mc_max_scf_logs = 64; 273 2214 av145390 int mc_max_errlog_processed = BANKNUM_PER_SB*2; 274 2214 av145390 int mc_scan_period = 12 * 60 * 60; /* 12 hours period */ 275 2214 av145390 int mc_max_rewrite_loop = 100; 276 2214 av145390 int mc_rewrite_delay = 10; 277 2214 av145390 /* 278 2214 av145390 * it takes SCF about 300 m.s. to process a requst. We can bail out 279 2214 av145390 * if it is busy. It does not pay to wait for it too long. 280 2214 av145390 */ 281 2214 av145390 int mc_max_scf_loop = 2; 282 2214 av145390 int mc_scf_delay = 100; 283 2214 av145390 int mc_pce_dropped = 0; 284 2214 av145390 int mc_poll_priority = MINCLSYSPRI; 285 5310 dhain int mc_max_rewrite_retry = 6 * 60; 286 2214 av145390 287 2214 av145390 288 2214 av145390 /* 289 3152 av145390 * Mutex hierarchy in mc-opl 290 2214 av145390 * If both mcmutex and mc_lock must be held, 291 2214 av145390 * mcmutex must be acquired first, and then mc_lock. 292 2214 av145390 */ 293 2214 av145390 294 1772 jl139090 static kmutex_t mcmutex; 295 2214 av145390 mc_opl_t *mc_instances[OPL_MAX_BOARDS]; 296 1772 jl139090 297 2214 av145390 static kmutex_t mc_polling_lock; 298 2214 av145390 static kcondvar_t mc_polling_cv; 299 2214 av145390 static kcondvar_t mc_poll_exit_cv; 300 2214 av145390 static int mc_poll_cmd = 0; 301 2214 av145390 static int mc_pollthr_running = 0; 302 2214 av145390 int mc_timeout_period = 0; /* this is in m.s. */ 303 1772 jl139090 void *mc_statep; 304 1772 jl139090 305 1772 jl139090 #ifdef DEBUG 306 1809 hyw int oplmc_debug = 0; 307 1772 jl139090 #endif 308 1772 jl139090 309 2214 av145390 static int mc_debug_show_all = 0; 310 1772 jl139090 311 1772 jl139090 extern struct mod_ops mod_driverops; 312 1772 jl139090 313 1772 jl139090 static struct modldrv modldrv = { 314 1772 jl139090 &mod_driverops, /* module type, this one is a driver */ 315 7656 Sherry "OPL Memory-controller", /* module name */ 316 1772 jl139090 &mc_ops, /* driver ops */ 317 1772 jl139090 }; 318 1772 jl139090 319 1772 jl139090 static struct modlinkage modlinkage = { 320 1772 jl139090 MODREV_1, /* rev */ 321 1772 jl139090 (void *)&modldrv, 322 1772 jl139090 NULL 323 1772 jl139090 }; 324 1772 jl139090 325 1772 jl139090 #pragma weak opl_get_mem_unum 326 2214 av145390 #pragma weak opl_get_mem_sid 327 2214 av145390 #pragma weak opl_get_mem_offset 328 2214 av145390 #pragma weak opl_get_mem_addr 329 2214 av145390 330 1772 jl139090 extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *); 331 2214 av145390 extern int (*opl_get_mem_sid)(char *unum, char *buf, int buflen, int *lenp); 332 2214 av145390 extern int (*opl_get_mem_offset)(uint64_t paddr, uint64_t *offp); 333 2214 av145390 extern int (*opl_get_mem_addr)(char *unum, char *sid, uint64_t offset, 334 2214 av145390 uint64_t *paddr); 335 2214 av145390 336 1772 jl139090 337 1772 jl139090 /* 338 1772 jl139090 * pseudo-mc node portid format 339 1772 jl139090 * 340 1772 jl139090 * [10] = 0 341 1772 jl139090 * [9] = 1 342 1772 jl139090 * [8] = LSB_ID[4] = 0 343 1772 jl139090 * [7:4] = LSB_ID[3:0] 344 1772 jl139090 * [3:0] = 0 345 1772 jl139090 * 346 1772 jl139090 */ 347 1772 jl139090 348 1772 jl139090 /* 349 1772 jl139090 * These are the module initialization routines. 350 1772 jl139090 */ 351 1772 jl139090 int 352 1772 jl139090 _init(void) 353 1772 jl139090 { 354 2214 av145390 int error; 355 2214 av145390 int plen; 356 2214 av145390 char model[20]; 357 2214 av145390 pnode_t node; 358 1772 jl139090 359 1772 jl139090 360 1772 jl139090 if ((error = ddi_soft_state_init(&mc_statep, 361 1772 jl139090 sizeof (mc_opl_t), 1)) != 0) 362 1772 jl139090 return (error); 363 1772 jl139090 364 2214 av145390 if ((error = mc_poll_init()) != 0) { 365 2214 av145390 ddi_soft_state_fini(&mc_statep); 366 2214 av145390 return (error); 367 2214 av145390 } 368 2214 av145390 369 1772 jl139090 mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL); 370 1772 jl139090 if (&opl_get_mem_unum) 371 1772 jl139090 opl_get_mem_unum = mc_get_mem_unum; 372 2214 av145390 if (&opl_get_mem_sid) 373 2214 av145390 opl_get_mem_sid = mc_get_mem_sid; 374 2214 av145390 if (&opl_get_mem_offset) 375 2214 av145390 opl_get_mem_offset = mc_get_mem_offset; 376 2214 av145390 if (&opl_get_mem_addr) 377 2214 av145390 opl_get_mem_addr = mc_get_mem_addr; 378 2214 av145390 379 2214 av145390 node = prom_rootnode(); 380 2214 av145390 plen = prom_getproplen(node, "model"); 381 2214 av145390 382 2214 av145390 if (plen > 0 && plen < sizeof (model)) { 383 2214 av145390 (void) prom_getprop(node, "model", model); 384 2214 av145390 model[plen] = '\0'; 385 2214 av145390 if (strcmp(model, "FF1") == 0) 386 2214 av145390 plat_model = MODEL_FF1; 387 2214 av145390 else if (strcmp(model, "FF2") == 0) 388 2214 av145390 plat_model = MODEL_FF2; 389 2214 av145390 else if (strncmp(model, "DC", 2) == 0) 390 2214 av145390 plat_model = MODEL_DC; 391 6297 jl139090 else if (strcmp(model, "IKKAKU") == 0) 392 6297 jl139090 plat_model = MODEL_IKKAKU; 393 2214 av145390 } 394 1772 jl139090 395 1772 jl139090 error = mod_install(&modlinkage); 396 1772 jl139090 if (error != 0) { 397 1772 jl139090 if (&opl_get_mem_unum) 398 1772 jl139090 opl_get_mem_unum = NULL; 399 2214 av145390 if (&opl_get_mem_sid) 400 2214 av145390 opl_get_mem_sid = NULL; 401 2214 av145390 if (&opl_get_mem_offset) 402 2214 av145390 opl_get_mem_offset = NULL; 403 2214 av145390 if (&opl_get_mem_addr) 404 2214 av145390 opl_get_mem_addr = NULL; 405 1772 jl139090 mutex_destroy(&mcmutex); 406 2214 av145390 mc_poll_fini(); 407 1772 jl139090 ddi_soft_state_fini(&mc_statep); 408 1772 jl139090 } 409 1772 jl139090 return (error); 410 1772 jl139090 } 411 1772 jl139090 412 1772 jl139090 int 413 1772 jl139090 _fini(void) 414 1772 jl139090 { 415 1772 jl139090 int error; 416 1772 jl139090 417 1772 jl139090 if ((error = mod_remove(&modlinkage)) != 0) 418 1772 jl139090 return (error); 419 1772 jl139090 420 1772 jl139090 if (&opl_get_mem_unum) 421 1772 jl139090 opl_get_mem_unum = NULL; 422 2214 av145390 if (&opl_get_mem_sid) 423 2214 av145390 opl_get_mem_sid = NULL; 424 2214 av145390 if (&opl_get_mem_offset) 425 2214 av145390 opl_get_mem_offset = NULL; 426 2214 av145390 if (&opl_get_mem_addr) 427 2214 av145390 opl_get_mem_addr = NULL; 428 1772 jl139090 429 2214 av145390 mutex_destroy(&mcmutex); 430 2214 av145390 mc_poll_fini(); 431 1772 jl139090 ddi_soft_state_fini(&mc_statep); 432 1772 jl139090 433 1772 jl139090 return (0); 434 1772 jl139090 } 435 1772 jl139090 436 1772 jl139090 int 437 1772 jl139090 _info(struct modinfo *modinfop) 438 1772 jl139090 { 439 1772 jl139090 return (mod_info(&modlinkage, modinfop)); 440 1772 jl139090 } 441 1772 jl139090 442 2214 av145390 static void 443 2214 av145390 mc_polling_thread() 444 2214 av145390 { 445 2214 av145390 mutex_enter(&mc_polling_lock); 446 2214 av145390 mc_pollthr_running = 1; 447 2214 av145390 while (!(mc_poll_cmd & MC_POLL_EXIT)) { 448 2214 av145390 mc_polling(); 449 11066 rafael cv_reltimedwait(&mc_polling_cv, &mc_polling_lock, 450 11066 rafael mc_timeout_period, TR_CLOCK_TICK); 451 2214 av145390 } 452 2214 av145390 mc_pollthr_running = 0; 453 2214 av145390 454 2214 av145390 /* 455 2214 av145390 * signal if any one is waiting for this thread to exit. 456 2214 av145390 */ 457 2214 av145390 cv_signal(&mc_poll_exit_cv); 458 2214 av145390 mutex_exit(&mc_polling_lock); 459 2214 av145390 thread_exit(); 460 2214 av145390 /* NOTREACHED */ 461 2214 av145390 } 462 2214 av145390 463 2214 av145390 static int 464 2214 av145390 mc_poll_init() 465 2214 av145390 { 466 2214 av145390 mutex_init(&mc_polling_lock, NULL, MUTEX_DRIVER, NULL); 467 2214 av145390 cv_init(&mc_polling_cv, NULL, CV_DRIVER, NULL); 468 2214 av145390 cv_init(&mc_poll_exit_cv, NULL, CV_DRIVER, NULL); 469 2214 av145390 return (0); 470 2214 av145390 } 471 2214 av145390 472 2214 av145390 static void 473 2214 av145390 mc_poll_fini() 474 2214 av145390 { 475 2214 av145390 mutex_enter(&mc_polling_lock); 476 2214 av145390 if (mc_pollthr_running) { 477 2214 av145390 mc_poll_cmd = MC_POLL_EXIT; 478 2214 av145390 cv_signal(&mc_polling_cv); 479 2214 av145390 while (mc_pollthr_running) { 480 2214 av145390 cv_wait(&mc_poll_exit_cv, &mc_polling_lock); 481 2214 av145390 } 482 2214 av145390 } 483 2214 av145390 mutex_exit(&mc_polling_lock); 484 2214 av145390 mutex_destroy(&mc_polling_lock); 485 2214 av145390 cv_destroy(&mc_polling_cv); 486 2214 av145390 cv_destroy(&mc_poll_exit_cv); 487 2214 av145390 } 488 2214 av145390 489 1772 jl139090 static int 490 1772 jl139090 mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 491 1772 jl139090 { 492 1772 jl139090 mc_opl_t *mcp; 493 1772 jl139090 int instance; 494 2214 av145390 int rv; 495 1772 jl139090 496 1772 jl139090 /* get the instance of this devi */ 497 1772 jl139090 instance = ddi_get_instance(devi); 498 1772 jl139090 499 1772 jl139090 switch (cmd) { 500 1772 jl139090 case DDI_ATTACH: 501 1772 jl139090 break; 502 1772 jl139090 case DDI_RESUME: 503 1772 jl139090 mcp = ddi_get_soft_state(mc_statep, instance); 504 2214 av145390 rv = mc_resume(mcp, MC_DRIVER_SUSPENDED); 505 2214 av145390 return (rv); 506 1772 jl139090 default: 507 1772 jl139090 return (DDI_FAILURE); 508 1772 jl139090 } 509 1772 jl139090 510 1772 jl139090 if (ddi_soft_state_zalloc(mc_statep, instance) != DDI_SUCCESS) 511 1772 jl139090 return (DDI_FAILURE); 512 1772 jl139090 513 6693 wh31274 if (ddi_create_minor_node(devi, "mc-opl", S_IFCHR, instance, 514 6693 wh31274 "ddi_mem_ctrl", 0) != DDI_SUCCESS) { 515 6693 wh31274 MC_LOG("mc_attach: create_minor_node failed\n"); 516 6693 wh31274 return (DDI_FAILURE); 517 6693 wh31274 } 518 6693 wh31274 519 1772 jl139090 if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) { 520 1772 jl139090 goto bad; 521 2214 av145390 } 522 2214 av145390 523 2214 av145390 if (mc_timeout_period == 0) { 524 2214 av145390 mc_patrol_interval_sec = (int)ddi_getprop(DDI_DEV_T_ANY, devi, 525 5080 wh31274 DDI_PROP_DONTPASS, "mc-timeout-interval-sec", 526 5080 wh31274 mc_patrol_interval_sec); 527 5080 wh31274 mc_timeout_period = drv_usectohz(1000000 * 528 5080 wh31274 mc_patrol_interval_sec / OPL_MAX_BOARDS); 529 1772 jl139090 } 530 1772 jl139090 531 1772 jl139090 /* set informations in mc state */ 532 1772 jl139090 mcp->mc_dip = devi; 533 1772 jl139090 534 1772 jl139090 if (mc_board_add(mcp)) 535 1772 jl139090 goto bad; 536 1772 jl139090 537 1772 jl139090 insert_mcp(mcp); 538 2214 av145390 539 2214 av145390 /* 540 2214 av145390 * Start the polling thread if it is not running already. 541 2214 av145390 */ 542 2214 av145390 mutex_enter(&mc_polling_lock); 543 2214 av145390 if (!mc_pollthr_running) { 544 2214 av145390 (void) thread_create(NULL, 0, (void (*)())mc_polling_thread, 545 5080 wh31274 NULL, 0, &p0, TS_RUN, mc_poll_priority); 546 2214 av145390 } 547 2214 av145390 mutex_exit(&mc_polling_lock); 548 1772 jl139090 ddi_report_dev(devi); 549 1772 jl139090 550 1772 jl139090 return (DDI_SUCCESS); 551 1772 jl139090 552 1772 jl139090 bad: 553 6693 wh31274 ddi_remove_minor_node(devi, NULL); 554 1772 jl139090 ddi_soft_state_free(mc_statep, instance); 555 1772 jl139090 return (DDI_FAILURE); 556 1772 jl139090 } 557 1772 jl139090 558 1772 jl139090 /* ARGSUSED */ 559 1772 jl139090 static int 560 1772 jl139090 mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 561 1772 jl139090 { 562 2214 av145390 int rv; 563 1772 jl139090 int instance; 564 1772 jl139090 mc_opl_t *mcp; 565 1772 jl139090 566 1772 jl139090 /* get the instance of this devi */ 567 1772 jl139090 instance = ddi_get_instance(devi); 568 1772 jl139090 if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) { 569 1772 jl139090 return (DDI_FAILURE); 570 1772 jl139090 } 571 1772 jl139090 572 1772 jl139090 switch (cmd) { 573 1772 jl139090 case DDI_SUSPEND: 574 2214 av145390 rv = mc_suspend(mcp, MC_DRIVER_SUSPENDED); 575 2214 av145390 return (rv); 576 1772 jl139090 case DDI_DETACH: 577 1772 jl139090 break; 578 1772 jl139090 default: 579 1772 jl139090 return (DDI_FAILURE); 580 1772 jl139090 } 581 1772 jl139090 582 2214 av145390 delete_mcp(mcp); 583 1772 jl139090 if (mc_board_del(mcp) != DDI_SUCCESS) { 584 1772 jl139090 return (DDI_FAILURE); 585 1772 jl139090 } 586 1772 jl139090 587 6693 wh31274 ddi_remove_minor_node(devi, NULL); 588 6693 wh31274 589 1772 jl139090 /* free up the soft state */ 590 1772 jl139090 ddi_soft_state_free(mc_statep, instance); 591 1772 jl139090 592 1772 jl139090 return (DDI_SUCCESS); 593 1772 jl139090 } 594 1772 jl139090 595 1772 jl139090 /* ARGSUSED */ 596 1772 jl139090 static int 597 1772 jl139090 mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 598 1772 jl139090 { 599 1772 jl139090 return (0); 600 1772 jl139090 } 601 1772 jl139090 602 1772 jl139090 /* ARGSUSED */ 603 1772 jl139090 static int 604 1772 jl139090 mc_close(dev_t devp, int flag, int otyp, cred_t *credp) 605 1772 jl139090 { 606 1772 jl139090 return (0); 607 1772 jl139090 } 608 1772 jl139090 609 1772 jl139090 /* ARGSUSED */ 610 1772 jl139090 static int 611 1772 jl139090 mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 612 1772 jl139090 int *rvalp) 613 1772 jl139090 { 614 6693 wh31274 mc_flt_page_t flt_page; 615 6693 wh31274 616 6693 wh31274 if (cmd == MCIOC_FAULT_PAGE) { 617 6693 wh31274 if (arg == NULL) 618 6693 wh31274 return (EINVAL); 619 6693 wh31274 620 6693 wh31274 if (ddi_copyin((const void *)arg, (void *)&flt_page, 621 6693 wh31274 sizeof (mc_flt_page_t), 0) < 0) 622 6693 wh31274 return (EFAULT); 623 6693 wh31274 624 6693 wh31274 return (mc_scf_log_event(&flt_page)); 625 6693 wh31274 } 626 2214 av145390 #ifdef DEBUG 627 2214 av145390 return (mc_ioctl_debug(dev, cmd, arg, mode, credp, rvalp)); 628 2214 av145390 #else 629 6693 wh31274 return (ENOTTY); 630 2214 av145390 #endif 631 1772 jl139090 } 632 1772 jl139090 633 1772 jl139090 /* 634 1772 jl139090 * PA validity check: 635 2662 hyw * This function return 1 if the PA is a valid PA 636 2662 hyw * in the running Solaris instance i.e. in physinstall 637 2662 hyw * Otherwise, return 0. 638 1772 jl139090 */ 639 1772 jl139090 640 1772 jl139090 /* ARGSUSED */ 641 1772 jl139090 static int 642 1772 jl139090 pa_is_valid(mc_opl_t *mcp, uint64_t addr) 643 1772 jl139090 { 644 1772 jl139090 if (mcp->mlist == NULL) 645 1772 jl139090 mc_get_mlist(mcp); 646 1772 jl139090 647 1772 jl139090 if (mcp->mlist && address_in_memlist(mcp->mlist, addr, 0)) { 648 1772 jl139090 return (1); 649 1772 jl139090 } 650 1772 jl139090 return (0); 651 1772 jl139090 } 652 1772 jl139090 653 1772 jl139090 /* 654 1772 jl139090 * mac-pa translation routines. 655 1772 jl139090 * 656 1772 jl139090 * Input: mc driver state, (LSB#, Bank#, DIMM address) 657 1772 jl139090 * Output: physical address 658 1772 jl139090 * 659 1772 jl139090 * Valid - return value: 0 660 1772 jl139090 * Invalid - return value: -1 661 1772 jl139090 */ 662 1772 jl139090 static int 663 1772 jl139090 mcaddr_to_pa(mc_opl_t *mcp, mc_addr_t *maddr, uint64_t *pa) 664 1772 jl139090 { 665 1772 jl139090 int i; 666 1772 jl139090 uint64_t pa_offset = 0; 667 1772 jl139090 int cs = (maddr->ma_dimm_addr >> CS_SHIFT) & 1; 668 1772 jl139090 int bank = maddr->ma_bank; 669 1772 jl139090 mc_addr_t maddr1; 670 1772 jl139090 int bank0, bank1; 671 1772 jl139090 672 1772 jl139090 MC_LOG("mcaddr /LSB%d/B%d/%x\n", maddr->ma_bd, bank, 673 5080 wh31274 maddr->ma_dimm_addr); 674 1772 jl139090 675 1772 jl139090 /* loc validity check */ 676 1772 jl139090 ASSERT(maddr->ma_bd >= 0 && OPL_BOARD_MAX > maddr->ma_bd); 677 1772 jl139090 ASSERT(bank >= 0 && OPL_BANK_MAX > bank); 678 1772 jl139090 679 1772 jl139090 /* Do translation */ 680 1772 jl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) { 681 1772 jl139090 int pa_bit = 0; 682 1772 jl139090 int mc_bit = mcp->mc_trans_table[cs][i]; 683 1772 jl139090 if (mc_bit < MC_ADDRESS_BITS) { 684 1772 jl139090 pa_bit = (maddr->ma_dimm_addr >> mc_bit) & 1; 685 1772 jl139090 } else if (mc_bit == MP_NONE) { 686 1772 jl139090 pa_bit = 0; 687 1772 jl139090 } else if (mc_bit == MP_BANK_0) { 688 1772 jl139090 pa_bit = bank & 1; 689 1772 jl139090 } else if (mc_bit == MP_BANK_1) { 690 1772 jl139090 pa_bit = (bank >> 1) & 1; 691 1772 jl139090 } else if (mc_bit == MP_BANK_2) { 692 1772 jl139090 pa_bit = (bank >> 2) & 1; 693 1772 jl139090 } 694 1772 jl139090 pa_offset |= ((uint64_t)pa_bit) << i; 695 1772 jl139090 } 696 1772 jl139090 *pa = mcp->mc_start_address + pa_offset; 697 1772 jl139090 MC_LOG("pa = %lx\n", *pa); 698 1772 jl139090 699 1772 jl139090 if (pa_to_maddr(mcp, *pa, &maddr1) == -1) { 700 2214 av145390 cmn_err(CE_WARN, "mcaddr_to_pa: /LSB%d/B%d/%x failed to " 701 2214 av145390 "convert PA %lx\n", maddr->ma_bd, bank, 702 2214 av145390 maddr->ma_dimm_addr, *pa); 703 1772 jl139090 return (-1); 704 1772 jl139090 } 705 1772 jl139090 706 2214 av145390 /* 707 2214 av145390 * In mirror mode, PA is always translated to the even bank. 708 2214 av145390 */ 709 1772 jl139090 if (IS_MIRROR(mcp, maddr->ma_bank)) { 710 1772 jl139090 bank0 = maddr->ma_bank & ~(1); 711 1772 jl139090 bank1 = maddr1.ma_bank & ~(1); 712 1772 jl139090 } else { 713 1772 jl139090 bank0 = maddr->ma_bank; 714 1772 jl139090 bank1 = maddr1.ma_bank; 715 1772 jl139090 } 716 1772 jl139090 /* 717 1772 jl139090 * there is no need to check ma_bd because it is generated from 718 1772 jl139090 * mcp. They are the same. 719 1772 jl139090 */ 720 5080 wh31274 if ((bank0 == bank1) && (maddr->ma_dimm_addr == 721 5080 wh31274 maddr1.ma_dimm_addr)) { 722 1772 jl139090 return (0); 723 1772 jl139090 } else { 724 6693 wh31274 MC_LOG("Translation error source /LSB%d/B%d/%x, " 725 5080 wh31274 "PA %lx, target /LSB%d/B%d/%x\n", maddr->ma_bd, bank, 726 5080 wh31274 maddr->ma_dimm_addr, *pa, maddr1.ma_bd, maddr1.ma_bank, 727 5080 wh31274 maddr1.ma_dimm_addr); 728 1772 jl139090 return (-1); 729 1772 jl139090 } 730 1772 jl139090 } 731 1772 jl139090 732 1772 jl139090 /* 733 1772 jl139090 * PA to CS (used by pa_to_maddr). 734 1772 jl139090 */ 735 1772 jl139090 static int 736 1772 jl139090 pa_to_cs(mc_opl_t *mcp, uint64_t pa_offset) 737 1772 jl139090 { 738 1772 jl139090 int i; 739 2662 hyw int cs = 1; 740 1772 jl139090 741 1772 jl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) { 742 1772 jl139090 /* MAC address bit<29> is arranged on the same PA bit */ 743 1772 jl139090 /* on both table. So we may use any table. */ 744 1772 jl139090 if (mcp->mc_trans_table[0][i] == CS_SHIFT) { 745 1772 jl139090 cs = (pa_offset >> i) & 1; 746 1772 jl139090 break; 747 1772 jl139090 } 748 1772 jl139090 } 749 1772 jl139090 return (cs); 750 1772 jl139090 } 751 1772 jl139090 752 1772 jl139090 /* 753 1772 jl139090 * PA to DIMM (used by pa_to_maddr). 754 1772 jl139090 */ 755 1772 jl139090 /* ARGSUSED */ 756 1772 jl139090 static uint32_t 757 1772 jl139090 pa_to_dimm(mc_opl_t *mcp, uint64_t pa_offset) 758 1772 jl139090 { 759 1772 jl139090 int i; 760 1772 jl139090 int cs = pa_to_cs(mcp, pa_offset); 761 1772 jl139090 uint32_t dimm_addr = 0; 762 1772 jl139090 763 1772 jl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) { 764 1772 jl139090 int pa_bit_value = (pa_offset >> i) & 1; 765 1772 jl139090 int mc_bit = mcp->mc_trans_table[cs][i]; 766 1772 jl139090 if (mc_bit < MC_ADDRESS_BITS) { 767 1772 jl139090 dimm_addr |= pa_bit_value << mc_bit; 768 1772 jl139090 } 769 1772 jl139090 } 770 2662 hyw dimm_addr |= cs << CS_SHIFT; 771 1772 jl139090 return (dimm_addr); 772 1772 jl139090 } 773 1772 jl139090 774 1772 jl139090 /* 775 1772 jl139090 * PA to Bank (used by pa_to_maddr). 776 1772 jl139090 */ 777 1772 jl139090 static int 778 1772 jl139090 pa_to_bank(mc_opl_t *mcp, uint64_t pa_offset) 779 1772 jl139090 { 780 1772 jl139090 int i; 781 1772 jl139090 int cs = pa_to_cs(mcp, pa_offset); 782 1772 jl139090 int bankno = mcp->mc_trans_table[cs][INDEX_OF_BANK_SUPPLEMENT_BIT]; 783 1772 jl139090 784 1772 jl139090 785 1772 jl139090 for (i = 0; i < PA_BITS_FOR_MAC; i++) { 786 1772 jl139090 int pa_bit_value = (pa_offset >> i) & 1; 787 1772 jl139090 int mc_bit = mcp->mc_trans_table[cs][i]; 788 1772 jl139090 switch (mc_bit) { 789 1772 jl139090 case MP_BANK_0: 790 1772 jl139090 bankno |= pa_bit_value; 791 1772 jl139090 break; 792 1772 jl139090 case MP_BANK_1: 793 1772 jl139090 bankno |= pa_bit_value << 1; 794 1772 jl139090 break; 795 1772 jl139090 case MP_BANK_2: 796 1772 jl139090 bankno |= pa_bit_value << 2; 797 1772 jl139090 break; 798 1772 jl139090 } 799 1772 jl139090 } 800 1772 jl139090 801 1772 jl139090 return (bankno); 802 1772 jl139090 } 803 1772 jl139090 804 1772 jl139090 /* 805 1772 jl139090 * PA to MAC address translation 806 1772 jl139090 * 807 1772 jl139090 * Input: MAC driver state, physicall adress 808 1772 jl139090 * Output: LSB#, Bank id, mac address 809 1772 jl139090 * 810 1772 jl139090 * Valid - return value: 0 811 1772 jl139090 * Invalid - return value: -1 812 1772 jl139090 */ 813 1772 jl139090 814 1772 jl139090 int 815 1772 jl139090 pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr) 816 1772 jl139090 { 817 1772 jl139090 uint64_t pa_offset; 818 1772 jl139090 819 2662 hyw if (!mc_rangecheck_pa(mcp, pa)) 820 1772 jl139090 return (-1); 821 1772 jl139090 822 1772 jl139090 /* Do translation */ 823 1772 jl139090 pa_offset = pa - mcp->mc_start_address; 824 1772 jl139090 825 1772 jl139090 maddr->ma_bd = mcp->mc_board_num; 826 3045 av145390 maddr->ma_phys_bd = mcp->mc_phys_board_num; 827 1772 jl139090 maddr->ma_bank = pa_to_bank(mcp, pa_offset); 828 1772 jl139090 maddr->ma_dimm_addr = pa_to_dimm(mcp, pa_offset); 829 5080 wh31274 MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n", pa_offset, maddr->ma_bd, 830 5080 wh31274 maddr->ma_bank, maddr->ma_dimm_addr); 831 1772 jl139090 return (0); 832 1772 jl139090 } 833 1772 jl139090 834 2214 av145390 /* 835 2214 av145390 * UNUM format for DC is "/CMUnn/MEMxyZ", where 836 2214 av145390 * nn = 00..03 for DC1 and 00..07 for DC2 and 00..15 for DC3. 837 2214 av145390 * x = MAC 0..3 838 2214 av145390 * y = 0..3 (slot info). 839 2214 av145390 * Z = 'A' or 'B' 840 2214 av145390 * 841 2214 av145390 * UNUM format for FF1 is "/MBU_A/MEMBx/MEMyZ", where 842 2214 av145390 * x = 0..3 (MEMB number) 843 2214 av145390 * y = 0..3 (slot info). 844 2214 av145390 * Z = 'A' or 'B' 845 2214 av145390 * 846 6297 jl139090 * UNUM format for FF2 is "/MBU_B/MEMBx/MEMyZ", where 847 2214 av145390 * x = 0..7 (MEMB number) 848 2214 av145390 * y = 0..3 (slot info). 849 2214 av145390 * Z = 'A' or 'B' 850 6297 jl139090 * 851 6297 jl139090 * UNUM format for IKKAKU is "/MBU_A/MEMyZ", where 852 6297 jl139090 * y = 0..3 (slot info). 853 6297 jl139090 * Z = 'A' or 'B' 854 6297 jl139090 * 855 2214 av145390 */ 856 2214 av145390 int 857 3045 av145390 mc_set_mem_unum(char *buf, int buflen, int sb, int bank, 858 2214 av145390 uint32_t mf_type, uint32_t d_slot) 859 2214 av145390 { 860 2214 av145390 char *dimmnm; 861 2214 av145390 char memb_num; 862 3045 av145390 int cs; 863 2214 av145390 int i; 864 3045 av145390 int j; 865 2214 av145390 866 3045 av145390 cs = SLOT_TO_CS(d_slot); 867 2214 av145390 868 6297 jl139090 switch (plat_model) { 869 6297 jl139090 case MODEL_DC: 870 5275 tsien if (mf_type == FLT_TYPE_INTERMITTENT_CE || 871 5275 tsien mf_type == FLT_TYPE_PERMANENT_CE) { 872 2214 av145390 i = BD_BK_SLOT_TO_INDEX(0, bank, d_slot); 873 2214 av145390 dimmnm = mc_dc_dimm_unum_table[i]; 874 2214 av145390 snprintf(buf, buflen, "/%s%02d/MEM%s", 875 2214 av145390 model_names[plat_model].unit_name, sb, dimmnm); 876 2214 av145390 } else { 877 2214 av145390 i = BD_BK_SLOT_TO_INDEX(0, bank, 0); 878 3045 av145390 j = (cs == 0) ? i : i + 2; 879 3045 av145390 snprintf(buf, buflen, "/%s%02d/MEM%s MEM%s", 880 2214 av145390 model_names[plat_model].unit_name, sb, 881 3045 av145390 mc_dc_dimm_unum_table[j], 882 3045 av145390 mc_dc_dimm_unum_table[j + 1]); 883 2214 av145390 } 884 6297 jl139090 break; 885 6297 jl139090 case MODEL_FF1: 886 6297 jl139090 case MODEL_FF2: 887 5275 tsien if (mf_type == FLT_TYPE_INTERMITTENT_CE || 888 5275 tsien mf_type == FLT_TYPE_PERMANENT_CE) { 889 3045 av145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot); 890 2214 av145390 dimmnm = mc_ff_dimm_unum_table[i]; 891 2214 av145390 memb_num = dimmnm[0]; 892 2214 av145390 snprintf(buf, buflen, "/%s/%s%c/MEM%s", 893 2214 av145390 model_names[plat_model].unit_name, 894 2214 av145390 model_names[plat_model].mem_name, 895 2214 av145390 memb_num, &dimmnm[1]); 896 2214 av145390 } else { 897 2214 av145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0); 898 3045 av145390 j = (cs == 0) ? i : i + 2; 899 2214 av145390 memb_num = mc_ff_dimm_unum_table[i][0], 900 5080 wh31274 snprintf(buf, buflen, "/%s/%s%c/MEM%s MEM%s", 901 2214 av145390 model_names[plat_model].unit_name, 902 2214 av145390 model_names[plat_model].mem_name, memb_num, 903 3045 av145390 &mc_ff_dimm_unum_table[j][1], 904 3045 av145390 &mc_ff_dimm_unum_table[j + 1][1]); 905 2214 av145390 } 906 6297 jl139090 break; 907 6297 jl139090 case MODEL_IKKAKU: 908 6297 jl139090 if (mf_type == FLT_TYPE_INTERMITTENT_CE || 909 6297 jl139090 mf_type == FLT_TYPE_PERMANENT_CE) { 910 6297 jl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, d_slot); 911 6297 jl139090 dimmnm = mc_ff_dimm_unum_table[i]; 912 6297 jl139090 snprintf(buf, buflen, "/%s/MEM%s", 913 6297 jl139090 model_names[plat_model].unit_name, &dimmnm[1]); 914 6297 jl139090 } else { 915 6297 jl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0); 916 6297 jl139090 j = (cs == 0) ? i : i + 2; 917 6297 jl139090 memb_num = mc_ff_dimm_unum_table[i][0], 918 6297 jl139090 snprintf(buf, buflen, "/%s/MEM%s MEM%s", 919 6297 jl139090 model_names[plat_model].unit_name, 920 6297 jl139090 &mc_ff_dimm_unum_table[j][1], 921 6297 jl139090 &mc_ff_dimm_unum_table[j + 1][1]); 922 6297 jl139090 } 923 6297 jl139090 break; 924 6297 jl139090 default: 925 6297 jl139090 return (-1); 926 2214 av145390 } 927 2214 av145390 return (0); 928 2214 av145390 } 929 2214 av145390 930 1772 jl139090 static void 931 1772 jl139090 mc_ereport_post(mc_aflt_t *mc_aflt) 932 1772 jl139090 { 933 1772 jl139090 char buf[FM_MAX_CLASS]; 934 1772 jl139090 char device_path[MAXPATHLEN]; 935 2214 av145390 char sid[MAXPATHLEN]; 936 1772 jl139090 nv_alloc_t *nva = NULL; 937 1772 jl139090 nvlist_t *ereport, *detector, *resource; 938 1772 jl139090 errorq_elem_t *eqep; 939 1772 jl139090 int nflts; 940 1772 jl139090 mc_flt_stat_t *flt_stat; 941 2214 av145390 int i, n; 942 2214 av145390 int blen = MAXPATHLEN; 943 2214 av145390 char *p, *s = NULL; 944 1772 jl139090 uint32_t values[2], synd[2], dslot[2]; 945 2214 av145390 uint64_t offset = (uint64_t)-1; 946 2214 av145390 int ret = -1; 947 1772 jl139090 948 1772 jl139090 if (panicstr) { 949 1772 jl139090 eqep = errorq_reserve(ereport_errorq); 950 1772 jl139090 if (eqep == NULL) 951 1772 jl139090 return; 952 1772 jl139090 ereport = errorq_elem_nvl(ereport_errorq, eqep); 953 1772 jl139090 nva = errorq_elem_nva(ereport_errorq, eqep); 954 1772 jl139090 } else { 955 1772 jl139090 ereport = fm_nvlist_create(nva); 956 1772 jl139090 } 957 1772 jl139090 958 1772 jl139090 /* 959 1772 jl139090 * Create the scheme "dev" FMRI. 960 1772 jl139090 */ 961 1772 jl139090 detector = fm_nvlist_create(nva); 962 1772 jl139090 resource = fm_nvlist_create(nva); 963 1772 jl139090 964 1772 jl139090 nflts = mc_aflt->mflt_nflts; 965 1772 jl139090 966 1772 jl139090 ASSERT(nflts >= 1 && nflts <= 2); 967 1772 jl139090 968 1772 jl139090 flt_stat = mc_aflt->mflt_stat[0]; 969 1772 jl139090 (void) ddi_pathname(mc_aflt->mflt_mcp->mc_dip, device_path); 970 1772 jl139090 (void) fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, 971 1772 jl139090 device_path, NULL); 972 1772 jl139090 973 1772 jl139090 /* 974 1772 jl139090 * Encode all the common data into the ereport. 975 1772 jl139090 */ 976 5080 wh31274 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", MC_OPL_ERROR_CLASS, 977 5080 wh31274 mc_aflt->mflt_is_ptrl ? MC_OPL_PTRL_SUBCLASS : MC_OPL_MI_SUBCLASS, 978 5080 wh31274 mc_aflt->mflt_erpt_class); 979 1772 jl139090 980 1772 jl139090 MC_LOG("mc_ereport_post: ereport %s\n", buf); 981 1772 jl139090 982 1772 jl139090 983 1772 jl139090 fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, 984 5080 wh31274 fm_ena_generate(mc_aflt->mflt_id, FM_ENA_FMT1), detector, NULL); 985 1772 jl139090 986 1772 jl139090 /* 987 1772 jl139090 * Set payload. 988 1772 jl139090 */ 989 1772 jl139090 fm_payload_set(ereport, MC_OPL_BOARD, DATA_TYPE_UINT32, 990 5080 wh31274 flt_stat->mf_flt_maddr.ma_bd, NULL); 991 1772 jl139090 992 1772 jl139090 fm_payload_set(ereport, MC_OPL_PA, DATA_TYPE_UINT64, 993 5080 wh31274 flt_stat->mf_flt_paddr, NULL); 994 1772 jl139090 995 5275 tsien if (flt_stat->mf_type == FLT_TYPE_INTERMITTENT_CE || 996 5275 tsien flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { 997 5080 wh31274 fm_payload_set(ereport, MC_OPL_FLT_TYPE, DATA_TYPE_UINT8, 998 5080 wh31274 ECC_STICKY, NULL); 999 1772 jl139090 } 1000 1772 jl139090 1001 1772 jl139090 for (i = 0; i < nflts; i++) 1002 1772 jl139090 values[i] = mc_aflt->mflt_stat[i]->mf_flt_maddr.ma_bank; 1003 1772 jl139090 1004 5080 wh31274 fm_payload_set(ereport, MC_OPL_BANK, DATA_TYPE_UINT32_ARRAY, nflts, 1005 5080 wh31274 values, NULL); 1006 1772 jl139090 1007 1772 jl139090 for (i = 0; i < nflts; i++) 1008 1772 jl139090 values[i] = mc_aflt->mflt_stat[i]->mf_cntl; 1009 1772 jl139090 1010 5080 wh31274 fm_payload_set(ereport, MC_OPL_STATUS, DATA_TYPE_UINT32_ARRAY, nflts, 1011 5080 wh31274 values, NULL); 1012 1772 jl139090 1013 1772 jl139090 for (i = 0; i < nflts; i++) 1014 1772 jl139090 values[i] = mc_aflt->mflt_stat[i]->mf_err_add; 1015 1772 jl139090 1016 5275 tsien /* offset is set only for PCE and ICE */ 1017 5275 tsien if (mc_aflt->mflt_stat[0]->mf_type == FLT_TYPE_INTERMITTENT_CE || 1018 5275 tsien mc_aflt->mflt_stat[0]->mf_type == FLT_TYPE_PERMANENT_CE) { 1019 2214 av145390 offset = values[0]; 1020 2214 av145390 1021 2214 av145390 } 1022 5080 wh31274 fm_payload_set(ereport, MC_OPL_ERR_ADD, DATA_TYPE_UINT32_ARRAY, nflts, 1023 5080 wh31274 values, NULL); 1024 1772 jl139090 1025 1772 jl139090 for (i = 0; i < nflts; i++) 1026 1772 jl139090 values[i] = mc_aflt->mflt_stat[i]->mf_err_log; 1027 1772 jl139090 1028 5080 wh31274 fm_payload_set(ereport, MC_OPL_ERR_LOG, DATA_TYPE_UINT32_ARRAY, nflts, 1029 5080 wh31274 values, NULL); 1030 1772 jl139090 1031 1772 jl139090 for (i = 0; i < nflts; i++) { 1032 1772 jl139090 flt_stat = mc_aflt->mflt_stat[i]; 1033 1772 jl139090 if (flt_stat->mf_errlog_valid) { 1034 1772 jl139090 synd[i] = flt_stat->mf_synd; 1035 1772 jl139090 dslot[i] = flt_stat->mf_dimm_slot; 1036 1772 jl139090 values[i] = flt_stat->mf_dram_place; 1037 1772 jl139090 } else { 1038 1772 jl139090 synd[i] = 0; 1039 1772 jl139090 dslot[i] = 0; 1040 1772 jl139090 values[i] = 0; 1041 1772 jl139090 } 1042 1772 jl139090 } 1043 1772 jl139090 1044 5080 wh31274 fm_payload_set(ereport, MC_OPL_ERR_SYND, DATA_TYPE_UINT32_ARRAY, nflts, 1045 5080 wh31274 synd, NULL); 1046 1772 jl139090 1047 5080 wh31274 fm_payload_set(ereport, MC_OPL_ERR_DIMMSLOT, DATA_TYPE_UINT32_ARRAY, 1048 5080 wh31274 nflts, dslot, NULL); 1049 1772 jl139090 1050 5080 wh31274 fm_payload_set(ereport, MC_OPL_ERR_DRAM, DATA_TYPE_UINT32_ARRAY, nflts, 1051 5080 wh31274 values, NULL); 1052 1772 jl139090 1053 1772 jl139090 device_path[0] = 0; 1054 1772 jl139090 p = &device_path[0]; 1055 2214 av145390 sid[0] = 0; 1056 2214 av145390 s = &sid[0]; 1057 2214 av145390 ret = 0; 1058 1772 jl139090 1059 1772 jl139090 for (i = 0; i < nflts; i++) { 1060 2214 av145390 int bank; 1061 1772 jl139090 1062 1772 jl139090 flt_stat = mc_aflt->mflt_stat[i]; 1063 2214 av145390 bank = flt_stat->mf_flt_maddr.ma_bank; 1064 5080 wh31274 ret = mc_set_mem_unum(p + strlen(p), blen, 1065 5080 wh31274 flt_stat->mf_flt_maddr.ma_phys_bd, bank, flt_stat->mf_type, 1066 5080 wh31274 flt_stat->mf_dimm_slot); 1067 1772 jl139090 1068 2214 av145390 if (ret != 0) { 1069 2214 av145390 cmn_err(CE_WARN, 1070 2214 av145390 "mc_ereport_post: Failed to determine the unum " 1071 2214 av145390 "for board=%d bank=%d type=0x%x slot=0x%x", 1072 2214 av145390 flt_stat->mf_flt_maddr.ma_bd, bank, 1073 2214 av145390 flt_stat->mf_type, flt_stat->mf_dimm_slot); 1074 2214 av145390 continue; 1075 1772 jl139090 } 1076 2214 av145390 n = strlen(device_path); 1077 1772 jl139090 blen = MAXPATHLEN - n; 1078 1772 jl139090 p = &device_path[n]; 1079 1772 jl139090 if (i < (nflts - 1)) { 1080 1772 jl139090 snprintf(p, blen, " "); 1081 2214 av145390 blen--; 1082 2214 av145390 p++; 1083 2214 av145390 } 1084 2214 av145390 1085 2214 av145390 if (ret == 0) { 1086 2214 av145390 ret = mc_set_mem_sid(mc_aflt->mflt_mcp, s + strlen(s), 1087 3045 av145390 blen, flt_stat->mf_flt_maddr.ma_phys_bd, bank, 1088 2214 av145390 flt_stat->mf_type, flt_stat->mf_dimm_slot); 1089 2214 av145390 1090 1772 jl139090 } 1091 1772 jl139090 } 1092 1772 jl139090 1093 5080 wh31274 (void) fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION, NULL, 1094 5080 wh31274 device_path, (ret == 0) ? sid : NULL, (ret == 0) ? offset : 1095 5080 wh31274 (uint64_t)-1); 1096 1772 jl139090 1097 5080 wh31274 fm_payload_set(ereport, MC_OPL_RESOURCE, DATA_TYPE_NVLIST, resource, 1098 5080 wh31274 NULL); 1099 1772 jl139090 1100 1772 jl139090 if (panicstr) { 1101 1772 jl139090 errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); 1102 1772 jl139090 } else { 1103 1772 jl139090 (void) fm_ereport_post(ereport, EVCH_TRYHARD); 1104 1772 jl139090 fm_nvlist_destroy(ereport, FM_NVA_FREE); 1105 1772 jl139090 fm_nvlist_destroy(detector, FM_NVA_FREE); 1106 1772 jl139090 fm_nvlist_destroy(resource, FM_NVA_FREE); 1107 1772 jl139090 } 1108 1772 jl139090 } 1109 1772 jl139090 1110 2214 av145390 1111 1772 jl139090 static void 1112 1772 jl139090 mc_err_drain(mc_aflt_t *mc_aflt) 1113 1772 jl139090 { 1114 1772 jl139090 int rv; 1115 1772 jl139090 uint64_t pa = (uint64_t)(-1); 1116 2214 av145390 int i; 1117 1772 jl139090 1118 5080 wh31274 MC_LOG("mc_err_drain: %s\n", mc_aflt->mflt_erpt_class); 1119 1772 jl139090 /* 1120 1772 jl139090 * we come here only when we have: 1121 3152 av145390 * In mirror mode: MUE, SUE 1122 5275 tsien * In normal mode: UE, Permanent CE, Intermittent CE 1123 1772 jl139090 */ 1124 2214 av145390 for (i = 0; i < mc_aflt->mflt_nflts; i++) { 1125 2214 av145390 rv = mcaddr_to_pa(mc_aflt->mflt_mcp, 1126 5080 wh31274 &(mc_aflt->mflt_stat[i]->mf_flt_maddr), &pa); 1127 2662 hyw 1128 2662 hyw /* Ensure the pa is valid (not in isolated memory block) */ 1129 2662 hyw if (rv == 0 && pa_is_valid(mc_aflt->mflt_mcp, pa)) 1130 2214 av145390 mc_aflt->mflt_stat[i]->mf_flt_paddr = pa; 1131 2214 av145390 else 1132 2214 av145390 mc_aflt->mflt_stat[i]->mf_flt_paddr = (uint64_t)-1; 1133 2214 av145390 } 1134 2214 av145390 1135 2662 hyw MC_LOG("mc_err_drain:pa = %lx\n", pa); 1136 2494 hyw 1137 2662 hyw switch (page_retire_check(pa, NULL)) { 1138 2662 hyw case 0: 1139 2662 hyw case EAGAIN: 1140 2662 hyw MC_LOG("Page retired or pending\n"); 1141 2662 hyw return; 1142 2662 hyw case EIO: 1143 2662 hyw /* 1144 5275 tsien * Do page retirement except for the PCE and ICE cases. 1145 2662 hyw * This is taken care by the OPL DE 1146 2662 hyw */ 1147 5275 tsien if (mc_aflt->mflt_stat[0]->mf_type != 1148 5275 tsien FLT_TYPE_INTERMITTENT_CE && 1149 5275 tsien mc_aflt->mflt_stat[0]->mf_type != FLT_TYPE_PERMANENT_CE) { 1150 2662 hyw MC_LOG("offline page at pa %lx error %x\n", pa, 1151 5080 wh31274 mc_aflt->mflt_pr); 1152 2662 hyw (void) page_retire(pa, mc_aflt->mflt_pr); 1153 1772 jl139090 } 1154 2662 hyw break; 1155 2662 hyw case EINVAL: 1156 2662 hyw default: 1157 2662 hyw /* 1158 2662 hyw * Some memory do not have page structure so 1159 2662 hyw * we keep going in case of EINVAL. 1160 2662 hyw */ 1161 2662 hyw break; 1162 1772 jl139090 } 1163 2214 av145390 1164 2214 av145390 for (i = 0; i < mc_aflt->mflt_nflts; i++) { 1165 2214 av145390 mc_aflt_t mc_aflt0; 1166 2214 av145390 if (mc_aflt->mflt_stat[i]->mf_flt_paddr != (uint64_t)-1) { 1167 2214 av145390 mc_aflt0 = *mc_aflt; 1168 2214 av145390 mc_aflt0.mflt_nflts = 1; 1169 2214 av145390 mc_aflt0.mflt_stat[0] = mc_aflt->mflt_stat[i]; 1170 2214 av145390 mc_ereport_post(&mc_aflt0); 1171 2214 av145390 } 1172 2214 av145390 } 1173 1772 jl139090 } 1174 1772 jl139090 1175 1772 jl139090 /* 1176 1772 jl139090 * The restart address is actually defined in unit of PA[37:6] 1177 1772 jl139090 * the mac patrol will convert that to dimm offset. If the 1178 1772 jl139090 * address is not in the bank, it will continue to search for 1179 1772 jl139090 * the next PA that is within the bank. 1180 1772 jl139090 * 1181 1772 jl139090 * Also the mac patrol scans the dimms based on PA, not 1182 1772 jl139090 * dimm offset. 1183 1772 jl139090 */ 1184 1772 jl139090 static int 1185 2662 hyw restart_patrol(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr_info) 1186 1772 jl139090 { 1187 1772 jl139090 uint64_t pa; 1188 1772 jl139090 int rv; 1189 1772 jl139090 1190 5310 dhain if (MC_REWRITE_MODE(mcp, bank)) { 1191 5310 dhain return (0); 1192 5310 dhain } 1193 2662 hyw if (rsaddr_info == NULL || (rsaddr_info->mi_valid == 0)) { 1194 1772 jl139090 MAC_PTRL_START(mcp, bank); 1195 1772 jl139090 return (0); 1196 1772 jl139090 } 1197 1772 jl139090 1198 2662 hyw rv = mcaddr_to_pa(mcp, &rsaddr_info->mi_restartaddr, &pa); 1199 1772 jl139090 if (rv != 0) { 1200 1772 jl139090 MC_LOG("cannot convert mcaddr to pa. use auto restart\n"); 1201 1772 jl139090 MAC_PTRL_START(mcp, bank); 1202 1772 jl139090 return (0); 1203 1772 jl139090 } 1204 1772 jl139090 1205 2662 hyw if (!mc_rangecheck_pa(mcp, pa)) { 1206 1772 jl139090 /* pa is not on this board, just retry */ 1207 1772 jl139090 cmn_err(CE_WARN, "restart_patrol: invalid address %lx " 1208 5080 wh31274 "on board %d\n", pa, mcp->mc_board_num); 1209 1772 jl139090 MAC_PTRL_START(mcp, bank); 1210 1772 jl139090 return (0); 1211 1772 jl139090 } 1212 1772 jl139090 1213 1772 jl139090 MC_LOG("restart_patrol: pa = %lx\n", pa); 1214 1772 jl139090 1215 2662 hyw if (!rsaddr_info->mi_injectrestart) { 1216 2662 hyw /* 1217 3152 av145390 * For non-error injection restart we need to 1218 2662 hyw * determine if the current restart pa/page is 1219 2662 hyw * a "good" page. A "good" page is a page that 1220 2662 hyw * has not been page retired. If the current 1221 2662 hyw * page that contains the pa is "good", we will 1222 2662 hyw * do a HW auto restart and let HW patrol continue 1223 2662 hyw * where it last stopped. Most desired scenario. 1224 2662 hyw * 1225 2662 hyw * If the current page is not "good", we will advance 1226 2662 hyw * to the next page to find the next "good" page and 1227 2662 hyw * restart the patrol from there. 1228 2662 hyw */ 1229 2662 hyw int wrapcount = 0; 1230 2662 hyw uint64_t origpa = pa; 1231 2662 hyw while (wrapcount < 2) { 1232 5080 wh31274 if (!pa_is_valid(mcp, pa)) { 1233 5310 dhain /* 1234 5310 dhain * Not in physinstall - advance to the 1235 5310 dhain * next memory isolation blocksize 1236 5310 dhain */ 1237 5310 dhain MC_LOG("Invalid PA\n"); 1238 5310 dhain pa = roundup(pa + 1, mc_isolation_bsize); 1239 5080 wh31274 } else { 1240 5310 dhain int rv; 1241 5310 dhain if ((rv = page_retire_check(pa, NULL)) != 0 && 1242 5310 dhain rv != EAGAIN) { 1243 5080 wh31274 /* 1244 5080 wh31274 * The page is "good" (not retired), 1245 5080 wh31274 * we will use automatic HW restart 1246 5080 wh31274 * algorithm if this is the original 1247 5080 wh31274 * current starting page. 1248 5080 wh31274 */ 1249 5310 dhain if (pa == origpa) { 1250 5310 dhain MC_LOG("Page has no error. " 1251 5310 dhain "Auto restart\n"); 1252 5310 dhain MAC_PTRL_START(mcp, bank); 1253 5310 dhain return (0); 1254 5310 dhain } else { 1255 5310 dhain /* 1256 5310 dhain * found a subsequent good page 1257 5310 dhain */ 1258 5310 dhain break; 1259 2662 hyw } 1260 2662 hyw } 1261 1772 jl139090 1262 5310 dhain /* 1263 5310 dhain * Skip to the next page 1264 5310 dhain */ 1265 5310 dhain pa = roundup(pa + 1, PAGESIZE); 1266 5310 dhain MC_LOG("Skipping bad page to %lx\n", pa); 1267 5310 dhain } 1268 5310 dhain 1269 5310 dhain /* Check to see if we hit the end of the memory range */ 1270 5080 wh31274 if (pa >= (mcp->mc_start_address + mcp->mc_size)) { 1271 5310 dhain MC_LOG("Wrap around\n"); 1272 5310 dhain pa = mcp->mc_start_address; 1273 5310 dhain wrapcount++; 1274 5080 wh31274 } 1275 2662 hyw } 1276 2662 hyw 1277 2662 hyw if (wrapcount > 1) { 1278 5080 wh31274 MC_LOG("Failed to find a good page. Just restart\n"); 1279 5080 wh31274 MAC_PTRL_START(mcp, bank); 1280 5080 wh31274 return (0); 1281 1772 jl139090 } 1282 1772 jl139090 } 1283 1772 jl139090 1284 1772 jl139090 /* 1285 2662 hyw * We reached here either: 1286 2662 hyw * 1. We are doing an error injection restart that specify 1287 2662 hyw * the exact pa/page to restart. OR 1288 2662 hyw * 2. We found a subsequent good page different from the 1289 2662 hyw * original restart pa/page. 1290 2662 hyw * Restart MAC patrol: PA[37:6] 1291 1772 jl139090 */ 1292 1772 jl139090 MC_LOG("restart at pa = %lx\n", pa); 1293 1772 jl139090 ST_MAC_REG(MAC_RESTART_ADD(mcp, bank), MAC_RESTART_PA(pa)); 1294 1772 jl139090 MAC_PTRL_START_ADD(mcp, bank); 1295 1772 jl139090 1296 1772 jl139090 return (0); 1297 1772 jl139090 } 1298 1772 jl139090 1299 5310 dhain static void 1300 5310 dhain mc_retry_info_put(mc_retry_info_t **q, mc_retry_info_t *p) 1301 5310 dhain { 1302 5310 dhain ASSERT(p != NULL); 1303 5310 dhain p->ri_next = *q; 1304 5310 dhain *q = p; 1305 5310 dhain } 1306 5310 dhain 1307 5310 dhain static mc_retry_info_t * 1308 5310 dhain mc_retry_info_get(mc_retry_info_t **q) 1309 5310 dhain { 1310 5310 dhain mc_retry_info_t *p; 1311 5310 dhain 1312 5310 dhain if ((p = *q) != NULL) { 1313 5310 dhain *q = p->ri_next; 1314 5310 dhain return (p); 1315 5310 dhain } else { 1316 5310 dhain return (NULL); 1317 5310 dhain } 1318 5310 dhain } 1319 5310 dhain 1320 1772 jl139090 /* 1321 1772 jl139090 * Rewriting is used for two purposes. 1322 1772 jl139090 * - to correct the error in memory. 1323 1772 jl139090 * - to determine whether the error is permanent or intermittent. 1324 1772 jl139090 * It's done by writing the address in MAC_BANKm_REWRITE_ADD 1325 1772 jl139090 * and issuing REW_REQ command in MAC_BANKm_PTRL_CNRL. After that, 1326 1772 jl139090 * REW_END (and REW_CE/REW_UE if some error detected) is set when 1327 1772 jl139090 * rewrite operation is done. See 4.7.3 and 4.7.11 in Columbus2 PRM. 1328 1772 jl139090 * 1329 1772 jl139090 * Note that rewrite operation doesn't change RAW_UE to Marked UE. 1330 1772 jl139090 * Therefore, we use it only CE case. 1331 1772 jl139090 */ 1332 5310 dhain 1333 1772 jl139090 static uint32_t 1334 5310 dhain do_rewrite(mc_opl_t *mcp, int bank, uint32_t dimm_addr, int retrying) 1335 1772 jl139090 { 1336 1772 jl139090 uint32_t cntl; 1337 1772 jl139090 int count = 0; 1338 5310 dhain int max_count; 1339 5310 dhain int retry_state; 1340 5310 dhain 1341 5310 dhain if (retrying) 1342 5310 dhain max_count = 1; 1343 5310 dhain else 1344 5310 dhain max_count = mc_max_rewrite_loop; 1345 5310 dhain 1346 5310 dhain retry_state = RETRY_STATE_PENDING; 1347 5310 dhain 1348 5310 dhain if (!retrying && MC_REWRITE_MODE(mcp, bank)) { 1349 5310 dhain goto timeout; 1350 5310 dhain } 1351 5310 dhain 1352 5310 dhain retry_state = RETRY_STATE_ACTIVE; 1353 1772 jl139090 1354 1772 jl139090 /* first wait to make sure PTRL_STATUS is 0 */ 1355 5310 dhain while (count++ < max_count) { 1356 1772 jl139090 cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 1357 5310 dhain if (!(cntl & MAC_CNTL_PTRL_STATUS)) { 1358 5310 dhain count = 0; 1359 1772 jl139090 break; 1360 5310 dhain } 1361 2214 av145390 drv_usecwait(mc_rewrite_delay); 1362 1772 jl139090 } 1363 5310 dhain if (count >= max_count) 1364 5310 dhain goto timeout; 1365 1772 jl139090 1366 1772 jl139090 count = 0; 1367 1772 jl139090 1368 1772 jl139090 ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), dimm_addr); 1369 1772 jl139090 MAC_REW_REQ(mcp, bank); 1370 1772 jl139090 1371 5310 dhain retry_state = RETRY_STATE_REWRITE; 1372 5310 dhain 1373 1772 jl139090 do { 1374 5310 dhain if (count++ > max_count) { 1375 5310 dhain goto timeout; 1376 2214 av145390 } else { 1377 2214 av145390 drv_usecwait(mc_rewrite_delay); 1378 2214 av145390 } 1379 5310 dhain cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 1380 1772 jl139090 /* 1381 1772 jl139090 * If there are other MEMORY or PCI activities, this 1382 1772 jl139090 * will be BUSY, else it should be set immediately 1383 1772 jl139090 */ 1384 1772 jl139090 } while (!(cntl & MAC_CNTL_REW_END)); 1385 1772 jl139090 1386 1772 jl139090 MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS); 1387 1772 jl139090 return (cntl); 1388 5310 dhain timeout: 1389 5310 dhain mc_set_rewrite(mcp, bank, dimm_addr, retry_state); 1390 5310 dhain 1391 5310 dhain return (0); 1392 1772 jl139090 } 1393 5310 dhain 1394 5310 dhain void 1395 5310 dhain mc_clear_rewrite(mc_opl_t *mcp, int bank) 1396 5310 dhain { 1397 5310 dhain struct mc_bank *bankp; 1398 5310 dhain mc_retry_info_t *retry; 1399 5310 dhain uint32_t rew_addr; 1400 5310 dhain 1401 5310 dhain bankp = &(mcp->mc_bank[bank]); 1402 5310 dhain retry = bankp->mcb_active; 1403 5310 dhain bankp->mcb_active = NULL; 1404 5310 dhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry); 1405 5310 dhain 1406 5310 dhain again: 1407 5310 dhain bankp->mcb_rewrite_count = 0; 1408 5310 dhain 1409 5310 dhain while (retry = mc_retry_info_get(&bankp->mcb_retry_pending)) { 1410 5310 dhain rew_addr = retry->ri_addr; 1411 5310 dhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry); 1412 5310 dhain if (do_rewrite(mcp, bank, rew_addr, 1) == 0) 1413 5310 dhain break; 1414 5310 dhain } 1415 5310 dhain 1416 5310 dhain /* we break out if no more pending rewrite or we got timeout again */ 1417 5310 dhain 1418 5310 dhain if (!bankp->mcb_active && !bankp->mcb_retry_pending) { 1419 5310 dhain if (!IS_MIRROR(mcp, bank)) { 1420 5310 dhain MC_CLEAR_REWRITE_MODE(mcp, bank); 1421 5310 dhain } else { 1422 5310 dhain int mbank = bank ^ 1; 1423 5310 dhain bankp = &(mcp->mc_bank[mbank]); 1424 5310 dhain if (!bankp->mcb_active && !bankp->mcb_retry_pending) { 1425 5310 dhain MC_CLEAR_REWRITE_MODE(mcp, bank); 1426 5310 dhain MC_CLEAR_REWRITE_MODE(mcp, mbank); 1427 5310 dhain } else { 1428 5310 dhain bank = mbank; 1429 5310 dhain goto again; 1430 5310 dhain } 1431 5310 dhain } 1432 5310 dhain } 1433 5310 dhain } 1434 5310 dhain 1435 5310 dhain void 1436 5310 dhain mc_set_rewrite(mc_opl_t *mcp, int bank, uint32_t addr, int state) 1437 5310 dhain { 1438 5310 dhain mc_retry_info_t *retry; 1439 5310 dhain struct mc_bank *bankp; 1440 5310 dhain 1441 5310 dhain bankp = &mcp->mc_bank[bank]; 1442 5310 dhain 1443 5310 dhain retry = mc_retry_info_get(&bankp->mcb_retry_freelist); 1444 5310 dhain 1445 6693 wh31274 if (retry == NULL) { 1446 6693 wh31274 mc_addr_t maddr; 1447 6693 wh31274 uint64_t paddr; 1448 6693 wh31274 /* 1449 6693 wh31274 * previous rewrite request has not completed yet. 1450 6693 wh31274 * So we discard this rewrite request. 1451 6693 wh31274 */ 1452 6693 wh31274 maddr.ma_bd = mcp->mc_board_num; 1453 6693 wh31274 maddr.ma_bank = bank; 1454 6693 wh31274 maddr.ma_dimm_addr = addr; 1455 6693 wh31274 if (mcaddr_to_pa(mcp, &maddr, &paddr) == 0) { 1456 6693 wh31274 cmn_err(CE_WARN, "Discard CE rewrite request" 1457 6693 wh31274 " for 0x%lx (/LSB%d/B%d/%x).\n", 1458 6693 wh31274 paddr, mcp->mc_board_num, bank, addr); 1459 6693 wh31274 } else { 1460 6693 wh31274 cmn_err(CE_WARN, "Discard CE rewrite request" 1461 6693 wh31274 " for /LSB%d/B%d/%x.\n", 1462 6693 wh31274 mcp->mc_board_num, bank, addr); 1463 6693 wh31274 } 1464 6693 wh31274 return; 1465 6693 wh31274 } 1466 5310 dhain 1467 5310 dhain retry->ri_addr = addr; 1468 5310 dhain retry->ri_state = state; 1469 5310 dhain 1470 5310 dhain MC_SET_REWRITE_MODE(mcp, bank); 1471 5310 dhain 1472 5310 dhain if ((state > RETRY_STATE_PENDING)) { 1473 5310 dhain ASSERT(bankp->mcb_active == NULL); 1474 5310 dhain bankp->mcb_active = retry; 1475 5310 dhain } else { 1476 5310 dhain mc_retry_info_put(&bankp->mcb_retry_pending, retry); 1477 5310 dhain } 1478 5310 dhain 1479 5310 dhain if (IS_MIRROR(mcp, bank)) { 1480 5310 dhain int mbank = bank ^1; 1481 5310 dhain MC_SET_REWRITE_MODE(mcp, mbank); 1482 5310 dhain } 1483 5310 dhain } 1484 5310 dhain 1485 1772 jl139090 void 1486 1772 jl139090 mc_process_scf_log(mc_opl_t *mcp) 1487 1772 jl139090 { 1488 2214 av145390 int count; 1489 2214 av145390 int n = 0; 1490 1772 jl139090 scf_log_t *p; 1491 1772 jl139090 int bank; 1492 1772 jl139090 1493 2214 av145390 for (bank = 0; bank < BANKNUM_PER_SB; bank++) { 1494 5080 wh31274 while ((p = mcp->mc_scf_log[bank]) != NULL && 1495 5080 wh31274 (n < mc_max_errlog_processed)) { 1496 5310 dhain ASSERT(bank == p->sl_bank); 1497 5310 dhain count = 0; 1498 5310 dhain while ((LD_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank)) 1499 5310 dhain & MAC_STATIC_ERR_VLD)) { 1500 5310 dhain if (count++ >= (mc_max_scf_loop)) { 1501 5310 dhain break; 1502 1772 jl139090 } 1503 5310 dhain drv_usecwait(mc_scf_delay); 1504 5310 dhain } 1505 5080 wh31274 1506 5310 dhain if (count < mc_max_scf_loop) { 1507 5310 dhain ST_MAC_REG(MAC_STATIC_ERR_LOG(mcp, p->sl_bank), 1508 5310 dhain p->sl_err_log); 1509 5080 wh31274 1510 5310 dhain ST_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank), 1511 5310 dhain p->sl_err_add|MAC_STATIC_ERR_VLD); 1512 5310 dhain mcp->mc_scf_retry[bank] = 0; 1513 5310 dhain } else { 1514 5310 dhain /* 1515 5310 dhain * if we try too many times, just drop the req 1516 5310 dhain */ 1517 5310 dhain if (mcp->mc_scf_retry[bank]++ <= 1518 5310 dhain mc_max_scf_retry) { 1519 5310 dhain return; 1520 5080 wh31274 } else { 1521 5310 dhain if ((++mc_pce_dropped & 0xff) == 0) { 1522 5310 dhain cmn_err(CE_WARN, "Cannot " 1523 6693 wh31274 "report CE to SCF\n"); 1524 5080 wh31274 } 1525 5080 wh31274 } 1526 5310 dhain } 1527 5310 dhain n++; 1528 5310 dhain mcp->mc_scf_log[bank] = p->sl_next; 1529 5310 dhain mcp->mc_scf_total[bank]--; 1530 5310 dhain ASSERT(mcp->mc_scf_total[bank] >= 0); 1531 5310 dhain kmem_free(p, sizeof (scf_log_t)); 1532 1772 jl139090 } 1533 1772 jl139090 } 1534 1772 jl139090 } 1535 1772 jl139090 void 1536 1772 jl139090 mc_queue_scf_log(mc_opl_t *mcp, mc_flt_stat_t *flt_stat, int bank) 1537 1772 jl139090 { 1538 1772 jl139090 scf_log_t *p; 1539 1772 jl139090 1540 2214 av145390 if (mcp->mc_scf_total[bank] >= mc_max_scf_logs) { 1541 2214 av145390 if ((++mc_pce_dropped & 0xff) == 0) { 1542 6693 wh31274 cmn_err(CE_WARN, "Too many CE requests.\n"); 1543 2214 av145390 } 1544 1772 jl139090 return; 1545 1772 jl139090 } 1546 1772 jl139090 p = kmem_zalloc(sizeof (scf_log_t), KM_SLEEP); 1547 1772 jl139090 p->sl_next = 0; 1548 1772 jl139090 p->sl_err_add = flt_stat->mf_err_add; 1549 1772 jl139090 p->sl_err_log = flt_stat->mf_err_log; 1550 1772 jl139090 p->sl_bank = bank; 1551 1772 jl139090 1552 2214 av145390 if (mcp->mc_scf_log[bank] == NULL) { 1553 1772 jl139090 /* 1554 1772 jl139090 * we rely on mc_scf_log to detect NULL queue. 1555 1772 jl139090 * mc_scf_log_tail is irrelevant is such case. 1556 1772 jl139090 */ 1557 2214 av145390 mcp->mc_scf_log_tail[bank] = mcp->mc_scf_log[bank] = p; 1558 1772 jl139090 } else { 1559 2214 av145390 mcp->mc_scf_log_tail[bank]->sl_next = p; 1560 2214 av145390 mcp->mc_scf_log_tail[bank] = p; 1561 1772 jl139090 } 1562 2214 av145390 mcp->mc_scf_total[bank]++; 1563 1772 jl139090 } 1564 1772 jl139090 /* 1565 1772 jl139090 * This routine determines what kind of CE happens, intermittent 1566 1772 jl139090 * or permanent as follows. (See 4.7.3 in Columbus2 PRM.) 1567 1772 jl139090 * - Do rewrite by issuing REW_REQ command to MAC_PTRL_CNTL register. 1568 1772 jl139090 * - If CE is still detected on the same address even after doing 1569 1772 jl139090 * rewrite operation twice, it is determined as permanent error. 1570 1772 jl139090 * - If error is not detected anymore, it is determined as intermittent 1571 1772 jl139090 * error. 1572 1772 jl139090 * - If UE is detected due to rewrite operation, it should be treated 1573 1772 jl139090 * as UE. 1574 1772 jl139090 */ 1575 1772 jl139090 1576 1772 jl139090 /* ARGSUSED */ 1577 1772 jl139090 static void 1578 1772 jl139090 mc_scrub_ce(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat, int ptrl_error) 1579 1772 jl139090 { 1580 1772 jl139090 uint32_t cntl; 1581 1772 jl139090 int i; 1582 1772 jl139090 1583 1772 jl139090 flt_stat->mf_type = FLT_TYPE_PERMANENT_CE; 1584 1772 jl139090 /* 1585 1772 jl139090 * rewrite request 1st time reads and correct error data 1586 1772 jl139090 * and write to DIMM. 2nd rewrite request must be issued 1587 1772 jl139090 * after REW_CE/UE/END is 0. When the 2nd request is completed, 1588 1772 jl139090 * if REW_CE = 1, then it is permanent CE. 1589 1772 jl139090 */ 1590 1772 jl139090 for (i = 0; i < 2; i++) { 1591 5310 dhain cntl = do_rewrite(mcp, bank, flt_stat->mf_err_add, 0); 1592 5310 dhain 1593 5310 dhain if (cntl == 0) { 1594 5310 dhain /* timeout case */ 1595 5310 dhain return; 1596 5310 dhain } 1597 1772 jl139090 /* 1598 1772 jl139090 * If the error becomes UE or CMPE 1599 1772 jl139090 * we return to the caller immediately. 1600 1772 jl139090 */ 1601 1772 jl139090 if (cntl & MAC_CNTL_REW_UE) { 1602 1772 jl139090 if (ptrl_error) 1603 1772 jl139090 flt_stat->mf_cntl |= MAC_CNTL_PTRL_UE; 1604 1772 jl139090 else 1605 1772 jl139090 flt_stat->mf_cntl |= MAC_CNTL_MI_UE; 1606 1772 jl139090 flt_stat->mf_type = FLT_TYPE_UE; 1607 1772 jl139090 return; 1608 1772 jl139090 } 1609 1772 jl139090 if (cntl & MAC_CNTL_REW_CMPE) { 1610 1772 jl139090 if (ptrl_error) 1611 1772 jl139090 flt_stat->mf_cntl |= MAC_CNTL_PTRL_CMPE; 1612 1772 jl139090 else 1613 1772 jl139090 flt_stat->mf_cntl |= MAC_CNTL_MI_CMPE; 1614 1772 jl139090 flt_stat->mf_type = FLT_TYPE_CMPE; 1615 1772 jl139090 return; 1616 1772 jl139090 } 1617 1772 jl139090 } 1618 1772 jl139090 if (!(cntl & MAC_CNTL_REW_CE)) { 1619 1772 jl139090 flt_stat->mf_type = FLT_TYPE_INTERMITTENT_CE; 1620 1772 jl139090 } 1621 1772 jl139090 1622 1772 jl139090 if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { 1623 1772 jl139090 /* report PERMANENT_CE to SP via SCF */ 1624 1772 jl139090 if (!(flt_stat->mf_err_log & MAC_ERR_LOG_INVALID)) { 1625 1772 jl139090 mc_queue_scf_log(mcp, flt_stat, bank); 1626 1772 jl139090 } 1627 1772 jl139090 } 1628 1772 jl139090 } 1629 1772 jl139090 1630 1772 jl139090 #define IS_CMPE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CMPE :\ 1631 1772 jl139090 MAC_CNTL_MI_CMPE)) 1632 1772 jl139090 #define IS_UE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_UE : MAC_CNTL_MI_UE)) 1633 1772 jl139090 #define IS_CE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CE : MAC_CNTL_MI_CE)) 1634 1772 jl139090 #define IS_OK(cntl, f) (!((cntl) & ((f) ? MAC_CNTL_PTRL_ERRS : \ 1635 1772 jl139090 MAC_CNTL_MI_ERRS))) 1636 1772 jl139090 1637 1772 jl139090 1638 1772 jl139090 static int 1639 1772 jl139090 IS_CE_ONLY(uint32_t cntl, int ptrl_error) 1640 1772 jl139090 { 1641 1772 jl139090 if (ptrl_error) { 1642 1772 jl139090 return ((cntl & MAC_CNTL_PTRL_ERRS) == MAC_CNTL_PTRL_CE); 1643 1772 jl139090 } else { 1644 1772 jl139090 return ((cntl & MAC_CNTL_MI_ERRS) == MAC_CNTL_MI_CE); 1645 1772 jl139090 } 1646 1772 jl139090 } 1647 1772 jl139090 1648 1772 jl139090 void 1649 1772 jl139090 mc_write_cntl(mc_opl_t *mcp, int bank, uint32_t value) 1650 1772 jl139090 { 1651 2867 hyw int ebank = (IS_MIRROR(mcp, bank)) ? MIRROR_IDX(bank) : bank; 1652 2867 hyw 1653 2867 hyw if (mcp->mc_speedup_period[ebank] > 0) 1654 2214 av145390 value |= mc_max_speed; 1655 2214 av145390 else 1656 2214 av145390 value |= mcp->mc_speed; 1657 1772 jl139090 ST_MAC_REG(MAC_PTRL_CNTL(mcp, bank), value); 1658 1772 jl139090 } 1659 1772 jl139090 1660 1772 jl139090 static void 1661 1772 jl139090 mc_read_ptrl_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat) 1662 1772 jl139090 { 1663 1772 jl139090 flt_stat->mf_cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & 1664 5080 wh31274 MAC_CNTL_PTRL_ERRS; 1665 1772 jl139090 flt_stat->mf_err_add = LD_MAC_REG(MAC_PTRL_ERR_ADD(mcp, bank)); 1666 1772 jl139090 flt_stat->mf_err_log = LD_MAC_REG(MAC_PTRL_ERR_LOG(mcp, bank)); 1667 1772 jl139090 flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num; 1668 3045 av145390 flt_stat->mf_flt_maddr.ma_phys_bd = mcp->mc_phys_board_num; 1669 1772 jl139090 flt_stat->mf_flt_maddr.ma_bank = bank; 1670 1772 jl139090 flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add; 1671 1772 jl139090 } 1672 1772 jl139090 1673 1772 jl139090 static void 1674 1772 jl139090 mc_read_mi_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat) 1675 1772 jl139090 { 1676 1772 jl139090 uint32_t status, old_status; 1677 1772 jl139090 1678 5080 wh31274 status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & MAC_CNTL_MI_ERRS; 1679 1772 jl139090 old_status = 0; 1680 1772 jl139090 1681 1772 jl139090 /* we keep reading until the status is stable */ 1682 1772 jl139090 while (old_status != status) { 1683 1772 jl139090 old_status = status; 1684 5080 wh31274 flt_stat->mf_err_add = LD_MAC_REG(MAC_MI_ERR_ADD(mcp, bank)); 1685 5080 wh31274 flt_stat->mf_err_log = LD_MAC_REG(MAC_MI_ERR_LOG(mcp, bank)); 1686 1772 jl139090 status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & 1687 5080 wh31274 MAC_CNTL_MI_ERRS; 1688 1772 jl139090 if (status == old_status) { 1689 1772 jl139090 break; 1690 1772 jl139090 } 1691 1772 jl139090 } 1692 1772 jl139090 1693 1772 jl139090 flt_stat->mf_cntl = status; 1694 1772 jl139090 flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num; 1695 3045 av145390 flt_stat->mf_flt_maddr.ma_phys_bd = mcp->mc_phys_board_num; 1696 1772 jl139090 flt_stat->mf_flt_maddr.ma_bank = bank; 1697 1772 jl139090 flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add; 1698 1772 jl139090 } 1699 1772 jl139090 1700 1772 jl139090 1701 1772 jl139090 /* 1702 1772 jl139090 * Error philosophy for mirror mode: 1703 1772 jl139090 * 1704 1772 jl139090 * PTRL (The error address for both banks are same, since ptrl stops if it 1705 1772 jl139090 * detects error.) 1706 3152 av145390 * - Compare error log CMPE. 1707 1772 jl139090 * 1708 1772 jl139090 * - UE-UE Report MUE. No rewrite. 1709 1772 jl139090 * 1710 1772 jl139090 * - UE-* UE-(CE/OK). Rewrite to scrub UE. Report SUE. 1711 1772 jl139090 * 1712 1772 jl139090 * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent. 1713 1772 jl139090 * If CE is permanent, inform SCF. Once for each 1714 1772 jl139090 * Dimm. If CE becomes UE or CMPE, go back to above. 1715 1772 jl139090 * 1716 1772 jl139090 * 1717 1772 jl139090 * MI (The error addresses for each bank are the same or different.) 1718 3152 av145390 * - Compare error If addresses are the same. Just CMPE, so log CMPE. 1719 1772 jl139090 * If addresses are different (this could happen 1720 3152 av145390 * as a result of scrubbing. Report each separately. 1721 1772 jl139090 * Only report error info on each side. 1722 1772 jl139090 * 1723 1772 jl139090 * - UE-UE Addresses are the same. Report MUE. 1724 1772 jl139090 * Addresses are different. Report SUE on each bank. 1725 1772 jl139090 * Rewrite to clear UE. 1726 1772 jl139090 * 1727 1772 jl139090 * - UE-* UE-(CE/OK) 1728 1772 jl139090 * Rewrite to clear UE. Report SUE for the bank. 1729 1772 jl139090 * 1730 1772 jl139090 * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent. 1731 1772 jl139090 * If CE becomes UE or CMPE, go back to above. 1732 1772 jl139090 * 1733 1772 jl139090 */ 1734 1772 jl139090 1735 1772 jl139090 static int 1736 1772 jl139090 mc_process_error_mir(mc_opl_t *mcp, mc_aflt_t *mc_aflt, mc_flt_stat_t *flt_stat) 1737 1772 jl139090 { 1738 1772 jl139090 int ptrl_error = mc_aflt->mflt_is_ptrl; 1739 1772 jl139090 int i; 1740 1772 jl139090 int rv = 0; 1741 5310 dhain int bank; 1742 5310 dhain int rewrite_timeout = 0; 1743 1772 jl139090 1744 1772 jl139090 MC_LOG("process mirror errors cntl[0] = %x, cntl[1] = %x\n", 1745 5080 wh31274 flt_stat[0].mf_cntl, flt_stat[1].mf_cntl); 1746 1772 jl139090 1747 1772 jl139090 if (ptrl_error) { 1748 5080 wh31274 if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) & 1749 5080 wh31274 MAC_CNTL_PTRL_ERRS) == 0) 1750 1772 jl139090 return (0); 1751 1772 jl139090 } else { 1752 5080 wh31274 if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) & 1753 5080 wh31274 MAC_CNTL_MI_ERRS) == 0) 1754 1772 jl139090 return (0); 1755 1772 jl139090 } 1756 1772 jl139090 1757 1772 jl139090 /* 1758 1772 jl139090 * First we take care of the case of CE 1759 1772 jl139090 * because they can become UE or CMPE 1760 1772 jl139090 */ 1761 1772 jl139090 for (i = 0; i < 2; i++) { 1762 1772 jl139090 if (IS_CE_ONLY(flt_stat[i].mf_cntl, ptrl_error)) { 1763 5310 dhain bank = flt_stat[i].mf_flt_maddr.ma_bank; 1764 5310 dhain MC_LOG("CE detected on bank %d\n", bank); 1765 5310 dhain mc_scrub_ce(mcp, bank, &flt_stat[i], ptrl_error); 1766 5310 dhain if (MC_REWRITE_ACTIVE(mcp, bank)) { 1767 5310 dhain rewrite_timeout = 1; 1768 5310 dhain } 1769 1772 jl139090 rv = 1; 1770 1772 jl139090 } 1771 1772 jl139090 } 1772 5310 dhain 1773 5310 dhain if (rewrite_timeout) 1774 5310 dhain return (0); 1775 1772 jl139090 1776 1772 jl139090 /* The above scrubbing can turn CE into UE or CMPE */ 1777 1772 jl139090 1778 1772 jl139090 /* 1779 1772 jl139090 * Now we distinguish two cases: same address or not 1780 1772 jl139090 * the same address. It might seem more intuitive to 1781 1772 jl139090 * distinguish PTRL v.s. MI error but it is more 1782 1772 jl139090 * complicated that way. 1783 1772 jl139090 */ 1784 1772 jl139090 1785 1772 jl139090 if (flt_stat[0].mf_err_add == flt_stat[1].mf_err_add) { 1786 1772 jl139090 1787 1772 jl139090 if (IS_CMPE(flt_stat[0].mf_cntl, ptrl_error) || 1788 1772 jl139090 IS_CMPE(flt_stat[1].mf_cntl, ptrl_error)) { 1789 1772 jl139090 flt_stat[0].mf_type = FLT_TYPE_CMPE; 1790 1772 jl139090 flt_stat[1].mf_type = FLT_TYPE_CMPE; 1791 1772 jl139090 mc_aflt->mflt_erpt_class = MC_OPL_CMPE; 1792 1772 jl139090 mc_aflt->mflt_nflts = 2; 1793 1772 jl139090 mc_aflt->mflt_stat[0] = &flt_stat[0]; 1794 1772 jl139090 mc_aflt->mflt_stat[1] = &flt_stat[1]; 1795 1772 jl139090 mc_aflt->mflt_pr = PR_UE; 1796 3152 av145390 /* 1797 3152 av145390 * Compare error is result of MAC internal error, so 1798 3152 av145390 * simply log it instead of publishing an ereport. SCF 1799 3152 av145390 * diagnoses all the MAC internal and its i/f error. 1800 3152 av145390 */ 1801 3152 av145390 MC_LOG("cmpe error detected\n"); 1802 1772 jl139090 return (1); 1803 1772 jl139090 } 1804 1772 jl139090 1805 1772 jl139090 if (IS_UE(flt_stat[0].mf_cntl, ptrl_error) && 1806 5080 wh31274 IS_UE(flt_stat[1].mf_cntl, ptrl_error)) { 1807 1772 jl139090 /* Both side are UE's */ 1808 1772 jl139090 1809 1772 jl139090 MAC_SET_ERRLOG_INFO(&flt_stat[0]); 1810 1772 jl139090 MAC_SET_ERRLOG_INFO(&flt_stat[1]); 1811 1772 jl139090 MC_LOG("MUE detected\n"); 1812 2214 av145390 flt_stat[0].mf_type = FLT_TYPE_MUE; 1813 2214 av145390 flt_stat[1].mf_type = FLT_TYPE_MUE; 1814 1772 jl139090 mc_aflt->mflt_erpt_class = MC_OPL_MUE; 1815 1772 jl139090 mc_aflt->mflt_nflts = 2; 1816 1772 jl139090 mc_aflt->mflt_stat[0] = &flt_stat[0]; 1817 1772 jl139090 mc_aflt->mflt_stat[1] = &flt_stat[1]; 1818 1772 jl139090 mc_aflt->mflt_pr = PR_UE; 1819 1772 jl139090 mc_err_drain(mc_aflt); 1820 1772 jl139090 return (1); 1821 1772 jl139090 } 1822 1772 jl139090 1823 1772 jl139090 /* Now the only case is UE/CE, UE/OK, or don't care */ 1824 1772 jl139090 for (i = 0; i < 2; i++) { 1825 5310 dhain if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) { 1826 2214 av145390 1827 2214 av145390 /* rewrite can clear the one side UE error */ 1828 2214 av145390 1829 1772 jl139090 if (IS_OK(flt_stat[i^1].mf_cntl, ptrl_error)) { 1830 1772 jl139090 (void) do_rewrite(mcp, 1831 1772 jl139090 flt_stat[i].mf_flt_maddr.ma_bank, 1832 5310 dhain flt_stat[i].mf_flt_maddr.ma_dimm_addr, 0); 1833 1772 jl139090 } 1834 1772 jl139090 flt_stat[i].mf_type = FLT_TYPE_UE; 1835 1772 jl139090 MAC_SET_ERRLOG_INFO(&flt_stat[i]); 1836 1772 jl139090 mc_aflt->mflt_erpt_class = MC_OPL_SUE; 1837 1772 jl139090 mc_aflt->mflt_stat[0] = &flt_stat[i]; 1838 1772 jl139090 mc_aflt->mflt_nflts = 1; 1839 1772 jl139090 mc_aflt->mflt_pr = PR_MCE; 1840 1772 jl139090 mc_err_drain(mc_aflt); 1841 1772 jl139090 /* Once we hit a UE/CE or UE/OK case, done */ 1842 1772 jl139090 return (1); 1843 5310 dhain } 1844 1772 jl139090 } 1845 1772 jl139090 1846 1772 jl139090 } else { 1847 1772 jl139090 /* 1848 1772 jl139090 * addresses are different. That means errors 1849 1772 jl139090 * on the 2 banks are not related at all. 1850 1772 jl139090 */ 1851 1772 jl139090 for (i = 0; i < 2; i++) { 1852 5080 wh31274 if (IS_CMPE(flt_stat[i].mf_cntl, ptrl_error)) { 1853 5080 wh31274 flt_stat[i].mf_type = FLT_TYPE_CMPE; 1854 5080 wh31274 mc_aflt->mflt_erpt_class = MC_OPL_CMPE; 1855 5080 wh31274 mc_aflt->mflt_nflts = 1; 1856 5080 wh31274 mc_aflt->mflt_stat[0] = &flt_stat[i]; 1857 5080 wh31274 mc_aflt->mflt_pr = PR_UE; 1858 5080 wh31274 /* 1859 5080 wh31274 * Compare error is result of MAC internal 1860 5080 wh31274 * error, so simply log it instead of 1861 5080 wh31274 * publishing an ereport. SCF diagnoses all 1862 5080 wh31274 * the MAC internal and its interface error. 1863 5080 wh31274 */ 1864 5080 wh31274 MC_LOG("cmpe error detected\n"); 1865 5080 wh31274 /* no more report on this bank */ 1866 5080 wh31274 flt_stat[i].mf_cntl = 0; 1867 5080 wh31274 rv = 1; 1868 5080 wh31274 } 1869 1772 jl139090 } 1870 1772 jl139090 1871 2214 av145390 /* rewrite can clear the one side UE error */ 1872 2214 av145390 1873 1772 jl139090 for (i = 0; i < 2; i++) { 1874 5080 wh31274 if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) { 1875 5080 wh31274 (void) do_rewrite(mcp, 1876 5080 wh31274 flt_stat[i].mf_flt_maddr.ma_bank, 1877 5310 dhain flt_stat[i].mf_flt_maddr.ma_dimm_addr, 1878 5310 dhain 0); 1879 5080 wh31274 flt_stat[i].mf_type = FLT_TYPE_UE; 1880 5080 wh31274 MAC_SET_ERRLOG_INFO(&flt_stat[i]); 1881 5080 wh31274 mc_aflt->mflt_erpt_class = MC_OPL_SUE; 1882 5080 wh31274 mc_aflt->mflt_stat[0] = &flt_stat[i]; 1883 5080 wh31274 mc_aflt->mflt_nflts = 1; 1884 5080 wh31274 mc_aflt->mflt_pr = PR_MCE; 1885 5080 wh31274 mc_err_drain(mc_aflt); 1886 5080 wh31274 rv = 1; 1887 5080 wh31274 } 1888 1772 jl139090 } 1889 1772 jl139090 } 1890 1772 jl139090 return (rv); 1891 1772 jl139090 } 1892 1772 jl139090 static void 1893 2662 hyw mc_error_handler_mir(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr) 1894 1772 jl139090 { 1895 1772 jl139090 mc_aflt_t mc_aflt; 1896 1772 jl139090 mc_flt_stat_t flt_stat[2], mi_flt_stat[2]; 1897 2214 av145390 int i; 1898 2214 av145390 int mi_valid; 1899 2662 hyw 1900 2662 hyw ASSERT(rsaddr); 1901 1772 jl139090 1902 1772 jl139090 bzero(&mc_aflt, sizeof (mc_aflt_t)); 1903 1772 jl139090 bzero(&flt_stat, 2 * sizeof (mc_flt_stat_t)); 1904 1772 jl139090 bzero(&mi_flt_stat, 2 * sizeof (mc_flt_stat_t)); 1905 3373 bm42561 1906 1772 jl139090 1907 1772 jl139090 mc_aflt.mflt_mcp = mcp; 1908 1772 jl139090 mc_aflt.mflt_id = gethrtime(); 1909 1772 jl139090 1910 1772 jl139090 /* Now read all the registers into flt_stat */ 1911 1772 jl139090 1912 2214 av145390 for (i = 0; i < 2; i++) { 1913 2214 av145390 MC_LOG("Reading registers of bank %d\n", bank); 1914 2214 av145390 /* patrol registers */ 1915 2214 av145390 mc_read_ptrl_reg(mcp, bank, &flt_stat[i]); 1916 1772 jl139090 1917 2662 hyw /* 1918 2662 hyw * In mirror mode, it is possible that only one bank 1919 2662 hyw * may report the error. We need to check for it to 1920 2662 hyw * ensure we pick the right addr value for patrol restart. 1921 2662 hyw * Note that if both banks reported errors, we pick the 1922 2662 hyw * 2nd one. Both banks should reported the same error address. 1923 2662 hyw */ 1924 2662 hyw if (flt_stat[i].mf_cntl & MAC_CNTL_PTRL_ERRS) 1925 2662 hyw rsaddr->mi_restartaddr = flt_stat[i].mf_flt_maddr; 1926 1772 jl139090 1927 2214 av145390 MC_LOG("ptrl registers cntl %x add %x log %x\n", 1928 5080 wh31274 flt_stat[i].mf_cntl, flt_stat[i].mf_err_add, 1929 5080 wh31274 flt_stat[i].mf_err_log); 1930 1772 jl139090 1931 2214 av145390 /* MI registers */ 1932 2214 av145390 mc_read_mi_reg(mcp, bank, &mi_flt_stat[i]); 1933 1772 jl139090 1934 2214 av145390 MC_LOG("MI registers cntl %x add %x log %x\n", 1935 5080 wh31274 mi_flt_stat[i].mf_cntl, mi_flt_stat[i].mf_err_add, 1936 5080 wh31274 mi_flt_stat[i].mf_err_log); 1937 1772 jl139090 1938 2214 av145390 bank = bank^1; 1939 2214 av145390 } 1940 1772 jl139090 1941 1772 jl139090 /* clear errors once we read all the registers */ 1942 5080 wh31274 MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); 1943 1772 jl139090 1944 2214 av145390 MAC_CLEAR_ERRS(mcp, bank ^ 1, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); 1945 1772 jl139090 1946 2214 av145390 /* Process MI errors first */ 1947 1772 jl139090 1948 2214 av145390 /* if not error mode, cntl1 is 0 */ 1949 2214 av145390 if ((mi_flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) || 1950 5080 wh31274 (mi_flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID)) 1951 2214 av145390 mi_flt_stat[0].mf_cntl = 0; 1952 2214 av145390 1953 2214 av145390 if ((mi_flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) || 1954 5080 wh31274 (mi_flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID)) 1955 2214 av145390 mi_flt_stat[1].mf_cntl = 0; 1956 2214 av145390 1957 2214 av145390 mc_aflt.mflt_is_ptrl = 0; 1958 2214 av145390 mi_valid = mc_process_error_mir(mcp, &mc_aflt, &mi_flt_stat[0]); 1959 2214 av145390 1960 2214 av145390 if ((((flt_stat[0].mf_cntl & MAC_CNTL_PTRL_ERRS) >> 1961 5080 wh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat[0].mf_cntl & 1962 5080 wh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) && 1963 6693 wh31274 (flt_stat[0].mf_err_add == 1964 6693 wh31274 ROUNDDOWN(mi_flt_stat[0].mf_err_add, MC_BOUND_BYTE)) && 1965 5080 wh31274 (((flt_stat[1].mf_cntl & MAC_CNTL_PTRL_ERRS) >> 1966 5080 wh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat[1].mf_cntl & 1967 5080 wh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) && 1968 6693 wh31274 (flt_stat[1].mf_err_add == 1969 6693 wh31274 ROUNDDOWN(mi_flt_stat[1].mf_err_add, MC_BOUND_BYTE))) { 1970 2214 av145390 #ifdef DEBUG 1971 2214 av145390 MC_LOG("discarding PTRL error because " 1972 2214 av145390 "it is the same as MI\n"); 1973 2214 av145390 #endif 1974 2662 hyw rsaddr->mi_valid = mi_valid; 1975 2214 av145390 return; 1976 2214 av145390 } 1977 1772 jl139090 /* if not error mode, cntl1 is 0 */ 1978 1772 jl139090 if ((flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) || 1979 5080 wh31274 (flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID)) 1980 1772 jl139090 flt_stat[0].mf_cntl = 0; 1981 1772 jl139090 1982 1772 jl139090 if ((flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) || 1983 5080 wh31274 (flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID)) 1984 1772 jl139090 flt_stat[1].mf_cntl = 0; 1985 1772 jl139090 1986 1772 jl139090 mc_aflt.mflt_is_ptrl = 1; 1987 2662 hyw rsaddr->mi_valid = mc_process_error_mir(mcp, &mc_aflt, &flt_stat[0]); 1988 1772 jl139090 } 1989 1772 jl139090 static int 1990 1772 jl139090 mc_process_error(mc_opl_t *mcp, int bank, mc_aflt_t *mc_aflt, 1991 1772 jl139090 mc_flt_stat_t *flt_stat) 1992 1772 jl139090 { 1993 1772 jl139090 int ptrl_error = mc_aflt->mflt_is_ptrl; 1994 1772 jl139090 int rv = 0; 1995 1772 jl139090 1996 1772 jl139090 mc_aflt->mflt_erpt_class = NULL; 1997 1772 jl139090 if (IS_UE(flt_stat->mf_cntl, ptrl_error)) { 1998 3152 av145390 MC_LOG("UE detected\n"); 1999 1772 jl139090 flt_stat->mf_type = FLT_TYPE_UE; 2000 1772 jl139090 mc_aflt->mflt_erpt_class = MC_OPL_UE; 2001 1772 jl139090 mc_aflt->mflt_pr = PR_UE; 2002 1772 jl139090 MAC_SET_ERRLOG_INFO(flt_stat); 2003 1772 jl139090 rv = 1; 2004 1772 jl139090 } else if (IS_CE(flt_stat->mf_cntl, ptrl_error)) { 2005 3152 av145390 MC_LOG("CE detected\n"); 2006 1772 jl139090 MAC_SET_ERRLOG_INFO(flt_stat); 2007 1772 jl139090 2008 3152 av145390 /* Error type can change after scrubbing */ 2009 1772 jl139090 mc_scrub_ce(mcp, bank, flt_stat, ptrl_error); 2010 5310 dhain if (MC_REWRITE_ACTIVE(mcp, bank)) { 2011 5310 dhain return (0); 2012 5310 dhain } 2013 1772 jl139090 2014 5275 tsien if (flt_stat->mf_type == FLT_TYPE_INTERMITTENT_CE) { 2015 5275 tsien mc_aflt->mflt_erpt_class = MC_OPL_ICE; 2016 5275 tsien mc_aflt->mflt_pr = PR_MCE; 2017 5275 tsien } else if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { 2018 1772 jl139090 mc_aflt->mflt_erpt_class = MC_OPL_CE; 2019 1772 jl139090 mc_aflt->mflt_pr = PR_MCE; 2020 1772 jl139090 } else if (flt_stat->mf_type == FLT_TYPE_UE) { 2021 1772 jl139090 mc_aflt->mflt_erpt_class = MC_OPL_UE; 2022 1772 jl139090 mc_aflt->mflt_pr = PR_UE; 2023 1772 jl139090 } 2024 1772 jl139090 rv = 1; 2025 1772 jl139090 } 2026 5080 wh31274 MC_LOG("mc_process_error: fault type %x erpt %s\n", flt_stat->mf_type, 2027 5080 wh31274 mc_aflt->mflt_erpt_class); 2028 1772 jl139090 if (mc_aflt->mflt_erpt_class) { 2029 1772 jl139090 mc_aflt->mflt_stat[0] = flt_stat; 2030 1772 jl139090 mc_aflt->mflt_nflts = 1; 2031 1772 jl139090 mc_err_drain(mc_aflt); 2032 1772 jl139090 } 2033 1772 jl139090 return (rv); 2034 1772 jl139090 } 2035 1772 jl139090 2036 1772 jl139090 static void 2037 2662 hyw mc_error_handler(mc_opl_t *mcp, int bank, mc_rsaddr_info_t *rsaddr) 2038 1772 jl139090 { 2039 1772 jl139090 mc_aflt_t mc_aflt; 2040 1772 jl139090 mc_flt_stat_t flt_stat, mi_flt_stat; 2041 2214 av145390 int mi_valid; 2042 1772 jl139090 2043 1772 jl139090 bzero(&mc_aflt, sizeof (mc_aflt_t)); 2044 1772 jl139090 bzero(&flt_stat, sizeof (mc_flt_stat_t)); 2045 1772 jl139090 bzero(&mi_flt_stat, sizeof (mc_flt_stat_t)); 2046 1772 jl139090 2047 1772 jl139090 mc_aflt.mflt_mcp = mcp; 2048 1772 jl139090 mc_aflt.mflt_id = gethrtime(); 2049 1772 jl139090 2050 1772 jl139090 /* patrol registers */ 2051 1772 jl139090 mc_read_ptrl_reg(mcp, bank, &flt_stat); 2052 1772 jl139090 2053 2662 hyw ASSERT(rsaddr); 2054 2662 hyw rsaddr->mi_restartaddr = flt_stat.mf_flt_maddr; 2055 1772 jl139090 2056 5080 wh31274 MC_LOG("ptrl registers cntl %x add %x log %x\n", flt_stat.mf_cntl, 2057 5080 wh31274 flt_stat.mf_err_add, flt_stat.mf_err_log); 2058 1772 jl139090 2059 1772 jl139090 /* MI registers */ 2060 1772 jl139090 mc_read_mi_reg(mcp, bank, &mi_flt_stat); 2061 1772 jl139090 2062 2214 av145390 2063 5080 wh31274 MC_LOG("MI registers cntl %x add %x log %x\n", mi_flt_stat.mf_cntl, 2064 5080 wh31274 mi_flt_stat.mf_err_add, mi_flt_stat.mf_err_log); 2065 1772 jl139090 2066 1772 jl139090 /* clear errors once we read all the registers */ 2067 1772 jl139090 MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); 2068 1772 jl139090 2069 2214 av145390 mc_aflt.mflt_is_ptrl = 0; 2070 2214 av145390 if ((mi_flt_stat.mf_cntl & MAC_CNTL_MI_ERRS) && 2071 5080 wh31274 ((mi_flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) && 2072 5080 wh31274 ((mi_flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) { 2073 2214 av145390 mi_valid = mc_process_error(mcp, bank, &mc_aflt, &mi_flt_stat); 2074 2214 av145390 } 2075 2214 av145390 2076 2214 av145390 if ((((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) >> 2077 5080 wh31274 MAC_CNTL_PTRL_ERR_SHIFT) == ((mi_flt_stat.mf_cntl & 2078 5080 wh31274 MAC_CNTL_MI_ERRS) >> MAC_CNTL_MI_ERR_SHIFT)) && 2079 6693 wh31274 (flt_stat.mf_err_add == 2080 6693 wh31274 ROUNDDOWN(mi_flt_stat.mf_err_add, MC_BOUND_BYTE))) { 2081 2214 av145390 #ifdef DEBUG 2082 2214 av145390 MC_LOG("discarding PTRL error because " 2083 2214 av145390 "it is the same as MI\n"); 2084 2214 av145390 #endif 2085 2662 hyw rsaddr->mi_valid = mi_valid; 2086 2214 av145390 return; 2087 2214 av145390 } 2088 2214 av145390 2089 1772 jl139090 mc_aflt.mflt_is_ptrl = 1; 2090 1772 jl139090 if ((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) && 2091 5080 wh31274 ((flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) && 2092 5080 wh31274 ((flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) { 2093 5080 wh31274 rsaddr->mi_valid = mc_process_error(mcp, bank, &mc_aflt, 2094 5080 wh31274 &flt_stat); 2095 1772 jl139090 } 2096 1772 jl139090 } 2097 1772 jl139090 /* 2098 1772 jl139090 * memory patrol error handling algorithm: 2099 1772 jl139090 * timeout() is used to do periodic polling 2100 1772 jl139090 * This is the flow chart. 2101 1772 jl139090 * timeout -> 2102 1772 jl139090 * mc_check_errors() 2103 1772 jl139090 * if memory bank is installed, read the status register 2104 1772 jl139090 * if any error bit is set, 2105 1772 jl139090 * -> mc_error_handler() 2106 3152 av145390 * -> read all error registers 2107 1772 jl139090 * -> mc_process_error() 2108 1772 jl139090 * determine error type 2109 1772 jl139090 * rewrite to clear error or scrub to determine CE type 2110 1772 jl139090 * inform SCF on permanent CE 2111 1772 jl139090 * -> mc_err_drain 2112 1772 jl139090 * page offline processing 2113 1772 jl139090 * -> mc_ereport_post() 2114 1772 jl139090 */ 2115 1772 jl139090 2116 1772 jl139090 static void 2117 5310 dhain mc_process_rewrite(mc_opl_t *mcp, int bank) 2118 5310 dhain { 2119 5310 dhain uint32_t rew_addr, cntl; 2120 5310 dhain mc_retry_info_t *retry; 2121 5310 dhain struct mc_bank *bankp; 2122 5310 dhain 2123 5310 dhain bankp = &(mcp->mc_bank[bank]); 2124 5310 dhain retry = bankp->mcb_active; 2125 5310 dhain if (retry == NULL) 2126 5310 dhain return; 2127 5310 dhain 2128 5310 dhain if (retry->ri_state <= RETRY_STATE_ACTIVE) { 2129 5310 dhain cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); 2130 5310 dhain if (cntl & MAC_CNTL_PTRL_STATUS) 2131 5310 dhain return; 2132 5310 dhain rew_addr = retry->ri_addr; 2133 5310 dhain ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), rew_addr); 2134 5310 dhain MAC_REW_REQ(mcp, bank); 2135 5310 dhain 2136 5310 dhain retry->ri_state = RETRY_STATE_REWRITE; 2137 5310 dhain } 2138 5310 dhain 2139 5310 dhain cntl = ldphysio(MAC_PTRL_CNTL(mcp, bank)); 2140 5310 dhain 2141 5310 dhain if (cntl & MAC_CNTL_REW_END) { 2142 5310 dhain MAC_CLEAR_ERRS(mcp, bank, 2143 5310 dhain MAC_CNTL_REW_ERRS); 2144 5310 dhain mc_clear_rewrite(mcp, bank); 2145 5310 dhain } else { 2146 5310 dhain /* 2147 5310 dhain * If the rewrite does not complete in 2148 5310 dhain * 1 hour, we have to consider this a HW 2149 5310 dhain * failure. However, there is no recovery 2150 5310 dhain * mechanism. The only thing we can do 2151 5310 dhain * to to print a warning message to the 2152 5310 dhain * console. We continue to increment the 2153 5310 dhain * counter but we only print the message 2154 5310 dhain * once. It will take the counter a long 2155 5310 dhain * time to wrap around and the user might 2156 5310 dhain * see a second message. In practice, 2157 5310 dhain * we have never hit this condition but 2158 5310 dhain * we have to keep the code here just in case. 2159 5310 dhain */ 2160 5310 dhain if (++mcp->mc_bank[bank].mcb_rewrite_count 2161 5310 dhain == mc_max_rewrite_retry) { 2162 5310 dhain cmn_err(CE_WARN, "Memory patrol feature is" 2163 5310 dhain " partly suspended on /LSB%d/B%d" 2164 5310 dhain " due to heavy memory load," 2165 5310 dhain " and it will restart" 2166 5310 dhain " automatically.\n", mcp->mc_board_num, 2167 5310 dhain bank); 2168 5310 dhain } 2169 5310 dhain } 2170 5310 dhain } 2171 5310 dhain 2172 5310 dhain static void 2173 1772 jl139090 mc_check_errors_func(mc_opl_t *mcp) 2174 1772 jl139090 { 2175 2662 hyw mc_rsaddr_info_t rsaddr_info; 2176 1772 jl139090 int i, error_count = 0; 2177 1772 jl139090 uint32_t stat, cntl; 2178 2214 av145390 int running; 2179 2494 hyw int wrapped; 2180 2867 hyw int ebk; 2181 1772 jl139090 2182 1772 jl139090 /* 2183 1772 jl139090 * scan errors. 2184 1772 jl139090 */ 2185 2214 av145390 if (mcp->mc_status & MC_MEMORYLESS) 2186 2214 av145390 return; 2187 2214 av145390 2188 1772 jl139090 for (i = 0; i < BANKNUM_PER_SB; i++) { 2189 1772 jl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { 2190 5310 dhain if (MC_REWRITE_ACTIVE(mcp, i)) { 2191 5310 dhain mc_process_rewrite(mcp, i); 2192 5310 dhain } 2193 1772 jl139090 stat = ldphysio(MAC_PTRL_STAT(mcp, i)); 2194 1772 jl139090 cntl = ldphysio(MAC_PTRL_CNTL(mcp, i)); 2195 2214 av145390 running = cntl & MAC_CNTL_PTRL_START; 2196 2494 hyw wrapped = cntl & MAC_CNTL_PTRL_ADD_MAX; 2197 2214 av145390 2198 2867 hyw /* Compute the effective bank idx */ 2199 2867 hyw ebk = (IS_MIRROR(mcp, i)) ? MIRROR_IDX(i) : i; 2200 2867 hyw 2201 2494 hyw if (mc_debug_show_all || stat) { 2202 2494 hyw MC_LOG("/LSB%d/B%d stat %x cntl %x\n", 2203 5080 wh31274 mcp->mc_board_num, i, stat, cntl); 2204 2494 hyw } 2205 2494 hyw 2206 2494 hyw /* 2207 2494 hyw * Update stats and reset flag if the HW patrol 2208 2494 hyw * wrapped around in its scan. 2209 2494 hyw */ 2210 2494 hyw if (wrapped) { 2211 1772 jl139090 MAC_CLEAR_MAX(mcp, i); 2212 2867 hyw mcp->mc_period[ebk]++; 2213 6297 jl139090 if (IS_MIRROR(mcp, i)) { 2214 5080 wh31274 MC_LOG("mirror mc period %ld on " 2215 5080 wh31274 "/LSB%d/B%d\n", mcp->mc_period[ebk], 2216 5080 wh31274 mcp->mc_board_num, i); 2217 6297 jl139090 } else { 2218 5080 wh31274 MC_LOG("mc period %ld on " 2219 5080 wh31274 "/LSB%d/B%d\n", mcp->mc_period[ebk], 2220 5080 wh31274 mcp->mc_board_num, i); 2221 2867 hyw } 2222 2494 hyw } 2223 2494 hyw 2224 2494 hyw if (running) { 2225 2494 hyw /* 2226 2494 hyw * Mac patrol HW is still running. 2227 2494 hyw * Normally when an error is detected, 2228 2494 hyw * the HW patrol will stop so that we 2229 2494 hyw * can collect error data for reporting. 2230 2494 hyw * Certain errors (MI errors) detected may not 2231 2494 hyw * cause the HW patrol to stop which is a 2232 2494 hyw * problem since we cannot read error data while 2233 2494 hyw * the HW patrol is running. SW is not allowed 2234 2494 hyw * to stop the HW patrol while it is running 2235 2494 hyw * as it may cause HW inconsistency. This is 2236 2494 hyw * described in a HW errata. 2237 2494 hyw * In situations where we detected errors 2238 2494 hyw * that may not cause the HW patrol to stop. 2239 2494 hyw * We speed up the HW patrol scanning in 2240 2494 hyw * the hope that it will find the 'real' PTRL 2241 2494 hyw * errors associated with the previous errors 2242 2494 hyw * causing the HW to finally stop so that we 2243 2494 hyw * can do the reporting. 2244 2494 hyw */ 2245 2494 hyw /* 2246 2494 hyw * Check to see if we did speed up 2247 2494 hyw * the HW patrol due to previous errors 2248 2494 hyw * detected that did not cause the patrol 2249 2494 hyw * to stop. We only do it if HW patrol scan 2250 2494 hyw * wrapped (counted as completing a 'period'). 2251 2494 hyw */ 2252 2867 hyw if (mcp->mc_speedup_period[ebk] > 0) { 2253 5080 wh31274 if (wrapped && 2254 5080 wh31274 (--mcp->mc_speedup_period[ebk] == 2255 5080 wh31274 0)) { 2256 5080 wh31274 /* 2257 5080 wh31274 * We did try to speed up. 2258 5080 wh31274 * The speed up period has 2259 5080 wh31274 * expired and the HW patrol 2260 5080 wh31274 * is still running. The 2261 5080 wh31274 * errors must be intermittent. 2262 5080 wh31274 * We have no choice but to 2263 5080 wh31274 * ignore them, reset the scan 2264 5080 wh31274 * speed to normal and clear 2265 5080 wh31274 * the MI error bits. For 2266 5080 wh31274 * mirror mode, we need to 2267 5080 wh31274 * clear errors on both banks. 2268 5080 wh31274 */ 2269 5080 wh31274 MC_LOG("Clearing MI errors\n"); 2270 5080 wh31274 MAC_CLEAR_ERRS(mcp, i, 2271 5080 wh31274 MAC_CNTL_MI_ERRS); 2272 2867 hyw 2273 5080 wh31274 if (IS_MIRROR(mcp, i)) { 2274 5080 wh31274 MC_LOG("Clearing " 2275 5080 wh31274 "Mirror MI errs\n"); 2276 5080 wh31274 MAC_CLEAR_ERRS(mcp, 2277 5080 wh31274 i^1, 2278 5080 wh31274 MAC_CNTL_MI_ERRS); 2279 5080 wh31274 } 2280 2867 hyw } 2281 2494 hyw } else if (stat & MAC_STAT_MI_ERRS) { 2282 2494 hyw /* 2283 2494 hyw * MI errors detected but we cannot 2284 2494 hyw * report them since the HW patrol 2285 2494 hyw * is still running. 2286 2494 hyw * We will attempt to speed up the 2287 2494 hyw * scanning and hopefully the HW 2288 2494 hyw * can detect PRTL errors at the same 2289 2494 hyw * location that cause the HW patrol 2290 2494 hyw * to stop. 2291 2494 hyw */ 2292 2867 hyw mcp->mc_speedup_period[ebk] = 2; 2293 2214 av145390 MAC_CMD(mcp, i, 0); 2294 2494 hyw } 2295 2494 hyw } else if (stat & (MAC_STAT_PTRL_ERRS | 2296 2494 hyw MAC_STAT_MI_ERRS)) { 2297 2494 hyw /* 2298 2494 hyw * HW Patrol has stopped and we found errors. 2299 2494 hyw * Proceed to collect and report error info. 2300 2494 hyw */ 2301 2867 hyw mcp->mc_speedup_period[ebk] = 0; 2302 2662 hyw rsaddr_info.mi_valid = 0; 2303 2662 hyw rsaddr_info.mi_injectrestart = 0; 2304 2662 hyw if (IS_MIRROR(mcp, i)) { 2305 5080 wh31274 mc_error_handler_mir(mcp, i, 2306 5080 wh31274 &rsaddr_info); 2307 2662 hyw } else { 2308 5080 wh31274 mc_error_handler(mcp, i, &rsaddr_info); 2309 2662 hyw } 2310 1772 jl139090 2311 2494 hyw error_count++; 2312 2662 hyw restart_patrol(mcp, i, &rsaddr_info); 2313 1772 jl139090 } else { 2314 2494 hyw /* 2315 2494 hyw * HW patrol scan has apparently stopped 2316 2494 hyw * but no errors detected/flagged. 2317 2494 hyw * Restart the HW patrol just to be sure. 2318 2867 hyw * In mirror mode, the odd bank might have 2319 2867 hyw * reported errors that caused the patrol to 2320 2867 hyw * stop. We'll defer the restart to the odd 2321 2867 hyw * bank in this case. 2322 2494 hyw */ 2323 2867 hyw if (!IS_MIRROR(mcp, i) || (i & 0x1)) 2324 2867 hyw restart_patrol(mcp, i, NULL); 2325 1772 jl139090 } 2326 1772 jl139090 } 2327 1772 jl139090 } 2328 1772 jl139090 if (error_count > 0) 2329 1772 jl139090 mcp->mc_last_error += error_count; 2330 1772 jl139090 else 2331 1772 jl139090 mcp->mc_last_error = 0; 2332 1772 jl139090 } 2333 1772 jl139090 2334 2214 av145390 /* 2335 2214 av145390 * mc_polling -- Check errors for only one instance, 2336 2214 av145390 * but process errors for all instances to make sure we drain the errors 2337 2214 av145390 * faster than they can be accumulated. 2338 2214 av145390 * 2339 2214 av145390 * Polling on each board should be done only once per each 2340 2214 av145390 * mc_patrol_interval_sec. This is equivalent to setting mc_tick_left 2341 2214 av145390 * to OPL_MAX_BOARDS and decrement by 1 on each timeout. 2342 2214 av145390 * Once mc_tick_left becomes negative, the board becomes a candidate 2343 2214 av145390 * for polling because it has waited for at least 2344 2214 av145390 * mc_patrol_interval_sec's long. If mc_timeout_period is calculated 2345 3152 av145390 * differently, this has to be updated accordingly. 2346 2214 av145390 */ 2347 1772 jl139090 2348 1772 jl139090 static void 2349 2214 av145390 mc_polling(void) 2350 1772 jl139090 { 2351 2214 av145390 int i, scan_error; 2352 2214 av145390 mc_opl_t *mcp; 2353 1772 jl139090 2354 1772 jl139090 2355 2214 av145390 scan_error = 1; 2356 2214 av145390 for (i = 0; i < OPL_MAX_BOARDS; i++) { 2357 2214 av145390 mutex_enter(&mcmutex); 2358 2214 av145390 if ((mcp = mc_instances[i]) == NULL) { 2359 2214 av145390 mutex_exit(&mcmutex); 2360 2214 av145390 continue; 2361 2214 av145390 } 2362 2214 av145390 mutex_enter(&mcp->mc_lock); 2363 2214 av145390 mutex_exit(&mcmutex); 2364 2662 hyw if (!(mcp->mc_status & MC_POLL_RUNNING)) { 2365 2662 hyw mutex_exit(&mcp->mc_lock); 2366 2662 hyw continue; 2367 2662 hyw } 2368 2214 av145390 if (scan_error && mcp->mc_tick_left <= 0) { 2369 2214 av145390 mc_check_errors_func((void *)mcp); 2370 2214 av145390 mcp->mc_tick_left = OPL_MAX_BOARDS; 2371 2214 av145390 scan_error = 0; 2372 2214 av145390 } else { 2373 2214 av145390 mcp->mc_tick_left--; 2374 2214 av145390 } 2375 2214 av145390 mc_process_scf_log(mcp); 2376 2214 av145390 mutex_exit(&mcp->mc_lock); 2377 1772 jl139090 } 2378 1772 jl139090 } 2379 1772 jl139090 2380 1772 jl139090 static void 2381 1772 jl139090 get_ptrl_start_address(mc_opl_t *mcp, int bank, mc_addr_t *maddr) 2382 1772 jl139090 { 2383 1772 jl139090 maddr->ma_bd = mcp->mc_board_num; 2384 1772 jl139090 maddr->ma_bank = bank; 2385 1772 jl139090 maddr->ma_dimm_addr = 0; 2386 1772 jl139090 } 2387 1772 jl139090 2388 1772 jl139090 typedef struct mc_mem_range { 2389 1772 jl139090 uint64_t addr; 2390 1772 jl139090 uint64_t size; 2391 1772 jl139090 } mc_mem_range_t; 2392 1772 jl139090 2393 1772 jl139090 static int 2394 1772 jl139090 get_base_address(mc_opl_t *mcp) 2395 1772 jl139090 { 2396 1772 jl139090 mc_mem_range_t *mem_range; 2397 1772 jl139090 int len; 2398 1772 jl139090 2399 1772 jl139090 if (ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS, 2400 5080 wh31274 "sb-mem-ranges", (caddr_t)&mem_range, &len) != DDI_SUCCESS) { 2401 1772 jl139090 return (DDI_FAILURE); 2402 1772 jl139090 } 2403 1772 jl139090 2404 1772 jl139090 mcp->mc_start_address = mem_range->addr; 2405 1772 jl139090 mcp->mc_size = mem_range->size; 2406 1772 jl139090 2407 1772 jl139090 kmem_free(mem_range, len); 2408 1772 jl139090 return (DDI_SUCCESS); 2409 1772 jl139090 } 2410 1772 jl139090 2411 1772 jl139090 struct mc_addr_spec { 2412 1772 jl139090 uint32_t bank; 2413 1772 jl139090 uint32_t phys_hi; 2414 1772 jl139090 uint32_t phys_lo; 2415 1772 jl139090 }; 2416 1772 jl139090 2417 1772 jl139090 #define REGS_PA(m, i) ((((uint64_t)m[i].phys_hi)<<32) | m[i].phys_lo) 2418 1772 jl139090 2419 1772 jl139090 static char *mc_tbl_name[] = { 2420 1772 jl139090 "cs0-mc-pa-trans-table", 2421 1772 jl139090 "cs1-mc-pa-trans-table" 2422 1772 jl139090 }; 2423 1772 jl139090 2424 2662 hyw /* 2425 2662 hyw * This routine performs a rangecheck for a given PA 2426 2662 hyw * to see if it belongs to the memory range for this board. 2427 2662 hyw * Return 1 if it is valid (within the range) and 0 otherwise 2428 2662 hyw */ 2429 1772 jl139090 static int 2430 2662 hyw mc_rangecheck_pa(mc_opl_t *mcp, uint64_t pa) 2431 1772 jl139090 { 2432 5080 wh31274 if ((pa < mcp->mc_start_address) || (mcp->mc_start_address + 2433 5080 wh31274 mcp->mc_size <= pa)) 2434 2662 hyw return (0); 2435 2662 hyw else 2436 2662 hyw return (1); 2437 1772 jl139090 } 2438 1772 jl139090 2439 1772 jl139090 static void 2440 1772 jl139090 mc_memlist_delete(struct memlist *mlist) 2441 1772 jl139090 { 2442 1772 jl139090 struct memlist *ml; 2443 1772 jl139090 2444 1772 jl139090 for (ml = mlist; ml; ml = mlist) { 2445 1772 jl139090 mlist = ml->next; 2446 1772 jl139090 kmem_free(ml, sizeof (struct memlist)); 2447 1772 jl139090 } 2448 1772 jl139090 } 2449 1772 jl139090 2450 1772 jl139090 static struct memlist * 2451 1772 jl139090 mc_memlist_dup(struct memlist *mlist) 2452 1772 jl139090 { 2453 1772 jl139090 struct memlist *hl = NULL, *tl, **mlp; 2454 1772 jl139090 2455 1772 jl139090 if (mlist == NULL) 2456 1772 jl139090 return (NULL); 2457 1772 jl139090 2458 1772 jl139090 mlp = &hl; 2459 1772 jl139090 tl = *mlp; 2460 1772 jl139090 for (; mlist; mlist = mlist->next) { 2461 1772 jl139090 *mlp = kmem_alloc(sizeof (struct memlist), KM_SLEEP); 2462 1772 jl139090 (*mlp)->address = mlist->address; 2463 1772 jl139090 (*mlp)->size = mlist->size; 2464 1772 jl139090 (*mlp)->prev = tl; 2465 1772 jl139090 tl = *mlp; 2466 1772 jl139090 mlp = &((*mlp)->next); 2467 1772 jl139090 } 2468 1772 jl139090 *mlp = NULL; 2469 1772 jl139090 2470 1772 jl139090 return (hl); 2471 1772 jl139090 } 2472 1772 jl139090 2473 1772 jl139090 2474 1772 jl139090 static struct memlist * 2475 1772 jl139090 mc_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len) 2476 1772 jl139090 { 2477 1772 jl139090 uint64_t end; 2478 1772 jl139090 struct memlist *ml, *tl, *nlp; 2479 1772 jl139090 2480 1772 jl139090 if (mlist == NULL) 2481 1772 jl139090 return (NULL); 2482 1772 jl139090 2483 1772 jl139090 end = base + len; 2484 1772 jl139090 if ((end <= mlist->address) || (base == end)) 2485 1772 jl139090 return (mlist); 2486 1772 jl139090 2487 1772 jl139090 for (tl = ml = mlist; ml; tl = ml, ml = nlp) { 2488 1772 jl139090 uint64_t mend; 2489 1772 jl139090 2490 1772 jl139090 nlp = ml->next; 2491 1772 jl139090 2492 1772 jl139090 if (end <= ml->address) 2493 1772 jl139090 break; 2494 1772 jl139090 2495 1772 jl139090 mend = ml->address + ml->size; 2496 1772 jl139090 if (base < mend) { 2497 1772 jl139090 if (base <= ml->address) { 2498 1772 jl139090 ml->address = end; 2499 1772 jl139090 if (end >= mend) 2500 1772 jl139090 ml->size = 0ull; 2501 1772 jl139090 else 2502 1772 jl139090 ml->size = mend - ml->address; 2503 1772 jl139090 } else { 2504 1772 jl139090 ml->size = base - ml->address; 2505 1772 jl139090 if (end < mend) { 2506 1772 jl139090 struct memlist *nl; 2507 1772 jl139090 /* 2508 1772 jl139090 * splitting an memlist entry. 2509 1772 jl139090 */ 2510 1772 jl139090 nl = kmem_alloc(sizeof (struct memlist), 2511 5080 wh31274 KM_SLEEP); 2512 1772 jl139090 nl->address = end; 2513 1772 jl139090 nl->size = mend - nl->address; 2514 1772 jl139090 if ((nl->next = nlp) != NULL) 2515 1772 jl139090 nlp->prev = nl; 2516 1772 jl139090 nl->prev = ml; 2517 1772 jl139090 ml->next = nl; 2518 1772 jl139090 nlp = nl; 2519 1772 jl139090 } 2520 1772 jl139090 } 2521 1772 jl139090 if (ml->size == 0ull) { 2522 1772 jl139090 if (ml == mlist) { 2523 1772 jl139090 if ((mlist = nlp) != NULL) 2524 1772 jl139090 nlp->prev = NULL; 2525 1772 jl139090 kmem_free(ml, sizeof (struct memlist)); 2526 1772 jl139090 if (mlist == NULL) 2527 1772 jl139090 break; 2528 1772 jl139090 ml = nlp; 2529 1772 jl139090 } else { 2530 1772 jl139090 if ((tl->next = nlp) != NULL) 2531 1772 jl139090 nlp->prev = tl; 2532 1772 jl139090 kmem_free(ml, sizeof (struct memlist)); 2533 1772 jl139090 ml = tl; 2534 1772 jl139090 } 2535 1772 jl139090 } 2536 1772 jl139090 } 2537 1772 jl139090 } 2538 1772 jl139090 2539 1772 jl139090 return (mlist); 2540 1772 jl139090 } 2541 1772 jl139090 2542 1772 jl139090 static void 2543 1772 jl139090 mc_get_mlist(mc_opl_t *mcp) 2544 1772 jl139090 { 2545 1772 jl139090 struct memlist *mlist; 2546 1772 jl139090 2547 1772 jl139090 memlist_read_lock(); 2548 1772 jl139090 mlist = mc_memlist_dup(phys_install); 2549 1772 jl139090 memlist_read_unlock(); 2550 1772 jl139090 2551 1772 jl139090 if (mlist) { 2552 1772 jl139090 mlist = mc_memlist_del_span(mlist, 0ull, mcp->mc_start_address); 2553 1772 jl139090 } 2554 1772 jl139090 2555 1772 jl139090 if (mlist) { 2556 1772 jl139090 uint64_t startpa, endpa; 2557 1772 jl139090 2558 1772 jl139090 startpa = mcp->mc_start_address + mcp->mc_size; 2559 1772 jl139090 endpa = ptob(physmax + 1); 2560 1772 jl139090 if (endpa > startpa) { 2561 5080 wh31274 mlist = mc_memlist_del_span(mlist, startpa, 2562 5080 wh31274 endpa - startpa); 2563 1772 jl139090 } 2564 1772 jl139090 } 2565 1772 jl139090 2566 1772 jl139090 if (mlist) { 2567 1772 jl139090 mcp->mlist = mlist; 2568 1772 jl139090 } 2569 1772 jl139090 } 2570 1772 jl139090 2571 1772 jl139090 int 2572 1772 jl139090 mc_board_add(mc_opl_t *mcp) 2573 1772 jl139090 { 2574 1772 jl139090 struct mc_addr_spec *macaddr; 2575 2214 av145390 cs_status_t *cs_status; 2576 2214 av145390 int len, len1, i, bk, cc; 2577 2662 hyw mc_rsaddr_info_t rsaddr; 2578 1772 jl139090 uint32_t mirr; 2579 2214 av145390 int nbanks = 0; 2580 2214 av145390 uint64_t nbytes = 0; 2581 5080 wh31274 int mirror_mode = 0; 2582 5080 wh31274 int ret; 2583 1772 jl139090 2584 1772 jl139090 /* 2585 1772 jl139090 * Get configurations from "pseudo-mc" node which includes: 2586 1772 jl139090 * board# : LSB number 2587 1772 jl139090 * mac-addr : physical base address of MAC registers 2588 1772 jl139090 * csX-mac-pa-trans-table: translation table from DIMM address 2589 1772 jl139090 * to physical address or vice versa. 2590 1772 jl139090 */ 2591 1772 jl139090 mcp->mc_board_num = (int)ddi_getprop(DDI_DEV_T_ANY, mcp->mc_dip, 2592 5080 wh31274 DDI_PROP_DONTPASS, "board#", -1); 2593 1772 jl139090 2594 2214 av145390 if (mcp->mc_board_num == -1) { 2595 2214 av145390 return (DDI_FAILURE); 2596 2214 av145390 } 2597 2214 av145390 2598 1772 jl139090 /* 2599 1772 jl139090 * Get start address in this CAB. It can be gotten from 2600 1772 jl139090 * "sb-mem-ranges" property. 2601 1772 jl139090 */ 2602 1772 jl139090 2603 1772 jl139090 if (get_base_address(mcp) == DDI_FAILURE) { 2604 1772 jl139090 return (DDI_FAILURE); 2605 1772 jl139090 } 2606 1772 jl139090 /* get mac-pa trans tables */ 2607 1772 jl139090 for (i = 0; i < MC_TT_CS; i++) { 2608 1772 jl139090 len = MC_TT_ENTRIES; 2609 1772 jl139090 cc = ddi_getlongprop_buf(DDI_DEV_T_ANY, mcp->mc_dip, 2610 5080 wh31274 DDI_PROP_DONTPASS, mc_tbl_name[i], 2611 5080 wh31274 (caddr_t)mcp->mc_trans_table[i], &len); 2612 1772 jl139090 2613 1772 jl139090 if (cc != DDI_SUCCESS) { 2614 1772 jl139090 bzero(mcp->mc_trans_table[i], MC_TT_ENTRIES); 2615 1772 jl139090 } 2616 1772 jl139090 } 2617 1772 jl139090 mcp->mlist = NULL; 2618 1772 jl139090 2619 1772 jl139090 mc_get_mlist(mcp); 2620 1772 jl139090 2621 1772 jl139090 /* initialize bank informations */ 2622 1772 jl139090 cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS, 2623 5080 wh31274 "mc-addr", (caddr_t)&macaddr, &len); 2624 1772 jl139090 if (cc != DDI_SUCCESS) { 2625 1772 jl139090 cmn_err(CE_WARN, "Cannot get mc-addr. err=%d\n", cc); 2626 1772 jl139090 return (DDI_FAILURE); 2627 1772 jl139090 } 2628 2214 av145390 2629 2214 av145390 cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS, 2630 5080 wh31274 "cs-status", (caddr_t)&cs_status, &len1); 2631 2214 av145390 2632 2214 av145390 if (cc != DDI_SUCCESS) { 2633 2214 av145390 if (len > 0) 2634 2214 av145390 kmem_free(macaddr, len); 2635 2214 av145390 cmn_err(CE_WARN, "Cannot get cs-status. err=%d\n", cc); 2636 2214 av145390 return (DDI_FAILURE); 2637 2214 av145390 } 2638 3045 av145390 /* get the physical board number for a given logical board number */ 2639 3045 av145390 mcp->mc_phys_board_num = mc_opl_get_physical_board(mcp->mc_board_num); 2640 3045 av145390 2641 3045 av145390 if (mcp->mc_phys_board_num < 0) { 2642 3045 av145390 if (len > 0) 2643 3045 av145390 kmem_free(macaddr, len); 2644 3045 av145390 cmn_err(CE_WARN, "Unable to obtain the physical board number"); 2645 3045 av145390 return (DDI_FAILURE); 2646 3045 av145390 } 2647 2214 av145390 2648 2214 av145390 mutex_init(&mcp->mc_lock, NULL, MUTEX_DRIVER, NULL); 2649 2214 av145390 2650 2214 av145390 for (i = 0; i < len1 / sizeof (cs_status_t); i++) { 2651 2214 av145390 nbytes += ((uint64_t)cs_status[i].cs_avail_hi << 32) | 2652 5080 wh31274 ((uint64_t)cs_status[i].cs_avail_low); 2653 2214 av145390 } 2654 2214 av145390 if (len1 > 0) 2655 2214 av145390 kmem_free(cs_status, len1); 2656 2214 av145390 nbanks = len / sizeof (struct mc_addr_spec); 2657 2214 av145390 2658 2214 av145390 if (nbanks > 0) 2659 2214 av145390 nbytes /= nbanks; 2660 2214 av145390 else { 2661 2214 av145390 /* No need to free macaddr because len must be 0 */ 2662 2214 av145390 mcp->mc_status |= MC_MEMORYLESS; 2663 2214 av145390 return (DDI_SUCCESS); 2664 2214 av145390 } 2665 2214 av145390 2666 2214 av145390 for (i = 0; i < BANKNUM_PER_SB; i++) { 2667 2214 av145390 mcp->mc_scf_retry[i] = 0; 2668 2214 av145390 mcp->mc_period[i] = 0; 2669 2214 av145390 mcp->mc_speedup_period[i] = 0; 2670 2214 av145390 } 2671 2214 av145390 2672 2214 av145390 /* 2673 2214 av145390 * Get the memory size here. Let it be B (bytes). 2674 2214 av145390 * Let T be the time in u.s. to scan 64 bytes. 2675 2214 av145390 * If we want to complete 1 round of scanning in P seconds. 2676 2214 av145390 * 2677 2214 av145390 * B * T * 10^(-6) = P 2678 2214 av145390 * --------------- 2679 2214 av145390 * 64 2680 2214 av145390 * 2681 2214 av145390 * T = P * 64 * 10^6 2682 2214 av145390 * ------------- 2683 2214 av145390 * B 2684 2214 av145390 * 2685 2214 av145390 * = P * 64 * 10^6 2686 2214 av145390 * ------------- 2687 2214 av145390 * B 2688 2214 av145390 * 2689 2214 av145390 * The timing bits are set in PTRL_CNTL[28:26] where 2690 2214 av145390 * 2691 2214 av145390 * 0 - 1 m.s 2692 2214 av145390 * 1 - 512 u.s. 2693 2214 av145390 * 10 - 256 u.s. 2694 2214 av145390 * 11 - 128 u.s. 2695 2214 av145390 * 100 - 64 u.s. 2696 2214 av145390 * 101 - 32 u.s. 2697 2214 av145390 * 110 - 0 u.s. 2698 2214 av145390 * 111 - reserved. 2699 2214 av145390 * 2700 2214 av145390 * 2701 2214 av145390 * a[0] = 110, a[1] = 101, ... a[6] = 0 2702 2214 av145390 * 2703 2214 av145390 * cs-status property is int x 7 2704 2214 av145390 * 0 - cs# 2705 2214 av145390 * 1 - cs-status 2706 2214 av145390 * 2 - cs-avail.hi 2707 2214 av145390 * 3 - cs-avail.lo 2708 2214 av145390 * 4 - dimm-capa.hi 2709 2214 av145390 * 5 - dimm-capa.lo 2710 2214 av145390 * 6 - #of dimms 2711 2214 av145390 */ 2712 2214 av145390 2713 2214 av145390 if (nbytes > 0) { 2714 2214 av145390 int i; 2715 2214 av145390 uint64_t ms; 2716 2214 av145390 ms = ((uint64_t)mc_scan_period * 64 * 1000000)/nbytes; 2717 2214 av145390 mcp->mc_speed = mc_scan_speeds[MC_MAX_SPEEDS - 1].mc_speeds; 2718 2214 av145390 for (i = 0; i < MC_MAX_SPEEDS - 1; i++) { 2719 2214 av145390 if (ms < mc_scan_speeds[i + 1].mc_period) { 2720 2214 av145390 mcp->mc_speed = mc_scan_speeds[i].mc_speeds; 2721 2214 av145390 break; 2722 2214 av145390 } 2723 2214 av145390 } 2724 2214 av145390 } else 2725 2214 av145390 mcp->mc_speed = 0; 2726 2214 av145390 2727 1772 jl139090 2728 1772 jl139090 for (i = 0; i < len / sizeof (struct mc_addr_spec); i++) { 2729 1772 jl139090 struct mc_bank *bankp; 2730 5310 dhain mc_retry_info_t *retry; 2731 1772 jl139090 uint32_t reg; 2732 5310 dhain int k; 2733 1772 jl139090 2734 1772 jl139090 /* 2735 1772 jl139090 * setup bank 2736 1772 jl139090 */ 2737 1772 jl139090 bk = macaddr[i].bank; 2738 1772 jl139090 bankp = &(mcp->mc_bank[bk]); 2739 1772 jl139090 bankp->mcb_status = BANK_INSTALLED; 2740 1772 jl139090 bankp->mcb_reg_base = REGS_PA(macaddr, i); 2741 5310 dhain 2742 5310 dhain bankp->mcb_retry_freelist = NULL; 2743 5310 dhain bankp->mcb_retry_pending = NULL; 2744 5310 dhain bankp->mcb_active = NULL; 2745 5310 dhain retry = &bankp->mcb_retry_infos[0]; 2746 5310 dhain for (k = 0; k < MC_RETRY_COUNT; k++, retry++) { 2747 5310 dhain mc_retry_info_put(&bankp->mcb_retry_freelist, retry); 2748 5310 dhain } 2749 1772 jl139090 2750 1772 jl139090 reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bk)); 2751 1772 jl139090 bankp->mcb_ptrl_cntl = (reg & MAC_CNTL_PTRL_PRESERVE_BITS); 2752 1772 jl139090 2753 1772 jl139090 /* 2754 1772 jl139090 * check if mirror mode 2755 1772 jl139090 */ 2756 1772 jl139090 mirr = LD_MAC_REG(MAC_MIRR(mcp, bk)); 2757 1772 jl139090 2758 1772 jl139090 if (mirr & MAC_MIRR_MIRROR_MODE) { 2759 5080 wh31274 MC_LOG("Mirror -> /LSB%d/B%d\n", mcp->mc_board_num, 2760 5080 wh31274 bk); 2761 1772 jl139090 bankp->mcb_status |= BANK_MIRROR_MODE; 2762 5080 wh31274 mirror_mode = 1; 2763 1772 jl139090 /* 2764 1772 jl139090 * The following bit is only used for 2765 1772 jl139090 * error injection. We should clear it 2766 1772 jl139090 */ 2767 1772 jl139090 if (mirr & MAC_MIRR_BANK_EXCLUSIVE) 2768 5080 wh31274 ST_MAC_REG(MAC_MIRR(mcp, bk), 0); 2769 1772 jl139090 } 2770 1772 jl139090 2771 1772 jl139090 /* 2772 1772 jl139090 * restart if not mirror mode or the other bank 2773 1772 jl139090 * of the mirror is not running 2774 1772 jl139090 */ 2775 1772 jl139090 if (!(mirr & MAC_MIRR_MIRROR_MODE) || 2776 5080 wh31274 !(mcp->mc_bank[bk^1].mcb_status & BANK_PTRL_RUNNING)) { 2777 5080 wh31274 MC_LOG("Starting up /LSB%d/B%d\n", mcp->mc_board_num, 2778 5080 wh31274 bk); 2779 2662 hyw get_ptrl_start_address(mcp, bk, &rsaddr.mi_restartaddr); 2780 2662 hyw rsaddr.mi_valid = 0; 2781 2662 hyw rsaddr.mi_injectrestart = 0; 2782 2662 hyw restart_patrol(mcp, bk, &rsaddr); 2783 1772 jl139090 } else { 2784 1772 jl139090 MC_LOG("Not starting up /LSB%d/B%d\n", 2785 5080 wh31274 mcp->mc_board_num, bk); 2786 1772 jl139090 } 2787 1772 jl139090 bankp->mcb_status |= BANK_PTRL_RUNNING; 2788 1772 jl139090 } 2789 2214 av145390 if (len > 0) 2790 2214 av145390 kmem_free(macaddr, len); 2791 5080 wh31274 2792 5080 wh31274 ret = ndi_prop_update_int(DDI_DEV_T_NONE, mcp->mc_dip, "mirror-mode", 2793 5080 wh31274 mirror_mode); 2794 5080 wh31274 if (ret != DDI_PROP_SUCCESS) { 2795 5080 wh31274 cmn_err(CE_WARN, "Unable to update mirror-mode property"); 2796 5080 wh31274 } 2797 2214 av145390 2798 2214 av145390 mcp->mc_dimm_list = mc_get_dimm_list(mcp); 2799 1772 jl139090 2800 1772 jl139090 /* 2801 1772 jl139090 * set interval in HZ. 2802 1772 jl139090 */ 2803 1772 jl139090 mcp->mc_last_error = 0; 2804 1772 jl139090 2805 1772 jl139090 /* restart memory patrol checking */ 2806 1772 jl139090 mcp->mc_status |= MC_POLL_RUNNING; 2807 1772 jl139090 2808 1772 jl139090 return (DDI_SUCCESS); 2809 1772 jl139090 } 2810 1772 jl139090 2811 1772 jl139090 int 2812 1772 jl139090 mc_board_del(mc_opl_t *mcp) 2813 1772 jl139090 { 2814 1772 jl139090 int i; 2815 1772 jl139090 scf_log_t *p; 2816 1772 jl139090 2817 1772 jl139090 /* 2818 1772 jl139090 * cleanup mac state 2819 1772 jl139090 */ 2820 1772 jl139090 mutex_enter(&mcp->mc_lock); 2821 2214 av145390 if (mcp->mc_status & MC_MEMORYLESS) { 2822 2214 av145390 mutex_exit(&mcp->mc_lock); 2823 2214 av145390 mutex_destroy(&mcp->mc_lock); 2824 2214 av145390 return (DDI_SUCCESS); 2825 2214 av145390 } 2826 1772 jl139090 for (i = 0; i < BANKNUM_PER_SB; i++) { 2827 1772 jl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { 2828 1772 jl139090 mcp->mc_bank[i].mcb_status &= ~BANK_INSTALLED; 2829 1772 jl139090 } 2830 1772 jl139090 } 2831 1772 jl139090 2832 1772 jl139090 /* stop memory patrol checking */ 2833 2662 hyw mcp->mc_status &= ~MC_POLL_RUNNING; 2834 1772 jl139090 2835 1772 jl139090 /* just throw away all the scf logs */ 2836 2214 av145390 for (i = 0; i < BANKNUM_PER_SB; i++) { 2837 5080 wh31274 while ((p = mcp->mc_scf_log[i]) != NULL) { 2838 5080 wh31274 mcp->mc_scf_log[i] = p->sl_next; 2839 5080 wh31274 mcp->mc_scf_total[i]--; 2840 5080 wh31274 kmem_free(p, sizeof (scf_log_t)); 2841 5080 wh31274 } 2842 1772 jl139090 } 2843 1772 jl139090 2844 1772 jl139090 if (mcp->mlist) 2845 1772 jl139090 mc_memlist_delete(mcp->mlist); 2846 1772 jl139090 2847 2214 av145390 if (mcp->mc_dimm_list) 2848 2214 av145390 mc_free_dimm_list(mcp->mc_dimm_list); 2849 2214 av145390 2850 1772 jl139090 mutex_exit(&mcp->mc_lock); 2851 1772 jl139090 2852 1772 jl139090 mutex_destroy(&mcp->mc_lock); 2853 1772 jl139090 return (DDI_SUCCESS); 2854 1772 jl139090 } 2855 1772 jl139090 2856 1772 jl139090 int 2857 1772 jl139090 mc_suspend(mc_opl_t *mcp, uint32_t flag) 2858 1772 jl139090 { 2859 1772 jl139090 /* stop memory patrol checking */ 2860 1772 jl139090 mutex_enter(&mcp->mc_lock); 2861 2214 av145390 if (mcp->mc_status & MC_MEMORYLESS) { 2862 2214 av145390 mutex_exit(&mcp->mc_lock); 2863 2214 av145390 return (DDI_SUCCESS); 2864 2214 av145390 } 2865 2214 av145390 2866 2662 hyw mcp->mc_status &= ~MC_POLL_RUNNING; 2867 2662 hyw 2868 1772 jl139090 mcp->mc_status |= flag; 2869 1772 jl139090 mutex_exit(&mcp->mc_lock); 2870 1772 jl139090 2871 1772 jl139090 return (DDI_SUCCESS); 2872 3354 jl139090 } 2873 3354 jl139090 2874 3354 jl139090 void 2875 3354 jl139090 opl_mc_update_mlist(void) 2876 3354 jl139090 { 2877 3354 jl139090 int i; 2878 3354 jl139090 mc_opl_t *mcp; 2879 3354 jl139090 2880 3354 jl139090 /* 2881 3354 jl139090 * memory information is not updated until 2882 3354 jl139090 * the post attach/detach stage during DR. 2883 3354 jl139090 * This interface is used by dr_mem to inform 2884 3354 jl139090 * mc-opl to update the mlist. 2885 3354 jl139090 */ 2886 3354 jl139090 2887 3354 jl139090 mutex_enter(&mcmutex); 2888 3354 jl139090 for (i = 0; i < OPL_MAX_BOARDS; i++) { 2889 3354 jl139090 if ((mcp = mc_instances[i]) == NULL) 2890 3354 jl139090 continue; 2891 3354 jl139090 mutex_enter(&mcp->mc_lock); 2892 3354 jl139090 if (mcp->mlist) 2893 3354 jl139090 mc_memlist_delete(mcp->mlist); 2894 3354 jl139090 mcp->mlist = NULL; 2895 3354 jl139090 mc_get_mlist(mcp); 2896 3354 jl139090 mutex_exit(&mcp->mc_lock); 2897 3354 jl139090 } 2898 3354 jl139090 mutex_exit(&mcmutex); 2899 1772 jl139090 } 2900 1772 jl139090 2901 1772 jl139090 /* caller must clear the SUSPEND bits or this will do nothing */ 2902 1772 jl139090 2903 1772 jl139090 int 2904 1772 jl139090 mc_resume(mc_opl_t *mcp, uint32_t flag) 2905 1772 jl139090 { 2906 1772 jl139090 int i; 2907 1772 jl139090 uint64_t basepa; 2908 1772 jl139090 2909 1772 jl139090 mutex_enter(&mcp->mc_lock); 2910 2214 av145390 if (mcp->mc_status & MC_MEMORYLESS) { 2911 2214 av145390 mutex_exit(&mcp->mc_lock); 2912 2214 av145390 return (DDI_SUCCESS); 2913 2214 av145390 } 2914 1772 jl139090 basepa = mcp->mc_start_address; 2915 1772 jl139090 if (get_base_address(mcp) == DDI_FAILURE) { 2916 1772 jl139090 mutex_exit(&mcp->mc_lock); 2917 1772 jl139090 return (DDI_FAILURE); 2918 1772 jl139090 } 2919 1772 jl139090 2920 1772 jl139090 if (basepa != mcp->mc_start_address) { 2921 1772 jl139090 if (mcp->mlist) 2922 1772 jl139090 mc_memlist_delete(mcp->mlist); 2923 1772 jl139090 mcp->mlist = NULL; 2924 1772 jl139090 mc_get_mlist(mcp); 2925 1772 jl139090 } 2926 1772 jl139090 2927 1772 jl139090 mcp->mc_status &= ~flag; 2928 1772 jl139090 2929 1772 jl139090 if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) { 2930 1772 jl139090 mutex_exit(&mcp->mc_lock); 2931 1772 jl139090 return (DDI_SUCCESS); 2932 1772 jl139090 } 2933 1772 jl139090 2934 1772 jl139090 if (!(mcp->mc_status & MC_POLL_RUNNING)) { 2935 1772 jl139090 /* restart memory patrol checking */ 2936 1772 jl139090 mcp->mc_status |= MC_POLL_RUNNING; 2937 1772 jl139090 for (i = 0; i < BANKNUM_PER_SB; i++) { 2938 1772 jl139090 if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { 2939 5310 dhain mc_check_errors_func(mcp); 2940 1772 jl139090 } 2941 1772 jl139090 } 2942 1772 jl139090 } 2943 1772 jl139090 mutex_exit(&mcp->mc_lock); 2944 1772 jl139090 2945 1772 jl139090 return (DDI_SUCCESS); 2946 1772 jl139090 } 2947 1772 jl139090 2948 1772 jl139090 static mc_opl_t * 2949 1772 jl139090 mc_pa_to_mcp(uint64_t pa) 2950 1772 jl139090 { 2951 2214 av145390 mc_opl_t *mcp; 2952 2214 av145390 int i; 2953 2214 av145390 2954 1772 jl139090 ASSERT(MUTEX_HELD(&mcmutex)); 2955 2214 av145390 for (i = 0; i < OPL_MAX_BOARDS; i++) { 2956 2214 av145390 if ((mcp = mc_instances[i]) == NULL) 2957 2214 av145390 continue; 2958 1772 jl139090 /* if mac patrol is suspended, we cannot rely on it */ 2959 2214 av145390 if (!(mcp->mc_status & MC_POLL_RUNNING) || 2960 5080 wh31274 (mcp->mc_status & MC_SOFT_SUSPENDED)) 2961 1772 jl139090 continue; 2962 2662 hyw if (mc_rangecheck_pa(mcp, pa)) { 2963 2214 av145390 return (mcp); 2964 1772 jl139090 } 2965 1772 jl139090 } 2966 1772 jl139090 return (NULL); 2967 1772 jl139090 } 2968 1772 jl139090 2969 1772 jl139090 /* 2970 1772 jl139090 * Get Physical Board number from Logical one. 2971 1772 jl139090 */ 2972 1772 jl139090 static int 2973 1772 jl139090 mc_opl_get_physical_board(int sb) 2974 1772 jl139090 { 2975 1772 jl139090 if (&opl_get_physical_board) { 2976 1772 jl139090 return (opl_get_physical_board(sb)); 2977 1772 jl139090 } 2978 1772 jl139090 2979 1772 jl139090 cmn_err(CE_NOTE, "!opl_get_physical_board() not loaded\n"); 2980 1772 jl139090 return (-1); 2981 1772 jl139090 } 2982 1772 jl139090 2983 1772 jl139090 /* ARGSUSED */ 2984 1772 jl139090 int 2985 1772 jl139090 mc_get_mem_unum(int synd_code, uint64_t flt_addr, char *buf, int buflen, 2986 1772 jl139090 int *lenp) 2987 1772 jl139090 { 2988 2214 av145390 int i; 2989 3045 av145390 int j; 2990 2214 av145390 int sb; 2991 2214 av145390 int bank; 2992 3045 av145390 int cs; 2993 6297 jl139090 int rv = 0; 2994 1772 jl139090 mc_opl_t *mcp; 2995 2214 av145390 char memb_num; 2996 1772 jl139090 2997 1772 jl139090 mutex_enter(&mcmutex); 2998 1772 jl139090 2999 1772 jl139090 if (((mcp = mc_pa_to_mcp(flt_addr)) == NULL) || 3000 5080 wh31274 (!pa_is_valid(mcp, flt_addr))) { 3001 1772 jl139090 mutex_exit(&mcmutex); 3002 1772 jl139090 if (snprintf(buf, buflen, "UNKNOWN") >= buflen) { 3003 1772 jl139090 return (ENOSPC); 3004 1772 jl139090 } else { 3005 1772 jl139090 if (lenp) 3006 1772 jl139090 *lenp = strlen(buf); 3007 1772 jl139090 } 3008 1772 jl139090 return (0); 3009 1772 jl139090 } 3010 1772 jl139090 3011 1772 jl139090 bank = pa_to_bank(mcp, flt_addr - mcp->mc_start_address); 3012 3045 av145390 sb = mcp->mc_phys_board_num; 3013 3045 av145390 cs = pa_to_cs(mcp, flt_addr - mcp->mc_start_address); 3014 1772 jl139090 3015 1772 jl139090 if (sb == -1) { 3016 1772 jl139090 mutex_exit(&mcmutex); 3017 1772 jl139090 return (ENXIO); 3018 1772 jl139090 } 3019 1772 jl139090 3020 6297 jl139090 switch (plat_model) { 3021 6297 jl139090 case MODEL_DC: 3022 2214 av145390 i = BD_BK_SLOT_TO_INDEX(0, bank, 0); 3023 3045 av145390 j = (cs == 0) ? i : i + 2; 3024 3045 av145390 snprintf(buf, buflen, "/%s%02d/MEM%s MEM%s", 3025 2214 av145390 model_names[plat_model].unit_name, sb, 3026 3045 av145390 mc_dc_dimm_unum_table[j], 3027 3045 av145390 mc_dc_dimm_unum_table[j + 1]); 3028 6297 jl139090 break; 3029 6297 jl139090 case MODEL_FF2: 3030 6297 jl139090 case MODEL_FF1: 3031 2214 av145390 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0); 3032 3045 av145390 j = (cs == 0) ? i : i + 2; 3033 2214 av145390 memb_num = mc_ff_dimm_unum_table[i][0]; 3034 3045 av145390 snprintf(buf, buflen, "/%s/%s%c/MEM%s MEM%s", 3035 2214 av145390 model_names[plat_model].unit_name, 3036 2214 av145390 model_names[plat_model].mem_name, memb_num, 3037 3045 av145390 &mc_ff_dimm_unum_table[j][1], 3038 3045 av145390 &mc_ff_dimm_unum_table[j + 1][1]); 3039 6297 jl139090 break; 3040 6297 jl139090 case MODEL_IKKAKU: 3041 6297 jl139090 i = BD_BK_SLOT_TO_INDEX(sb, bank, 0); 3042 6297 jl139090 j = (cs == 0) ? i : i + 2; 3043 6297 jl139090 snprintf(buf, buflen, "/%s/MEM%s MEM%s", 3044 6297 jl139090 model_names[plat_model].unit_name, 3045 6297 jl139090 &mc_ff_dimm_unum_table[j][1], 3046 6297 jl139090 &mc_ff_dimm_unum_table[j + 1][1]); 3047 6297 jl139090 break; 3048 6297 jl139090 default: 3049 6297 jl139090 rv = ENXIO; 3050 2214 av145390 } 3051 2214 av145390 if (lenp) { 3052 2214 av145390 *lenp = strlen(buf); 3053 1772 jl139090 } 3054 1772 jl139090 mutex_exit(&mcmutex); 3055 6297 jl139090 return (rv); 3056 1772 jl139090 } 3057 1772 jl139090 3058 1772 jl139090 int 3059 2214 av145390 opl_mc_suspend(void) 3060 1772 jl139090 { 3061 1772 jl139090 mc_opl_t *mcp; 3062 2214 av145390 int i; 3063 1772 jl139090 3064 1772 jl139090 mutex_enter(&mcmutex); 3065 2214 av145390 for (i = 0; i < OPL_MAX_BOARDS; i++) { 3066 2214 av145390 if ((mcp = mc_instances[i]) == NULL) 3067 2214 av145390 continue; 3068 2214 av145390 mc_suspend(mcp, MC_SOFT_SUSPENDED); 3069 2214 av145390 } 3070 2214 av145390 mutex_exit(&mcmutex); 3071 1772 jl139090 3072 1772 jl139090 return (0); 3073 1772 jl139090 } 3074 1772 jl139090 3075