1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <mdb/mdb_modapi.h> 28 #include <generic_cpu/gcpu.h> 29 #include <sys/cpu_module_impl.h> 30 #include <sys/cpu_module_ms_impl.h> 31 32 typedef struct cmi_hdl_impl { 33 enum cmi_hdl_class cmih_class; /* Handle nature */ 34 struct cmi_hdl_ops *cmih_ops; /* Operations vector */ 35 uint_t cmih_chipid; /* Chipid of cpu resource */ 36 uint_t cmih_procnodeid; /* Nodeid of cpu resource */ 37 uint_t cmih_coreid; /* Core within die */ 38 uint_t cmih_strandid; /* Thread within core */ 39 uint_t cmih_procnodes_per_pkg; /* Nodes in a processor */ 40 boolean_t cmih_mstrand; /* cores are multithreaded */ 41 volatile uint32_t *cmih_refcntp; /* Reference count pointer */ 42 uint64_t cmih_msrsrc; /* MSR data source flags */ 43 void *cmih_hdlpriv; /* cmi_hw.c private data */ 44 void *cmih_spec; /* cmi_hdl_{set,get}_specific */ 45 void *cmih_cmi; /* cpu mod control structure */ 46 void *cmih_cmidata; /* cpu mod private data */ 47 const struct cmi_mc_ops *cmih_mcops; /* Memory-controller ops */ 48 void *cmih_mcdata; /* Memory-controller data */ 49 uint64_t cmih_flags; 50 uint16_t cmih_smbiosid; /* SMBIOS Type 4 struct ID */ 51 uint_t cmih_smb_chipid; /* smbios chipid */ 52 nvlist_t *cmih_smb_bboard; /* smbios bboard */ 53 } cmi_hdl_impl_t; 54 55 typedef struct cmi_hdl_ent { 56 volatile uint32_t cmae_refcnt; 57 cmi_hdl_impl_t *cmae_hdlp; 58 } cmi_hdl_ent_t; 59 60 typedef struct cmi { 61 struct cmi *cmi_next; 62 struct cmi *cmi_prev; 63 const cmi_ops_t *cmi_ops; 64 struct modctl *cmi_modp; 65 uint_t cmi_refcnt; 66 } cmi_t; 67 68 typedef struct cms { 69 struct cms *cms_next; 70 struct cms *cms_prev; 71 const cms_ops_t *cms_ops; 72 struct modctl *cms_modp; 73 uint_t cms_refcnt; 74 } cms_t; 75 76 struct cms_ctl { 77 cms_t *cs_cms; 78 void *cs_cmsdata; 79 }; 80 81 #define CMI_MAX_CHIPID_NBITS 6 /* max chipid of 63 */ 82 #define CMI_MAX_CORES_PER_CHIP_NBITS 4 /* 16 cores per chip max */ 83 #define CMI_MAX_STRANDS_PER_CORE_NBITS 3 /* 8 strands per core max */ 84 85 #define CMI_MAX_CHIPID ((1 << (CMI_MAX_CHIPID_NBITS)) - 1) 86 #define CMI_MAX_CORES_PER_CHIP (1 << CMI_MAX_CORES_PER_CHIP_NBITS) 87 #define CMI_MAX_STRANDS_PER_CORE (1 << CMI_MAX_STRANDS_PER_CORE_NBITS) 88 #define CMI_MAX_STRANDS_PER_CHIP (CMI_MAX_CORES_PER_CHIP * \ 89 CMI_MAX_STRANDS_PER_CORE) 90 91 #define CMI_HDL_ARR_IDX_CORE(coreid) \ 92 (((coreid) & (CMI_MAX_CORES_PER_CHIP - 1)) << \ 93 CMI_MAX_STRANDS_PER_CORE_NBITS) 94 95 #define CMI_HDL_ARR_IDX_STRAND(strandid) \ 96 (((strandid) & (CMI_MAX_STRANDS_PER_CORE - 1))) 97 98 #define CMI_HDL_ARR_IDX(coreid, strandid) \ 99 (CMI_HDL_ARR_IDX_CORE(coreid) | CMI_HDL_ARR_IDX_STRAND(strandid)) 100 101 #define CMI_CHIPID_ARR_SZ (1 << CMI_MAX_CHIPID_NBITS) 102 103 struct cmih_walk_state { 104 int chipid, coreid, strandid; /* currently visited cpu */ 105 cmi_hdl_ent_t *chip_tab[CMI_CHIPID_ARR_SZ]; 106 }; 107 108 /* 109 * Advance the <chipid,coreid,strandid> tuple to the next strand entry 110 * Return true upon sucessful result. Otherwise return false if already reach 111 * the highest strand. 112 */ 113 static boolean_t 114 cmih_ent_next(struct cmih_walk_state *wsp) 115 { 116 uint_t carry = 0; 117 118 /* Check for end of the table */ 119 if (wsp->chipid == CMI_MAX_CHIPID && 120 wsp->coreid == (CMI_MAX_CORES_PER_CHIP - 1) && 121 wsp->strandid == (CMI_MAX_STRANDS_PER_CORE - 1)) 122 return (B_FALSE); 123 124 /* increment the strand id */ 125 wsp->strandid++; 126 carry = wsp->strandid >> CMI_MAX_STRANDS_PER_CORE_NBITS; 127 wsp->strandid = wsp->strandid & (CMI_MAX_STRANDS_PER_CORE - 1); 128 if (carry == 0) 129 return (B_TRUE); 130 131 /* increment the core id */ 132 wsp->coreid++; 133 carry = wsp->coreid >> CMI_MAX_CORES_PER_CHIP_NBITS; 134 wsp->coreid = wsp->coreid & (CMI_MAX_CORES_PER_CHIP - 1); 135 if (carry == 0) 136 return (B_TRUE); 137 138 /* increment the chip id */ 139 wsp->chipid = ++wsp->chipid & (CMI_MAX_CHIPID); 140 141 return (B_TRUE); 142 } 143 144 /* 145 * Lookup for the hdl entry of a given <chip,core,strand> 146 */ 147 static cmi_hdl_ent_t * 148 cmih_ent_lookup(struct cmih_walk_state *wsp) 149 { 150 if (wsp == NULL || wsp->chip_tab[wsp->chipid] == NULL) 151 return (NULL); /* chip is not present */ 152 153 return (wsp->chip_tab[wsp->chipid] + 154 CMI_HDL_ARR_IDX(wsp->coreid, wsp->strandid)); 155 } 156 157 /* forward decls */ 158 static void 159 cmih_walk_fini(mdb_walk_state_t *wsp); 160 161 static int 162 cmih_walk_init(mdb_walk_state_t *wsp) 163 { 164 int i; 165 ssize_t sz; 166 struct cmih_walk_state *awsp; 167 void *pg; 168 cmi_hdl_ent_t *ent; 169 170 if (wsp->walk_addr != NULL) { 171 mdb_warn("cmihdl is a global walker\n"); 172 return (WALK_ERR); 173 } 174 175 wsp->walk_data = awsp = 176 mdb_zalloc(sizeof (struct cmih_walk_state), UM_SLEEP); 177 178 /* table of chipid entries */ 179 if ((sz = mdb_readvar(&awsp->chip_tab, "cmi_chip_tab")) == -1) { 180 mdb_warn("read of cmi_chip_tab failed"); 181 mdb_free(wsp->walk_data, sizeof (struct cmih_walk_state)); 182 wsp->walk_data = NULL; 183 return (WALK_ERR); 184 } else if (sz < sizeof (awsp->chip_tab)) { 185 mdb_warn("Unexpected cmi_chip_tab size (exp=%ld, actual=%ld)", 186 sizeof (awsp->chip_tab), sz); 187 mdb_free(wsp->walk_data, sizeof (struct cmih_walk_state)); 188 wsp->walk_data = NULL; 189 return (WALK_ERR); 190 } 191 192 /* read the per-chip table that contains all strands of the chip */ 193 sz = CMI_MAX_STRANDS_PER_CHIP * sizeof (cmi_hdl_ent_t); 194 for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) { 195 if (awsp->chip_tab[i] == NULL) 196 continue; /* this chip(i) is not present */ 197 pg = mdb_alloc(sz, UM_SLEEP); 198 if (mdb_vread(pg, sz, (uintptr_t)awsp->chip_tab[i]) != sz) { 199 mdb_warn("read of cmi_hdl(%i) array at 0x%p failed", 200 i, awsp->chip_tab[i]); 201 mdb_free(pg, sz); 202 cmih_walk_fini(wsp); 203 return (WALK_ERR); 204 } 205 awsp->chip_tab[i] = pg; 206 } 207 208 /* Look up the hdl of the first strand <0,0,0> */ 209 wsp->walk_addr = NULL; 210 if ((ent = cmih_ent_lookup(awsp)) != NULL) 211 wsp->walk_addr = (uintptr_t)ent->cmae_hdlp; 212 213 return (WALK_NEXT); 214 } 215 216 static int 217 cmih_walk_step(mdb_walk_state_t *wsp) 218 { 219 struct cmih_walk_state *awsp = wsp->walk_data; 220 uintptr_t addr = NULL; 221 cmi_hdl_impl_t hdl; 222 cmi_hdl_ent_t *ent; 223 int rv; 224 225 if ((ent = cmih_ent_lookup(awsp)) != NULL) 226 addr = (uintptr_t)ent->cmae_hdlp; 227 if (wsp->walk_addr == NULL || addr == NULL) 228 return (cmih_ent_next(awsp) ? WALK_NEXT : WALK_DONE); 229 230 if (mdb_vread(&hdl, sizeof (hdl), addr) != sizeof (hdl)) { 231 mdb_warn("read of handle at 0x%p failed", addr); 232 return (WALK_DONE); 233 } 234 235 if ((rv = wsp->walk_callback(addr, (void *)&hdl, 236 wsp->walk_cbdata)) != WALK_NEXT) 237 return (rv); 238 239 return (cmih_ent_next(awsp) ? WALK_NEXT : WALK_DONE); 240 } 241 242 static void 243 cmih_walk_fini(mdb_walk_state_t *wsp) 244 { 245 struct cmih_walk_state *awsp = wsp->walk_data; 246 247 if (awsp != NULL) { 248 int i; 249 for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) { 250 /* free the per-chip table */ 251 if (awsp->chip_tab[i] != NULL) { 252 mdb_free((void *)awsp->chip_tab[i], 253 CMI_MAX_STRANDS_PER_CHIP * 254 sizeof (cmi_hdl_ent_t)); 255 awsp->chip_tab[i] = NULL; 256 } 257 } 258 mdb_free(wsp->walk_data, sizeof (struct cmih_walk_state)); 259 wsp->walk_data = NULL; 260 } 261 } 262 263 struct cmihdl_cb { 264 int mod_cpuid; 265 int mod_chipid; 266 int mod_coreid; 267 int mod_strandid; 268 uintptr_t mod_hdladdr; 269 }; 270 271 static int 272 cmihdl_cb(uintptr_t addr, const void *arg, void *data) 273 { 274 cmi_hdl_impl_t *hdl = (cmi_hdl_impl_t *)arg; 275 struct cmihdl_cb *cbp = data; 276 cpu_t *cp; 277 int rv; 278 279 if (cbp->mod_cpuid != -1) { 280 cp = mdb_alloc(sizeof (cpu_t), UM_SLEEP); 281 if (mdb_vread(cp, sizeof (cpu_t), 282 (uintptr_t)hdl->cmih_hdlpriv) != sizeof (cpu_t)) { 283 mdb_warn("Read of cpu_t at 0x%p failed", 284 hdl->cmih_hdlpriv); 285 mdb_free(cp, sizeof (cpu_t)); 286 return (WALK_ERR); 287 } 288 289 if (cp->cpu_id == cbp->mod_cpuid) { 290 cbp->mod_hdladdr = addr; 291 rv = WALK_DONE; 292 } else { 293 rv = WALK_NEXT; 294 } 295 296 mdb_free(cp, sizeof (cpu_t)); 297 return (rv); 298 } else { 299 if (hdl->cmih_chipid == cbp->mod_chipid && 300 hdl->cmih_coreid == cbp->mod_coreid && 301 hdl->cmih_strandid == cbp->mod_strandid) { 302 cbp->mod_hdladdr = addr; 303 return (WALK_DONE); 304 } else { 305 return (WALK_NEXT); 306 } 307 } 308 } 309 310 static int 311 cmihdl_disp(uintptr_t addr, cmi_hdl_impl_t *hdl) 312 { 313 struct cms_ctl cmsctl; /* 16 bytes max */ 314 struct modctl cmimodc, cmsmodc; /* 288 bytes max */ 315 cmi_t cmi; /* 40 bytes max */ 316 cms_t cms; /* 40 bytes max */ 317 cpu_t *cp; 318 char cmimodnm[25], cmsmodnm[25]; /* 50 bytes */ 319 char cpuidstr[4], hwidstr[16]; 320 int native = hdl->cmih_class == CMI_HDL_NATIVE; 321 uint32_t refcnt; 322 323 cmimodnm[0] = cmsmodnm[0] = '-'; 324 cmimodnm[1] = cmsmodnm[1] = '\0'; 325 326 if (hdl->cmih_cmi != NULL) { 327 if (mdb_vread(&cmi, sizeof (cmi_t), 328 (uintptr_t)hdl->cmih_cmi) != sizeof (cmi)) { 329 mdb_warn("Read of cmi_t at 0x%p failed", 330 hdl->cmih_cmi); 331 return (0); 332 } 333 334 if (cmi.cmi_modp != NULL) { 335 if (mdb_vread(&cmimodc, sizeof (struct modctl), 336 (uintptr_t)cmi.cmi_modp) != sizeof (cmimodc)) { 337 mdb_warn("Read of modctl at 0x%p failed", 338 cmi.cmi_modp); 339 return (0); 340 } 341 342 if (mdb_readstr(cmimodnm, sizeof (cmimodnm), 343 (uintptr_t)cmimodc.mod_modname) == -1) { 344 mdb_warn("Read of cmi module name at 0x%p " 345 "failed", cmimodc.mod_modname); 346 return (0); 347 } 348 } 349 } 350 351 if (hdl->cmih_spec != NULL) { 352 if (mdb_vread(&cmsctl, sizeof (struct cms_ctl), 353 (uintptr_t)hdl->cmih_spec) != sizeof (cmsctl)) { 354 mdb_warn("Read of struct cms_ctl at 0x%p failed", 355 hdl->cmih_spec); 356 return (0); 357 } 358 359 if (mdb_vread(&cms, sizeof (cms_t), 360 (uintptr_t)cmsctl.cs_cms) != sizeof (cms)) { 361 mdb_warn("Read of cms_t at 0x%p failed", cmsctl.cs_cms); 362 return (0); 363 } 364 365 if (cms.cms_modp != NULL) { 366 if (mdb_vread(&cmsmodc, sizeof (struct modctl), 367 (uintptr_t)cms.cms_modp) != sizeof (cmsmodc)) { 368 mdb_warn("Read of modctl at 0x%p failed", 369 cms.cms_modp); 370 return (0); 371 } 372 373 if (mdb_readstr(cmsmodnm, sizeof (cmsmodnm), 374 (uintptr_t)cmsmodc.mod_modname) == -1) { 375 mdb_warn("Read of cms module name at 0x%p " 376 "failed", cmsmodc.mod_modname); 377 return (0); 378 } 379 } 380 } 381 382 if (mdb_vread(&refcnt, sizeof (uint32_t), 383 (uintptr_t)hdl->cmih_refcntp) != sizeof (uint32_t)) { 384 mdb_warn("Read of reference count for hdl 0x%p failed", hdl); 385 return (0); 386 } 387 388 if (native) { 389 cp = mdb_alloc(sizeof (cpu_t), UM_SLEEP); 390 391 if (mdb_vread(cp, sizeof (cpu_t), 392 (uintptr_t)hdl->cmih_hdlpriv) != sizeof (cpu_t)) { 393 mdb_free(cp, sizeof (cpu_t)); 394 mdb_warn("Read of cpu_t at 0x%p failed", 395 hdl->cmih_hdlpriv); 396 return (0); 397 } 398 } 399 400 if (native) { 401 (void) mdb_snprintf(cpuidstr, sizeof (cpuidstr), "%d", 402 cp->cpu_id); 403 } else { 404 (void) mdb_snprintf(cpuidstr, sizeof (cpuidstr), "-"); 405 } 406 407 (void) mdb_snprintf(hwidstr, sizeof (hwidstr), "%d/%d/%d", 408 hdl->cmih_chipid, hdl->cmih_coreid, hdl->cmih_strandid); 409 410 mdb_printf("%16lx %3d %3s %8s %3s %2s %-13s %-24s\n", addr, 411 refcnt, cpuidstr, hwidstr, hdl->cmih_mstrand ? "M" : "S", 412 hdl->cmih_mcops ? "Y" : "N", cmimodnm, cmsmodnm); 413 414 if (native) 415 mdb_free(cp, sizeof (cpu_t)); 416 417 return (1); 418 } 419 420 #define HDRFMT "%-16s %3s %3s %8s %3s %2s %-13s %-24s\n" 421 422 static int 423 cmihdl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 424 { 425 struct cmihdl_cb cb; 426 cmi_hdl_impl_t *hdl; 427 428 /* 429 * If an address is given it must be that of a cmi handle. 430 * Otherwise if the user has specified -c <cpuid> or 431 * -c <chipid/coreid/strandid> we will lookup a matching handle. 432 * Otherwise we'll walk and callback to this dcmd. 433 */ 434 if (!(flags & DCMD_ADDRSPEC)) { 435 char *p, *buf; 436 int len; 437 438 if (argc == 0) 439 return (mdb_walk_dcmd("cmihdl", "cmihdl", argc, 440 argv) == 0 ? DCMD_OK : DCMD_ERR); 441 442 443 if (mdb_getopts(argc, argv, 444 'c', MDB_OPT_STR, &p, 445 NULL) != argc) 446 return (DCMD_USAGE); 447 448 if ((len = strlen(p)) == 0) { 449 return (DCMD_USAGE); 450 } else { 451 buf = mdb_alloc(len + 1, UM_SLEEP); 452 strcpy(buf, p); 453 } 454 455 cb.mod_cpuid = cb.mod_chipid = cb.mod_coreid = 456 cb.mod_strandid = -1; 457 458 if ((p = strchr(buf, '/')) == NULL) { 459 /* Native cpuid */ 460 cb.mod_cpuid = (int)mdb_strtoull(buf); 461 } else { 462 /* Comma-separated triplet chip,core,strand. */ 463 char *q = buf; 464 465 *p = '\0'; 466 cb.mod_chipid = (int)mdb_strtoull(q); 467 468 if ((q = p + 1) >= buf + len || 469 (p = strchr(q, '/')) == NULL) { 470 mdb_free(buf, len); 471 return (DCMD_USAGE); 472 } 473 474 *p = '\0'; 475 cb.mod_coreid = (int)mdb_strtoull(q); 476 477 if ((q = p + 1) >= buf + len) { 478 mdb_free(buf, len); 479 return (DCMD_USAGE); 480 } 481 482 cb.mod_strandid = (int)mdb_strtoull(q); 483 } 484 485 mdb_free(buf, len); 486 487 cb.mod_hdladdr = NULL; 488 if (mdb_walk("cmihdl", cmihdl_cb, &cb) == -1) { 489 mdb_warn("cmi_hdl walk failed\n"); 490 return (DCMD_ERR); 491 } 492 493 if (cb.mod_hdladdr == NULL) { 494 if (cb.mod_cpuid != -1) { 495 mdb_warn("No handle found for cpuid %d\n", 496 cb.mod_cpuid); 497 } else { 498 499 mdb_warn("No handle found for chip %d " 500 "core %d strand %d\n", cb.mod_chipid, 501 cb.mod_coreid, cb.mod_strandid); 502 } 503 return (DCMD_ERR); 504 } 505 506 addr = cb.mod_hdladdr; 507 } 508 509 if (DCMD_HDRSPEC(flags)) { 510 char ul[] = "----------------------------"; 511 char *p = ul + sizeof (ul) - 1; 512 513 mdb_printf(HDRFMT HDRFMT, 514 "HANDLE", "REF", "CPU", "CH/CR/ST", "CMT", "MC", 515 "MODULE", "MODEL-SPECIFIC", 516 p - 16, p - 3, p - 3, p - 8, p - 3, p - 2, p - 13, p - 24); 517 } 518 519 hdl = mdb_alloc(sizeof (cmi_hdl_impl_t), UM_SLEEP); 520 521 if (mdb_vread(hdl, sizeof (cmi_hdl_impl_t), addr) != 522 sizeof (cmi_hdl_impl_t)) { 523 mdb_free(hdl, sizeof (cmi_hdl_impl_t)); 524 mdb_warn("Read of cmi handle at 0x%p failed", addr); 525 return (DCMD_ERR); 526 } 527 528 if (!cmihdl_disp(addr, hdl)) { 529 mdb_free(hdl, sizeof (cmi_hdl_impl_t)); 530 return (DCMD_ERR); 531 } 532 533 mdb_free(hdl, sizeof (cmi_hdl_impl_t)); 534 535 return (DCMD_OK); 536 } 537 538 /*ARGSUSED*/ 539 static int 540 gcpu_mpt_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 541 { 542 static const char *const whatstrs[] = { 543 "ntv-cyc-poll", /* GCPU_MPT_WHAT_CYC_ERR */ 544 "poll-poked", /* GCPU_MPT_WHAT_POKE_ERR */ 545 "unfaulting", /* GCPU_MPT_WHAT_UNFAULTING */ 546 "#MC", /* GCPU_MPT_WHAT_MC_ERR */ 547 "CMCI-int", /* GCPU_MPT_WHAT_CMCI_ERR */ 548 "xpv-virq-nrec", /* GCPU_MPT_WHAT_XPV_VIRQ */ 549 "xpv-virq-lgout", /* GCPU_MPT_WHAT_XPV_VIRQ_LOGOUT */ 550 }; 551 552 gcpu_poll_trace_t mpt; 553 const char *what; 554 555 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 556 return (DCMD_USAGE); 557 558 if (mdb_vread(&mpt, sizeof (mpt), addr) != sizeof (mpt)) { 559 mdb_warn("failed to read gcpu_poll_trace_t at 0x%p", addr); 560 return (DCMD_ERR); 561 } 562 563 if (DCMD_HDRSPEC(flags)) { 564 mdb_printf("%<u>%?s%</u> %<u>%?s%</u> %<u>%15s%</u> " 565 "%<u>%4s%</u>\n", "ADDR", "WHEN", "WHAT", "NERR"); 566 } 567 568 if (mpt.mpt_what < sizeof (whatstrs) / sizeof (char *)) 569 what = whatstrs[mpt.mpt_what]; 570 else 571 what = "???"; 572 573 mdb_printf("%?p %?p %15s %4u\n", addr, mpt.mpt_when, what, 574 mpt.mpt_nerr); 575 576 return (DCMD_OK); 577 } 578 579 typedef struct mptwalk_data { 580 uintptr_t mw_traceaddr; 581 gcpu_poll_trace_t *mw_trace; 582 size_t mw_tracesz; 583 uint_t mw_tracenent; 584 uint_t mw_curtrace; 585 } mptwalk_data_t; 586 587 static int 588 gcpu_mptwalk_init(mdb_walk_state_t *wsp) 589 { 590 gcpu_poll_trace_t *mpt; 591 mptwalk_data_t *mw; 592 GElf_Sym sym; 593 uint_t nent, i; 594 hrtime_t latest; 595 596 if (wsp->walk_addr == NULL) { 597 mdb_warn("the address of a poll trace array must be " 598 "specified\n"); 599 return (WALK_ERR); 600 } 601 602 if (mdb_lookup_by_name("gcpu_poll_trace_nent", &sym) < 0 || 603 sym.st_size != sizeof (uint_t) || mdb_vread(&nent, sizeof (uint_t), 604 sym.st_value) != sizeof (uint_t)) { 605 mdb_warn("failed to read gcpu_poll_trace_nent from kernel"); 606 return (WALK_ERR); 607 } 608 609 mw = mdb_alloc(sizeof (mptwalk_data_t), UM_SLEEP); 610 mw->mw_traceaddr = wsp->walk_addr; 611 mw->mw_tracenent = nent; 612 mw->mw_tracesz = nent * sizeof (gcpu_poll_trace_t); 613 mw->mw_trace = mdb_alloc(mw->mw_tracesz, UM_SLEEP); 614 615 if (mdb_vread(mw->mw_trace, mw->mw_tracesz, wsp->walk_addr) != 616 mw->mw_tracesz) { 617 mdb_free(mw->mw_trace, mw->mw_tracesz); 618 mdb_free(mw, sizeof (mptwalk_data_t)); 619 mdb_warn("failed to read poll trace array from kernel"); 620 return (WALK_ERR); 621 } 622 623 latest = 0; 624 mw->mw_curtrace = 0; 625 for (mpt = mw->mw_trace, i = 0; i < mw->mw_tracenent; i++, mpt++) { 626 if (mpt->mpt_when > latest) { 627 latest = mpt->mpt_when; 628 mw->mw_curtrace = i; 629 } 630 } 631 632 if (latest == 0) { 633 mdb_free(mw->mw_trace, mw->mw_tracesz); 634 mdb_free(mw, sizeof (mptwalk_data_t)); 635 return (WALK_DONE); /* trace array is empty */ 636 } 637 638 wsp->walk_data = mw; 639 640 return (WALK_NEXT); 641 } 642 643 static int 644 gcpu_mptwalk_step(mdb_walk_state_t *wsp) 645 { 646 mptwalk_data_t *mw = wsp->walk_data; 647 gcpu_poll_trace_t *thismpt, *prevmpt; 648 int prev, rv; 649 650 thismpt = &mw->mw_trace[mw->mw_curtrace]; 651 652 rv = wsp->walk_callback(mw->mw_traceaddr + (mw->mw_curtrace * 653 sizeof (gcpu_poll_trace_t)), thismpt, wsp->walk_cbdata); 654 655 if (rv != WALK_NEXT) 656 return (rv); 657 658 prev = (mw->mw_curtrace - 1) % mw->mw_tracenent; 659 prevmpt = &mw->mw_trace[prev]; 660 661 if (prevmpt->mpt_when == 0 || prevmpt->mpt_when > thismpt->mpt_when) 662 return (WALK_DONE); 663 664 mw->mw_curtrace = prev; 665 666 return (WALK_NEXT); 667 } 668 669 static void 670 gcpu_mptwalk_fini(mdb_walk_state_t *wsp) 671 { 672 mptwalk_data_t *mw = wsp->walk_data; 673 674 mdb_free(mw->mw_trace, mw->mw_tracesz); 675 mdb_free(mw, sizeof (mptwalk_data_t)); 676 } 677 678 static const mdb_dcmd_t dcmds[] = { 679 { "cmihdl", ": -c <cpuid>|<chip,core,strand> ", 680 "dump a cmi_handle_t", cmihdl }, 681 { "gcpu_poll_trace", ":", "dump a poll trace buffer", gcpu_mpt_dump }, 682 { NULL } 683 }; 684 685 static const mdb_walker_t walkers[] = { 686 { "cmihdl", "walks cpu module interface handle list", 687 cmih_walk_init, cmih_walk_step, cmih_walk_fini, NULL }, 688 { "gcpu_poll_trace", "walks poll trace buffers in reverse " 689 "chronological order", gcpu_mptwalk_init, gcpu_mptwalk_step, 690 gcpu_mptwalk_fini, NULL }, 691 { NULL } 692 }; 693 694 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 695 696 const mdb_modinfo_t * 697 _mdb_init(void) 698 { 699 return (&modinfo); 700 } 701