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