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