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