sd: remove 'ssd' driver support
[unleashed/tickless.git] / usr / src / cmd / mdb / i86xpv / modules / xpv_psm / xpv_psm.c
bloba54cbf06230574a38f40e031df3462dc240d0e14
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2013 by Delphix. All rights reserved.
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_ks.h>
31 #include <mdb/mdb_ctf.h>
32 #include <sys/evtchn_impl.h>
33 #include <errno.h>
34 #include <sys/xc_levels.h>
36 #include "intr_common.h"
38 typedef struct mdb_shared_info {
39 unsigned long evtchn_pending[sizeof (unsigned long) * NBBY];
40 unsigned long evtchn_mask[sizeof (unsigned long) * NBBY];
41 } mdb_shared_info_t;
43 static mdb_shared_info_t shared_info;
44 static int have_shared_info;
45 static uintptr_t evtchn_cpus_addr;
46 static struct av_head avec_tbl[NR_IRQS];
47 static irq_info_t irq_tbl[NR_IRQS];
48 static mec_info_t ipi_tbl[MAXIPL];
49 static mec_info_t virq_tbl[NR_VIRQS];
50 static short evtchn_tbl[NR_EVENT_CHANNELS];
51 static apic_irq_t *apic_irq_tbl[APIC_MAX_VECTOR+1];
52 static char level_tbl[APIC_MAX_VECTOR+1];
54 static int
55 update_tables(void)
57 GElf_Sym sym;
58 uintptr_t shared_info_addr;
60 if (mdb_readvar(&irq_tbl, "irq_info") == -1) {
61 mdb_warn("failed to read irq_info");
62 return (0);
65 if (mdb_readvar(&ipi_tbl, "ipi_info") == -1) {
66 mdb_warn("failed to read ipi_info");
67 return (0);
70 if (mdb_readvar(&avec_tbl, "autovect") == -1) {
71 mdb_warn("failed to read autovect");
72 return (0);
75 if (mdb_readvar(&irq_tbl, "irq_info") == -1) {
76 mdb_warn("failed to read irq_info");
77 return (0);
80 if (mdb_readvar(&ipi_tbl, "ipi_info") == -1) {
81 mdb_warn("failed to read ipi_info");
82 return (0);
85 if (mdb_readvar(&virq_tbl, "virq_info") == -1) {
86 mdb_warn("failed to read virq_info");
87 return (0);
90 if (mdb_readvar(&evtchn_tbl, "evtchn_to_irq") == -1) {
91 mdb_warn("failed to read evtchn_to_irq");
92 return (0);
95 if (mdb_readvar(&apic_irq_tbl, "apic_irq_table") == -1) {
96 mdb_warn("failed to read apic_irq_table");
97 return (0);
100 if (mdb_readvar(&level_tbl, "apic_level_intr") == -1) {
101 mdb_warn("failed to read apic_level_intr");
102 return (0);
105 if (mdb_lookup_by_name("evtchn_cpus", &sym) == -1) {
106 mdb_warn("failed to lookup evtchn_cpus");
107 return (0);
110 evtchn_cpus_addr = sym.st_value;
112 if (mdb_readvar(&shared_info_addr, "HYPERVISOR_shared_info") == -1) {
113 mdb_warn("failed to read HYPERVISOR_shared_info");
114 return (0);
118 * It's normal for this to fail with a domain dump.
120 if (mdb_ctf_vread(&shared_info, "shared_info_t", "mdb_shared_info_t",
121 shared_info_addr, MDB_CTF_VREAD_QUIET) != -1)
122 have_shared_info = 1;
124 return (1);
127 static const char *
128 virq_type(int irq)
130 int i;
132 for (i = 0; i < NR_VIRQS; i++) {
133 if (virq_tbl[i].mi_irq == irq)
134 break;
137 switch (i) {
138 case VIRQ_TIMER:
139 return ("virq:timer");
140 case VIRQ_DEBUG:
141 return ("virq:debug");
142 case VIRQ_CONSOLE:
143 return ("virq:console");
144 case VIRQ_DOM_EXC:
145 return ("virq:dom exc");
146 case VIRQ_DEBUGGER:
147 return ("virq:debugger");
148 case VIRQ_MCA:
149 return ("virq:mca");
150 default:
151 break;
154 return ("virq:?");
157 static const char *
158 irq_type(int irq, int extended)
160 switch (irq_tbl[irq].ii_type) {
161 case IRQT_UNBOUND:
162 return ("unset");
163 case IRQT_PIRQ:
164 return ("pirq");
165 case IRQT_VIRQ:
166 if (extended)
167 return (virq_type(irq));
168 return ("virq");
169 case IRQT_IPI:
170 return ("ipi");
171 case IRQT_EVTCHN:
172 return ("evtchn");
173 case IRQT_DEV_EVTCHN:
174 return ("device");
177 return ("?");
181 * We need a non-trivial IPL lookup as the CPU poke's IRQ doesn't have ii_ipl
182 * set -- see evtchn.h.
184 static int
185 irq_ipl(int irq)
187 int i;
189 if (irq_tbl[irq].ii_u2.ipl != 0)
190 return (irq_tbl[irq].ii_u2.ipl);
192 for (i = 0; i < MAXIPL; i++) {
193 if (ipi_tbl[i].mi_irq == irq) {
194 return (i);
198 return (0);
201 static void
202 print_cpu(irq_info_t *irqp, int evtchn)
204 size_t cpuset_size = BT_BITOUL(NCPU) * sizeof (ulong_t);
205 int cpu;
207 if (irqp != NULL) {
208 switch (irqp->ii_type) {
209 case IRQT_VIRQ:
210 case IRQT_IPI:
211 mdb_printf("all ");
212 return;
214 case IRQT_DEV_EVTCHN:
215 mdb_printf("0 ");
216 return;
218 default:
219 break;
223 if (evtchn >= NR_EVENT_CHANNELS || evtchn == 0) {
224 mdb_printf("- ");
225 return;
228 cpu = mdb_cpuset_find(evtchn_cpus_addr +
229 (cpuset_size * evtchn));
232 * XXPV: we should verify this against the CPU's mask and show
233 * something if they don't match.
235 mdb_printf("%-4d", cpu);
238 static void
239 print_isr(int i)
241 if (avec_tbl[i].avh_link != NULL) {
242 struct autovec avhp;
244 (void) mdb_vread(&avhp, sizeof (struct autovec),
245 (uintptr_t)avec_tbl[i].avh_link);
247 interrupt_print_isr((uintptr_t)avhp.av_vector,
248 (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
249 } else if (irq_ipl(i) == XC_CPUPOKE_PIL) {
250 mdb_printf("poke_cpu");
254 static int
255 evtchn_masked(int i)
257 return (!!TEST_EVTCHN_BIT(i, &shared_info.evtchn_mask[0]));
260 static int
261 evtchn_pending(int i)
263 return (!!TEST_EVTCHN_BIT(i, &shared_info.evtchn_pending[0]));
266 typedef struct mdb_xpv_psm_autovec {
267 dev_info_t *av_dip;
268 } mdb_xpv_psm_autovec_t;
270 static void
271 print_bus(int irq)
273 char parent[7];
274 uintptr_t dip_addr;
275 struct dev_info dev_info;
276 mdb_xpv_psm_autovec_t avhp;
278 if (mdb_ctf_vread(&avhp, "struct autovec", "mdb_xpv_psm_autovec_t",
279 (uintptr_t)avec_tbl[irq].avh_link, MDB_CTF_VREAD_QUIET) == -1)
280 goto fail;
282 dip_addr = (uintptr_t)avhp.av_dip;
284 if (dip_addr == (uintptr_t)NULL)
285 goto fail;
288 * Sigh. As a result of the perennial confusion of how you do opaque
289 * handles, dev_info_t has a funny old type, which means we can't use
290 * mdb_ctf_vread() here.
293 if (mdb_vread(&dev_info, sizeof (struct dev_info), dip_addr) == -1)
294 goto fail;
296 dip_addr = (uintptr_t)dev_info.devi_parent;
298 if (mdb_vread(&dev_info, sizeof (struct dev_info), dip_addr) == -1)
299 goto fail;
301 if (mdb_readstr(parent, 7, (uintptr_t)dev_info.devi_node_name) == -1)
302 goto fail;
304 mdb_printf("%-6s ", parent);
305 return;
307 fail:
308 mdb_printf("- ");
311 static void
312 ec_interrupt_dump(int i)
314 irq_info_t *irqp = &irq_tbl[i];
315 char evtchn[8];
317 if (irqp->ii_type == IRQT_UNBOUND)
318 return;
320 if (option_flags & INTR_DISPLAY_INTRSTAT) {
321 print_cpu(irqp, irqp->ii_u.evtchn);
322 print_isr(i);
323 mdb_printf("\n");
324 return;
327 switch (irqp->ii_type) {
328 case IRQT_EVTCHN:
329 case IRQT_VIRQ:
330 if (irqp->ii_u.index == VIRQ_TIMER) {
331 strcpy(evtchn, "T");
332 } else {
333 mdb_snprintf(evtchn, sizeof (evtchn), "%-7d",
334 irqp->ii_u.evtchn);
336 break;
337 case IRQT_IPI:
338 strcpy(evtchn, "I");
339 break;
340 case IRQT_DEV_EVTCHN:
341 strcpy(evtchn, "D");
342 break;
345 /* IRQ */
346 mdb_printf("%3d ", i);
347 /* Vector */
348 mdb_printf("- ");
349 /* Evtchn */
350 mdb_printf("%-7s", evtchn);
351 /* IPL */
352 mdb_printf("%-4d", irq_ipl(i));
353 /* Bus */
354 print_bus(i);
355 /* Trigger */
356 mdb_printf("%-4s", "Edg");
357 /* Type */
358 mdb_printf("%-7s", irq_type(i, 0));
359 /* CPU */
360 print_cpu(irqp, irqp->ii_u.evtchn);
361 /* Share */
362 mdb_printf("- ");
363 /* APIC/INT# */
364 mdb_printf("- ");
366 print_isr(i);
368 mdb_printf("\n");
371 /* ARGSUSED */
372 static int
373 interrupts_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
375 int i;
377 option_flags = 0;
378 if (mdb_getopts(argc, argv,
379 'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
380 'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags,
381 NULL) != argc)
382 return (DCMD_USAGE);
384 if (!update_tables())
385 return (DCMD_ERR);
387 if (option_flags & INTR_DISPLAY_INTRSTAT) {
388 mdb_printf("%<u>CPU ");
389 } else {
390 mdb_printf("%<u>IRQ Vect Evtchn IPL Bus Trg Type "
391 "CPU Share APIC/INT# ");
393 mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
394 "Driver Name(s)" : "ISR(s)");
396 for (i = 0; i < NR_IRQS; i++) {
397 if (irq_tbl[i].ii_type == IRQT_PIRQ) {
398 apic_irq_t airq;
400 if (irq_tbl[i].ii_u.evtchn == 0)
401 continue;
403 if (mdb_vread(&airq, sizeof (apic_irq_t),
404 (uintptr_t)apic_irq_tbl[i]) == -1)
405 continue;
407 apic_interrupt_dump(&airq, &avec_tbl[i], i,
408 &irq_tbl[i].ii_u.evtchn, level_tbl[i]);
409 continue;
412 ec_interrupt_dump(i);
415 return (DCMD_OK);
418 static void
419 evtchn_dump(int i)
421 int irq = evtchn_tbl[i];
423 if (irq == INVALID_IRQ) {
424 mdb_printf("%-14s%-7d%-4s%-4s", "unassigned", i, "-", "-");
425 print_cpu(NULL, i);
426 if (have_shared_info) {
427 mdb_printf("%-7d", evtchn_masked(i));
428 mdb_printf("%-8d", evtchn_pending(i));
430 mdb_printf("\n");
431 return;
434 /* Type */
435 mdb_printf("%-14s", irq_type(irq, 1));
436 /* Evtchn */
437 mdb_printf("%-7d", i);
438 /* IRQ */
439 mdb_printf("%-4d", irq);
440 /* IPL */
441 mdb_printf("%-4d", irq_ipl(irq));
442 /* CPU */
443 print_cpu(NULL, i);
444 if (have_shared_info) {
445 /* Masked/Pending */
446 mdb_printf("%-7d", evtchn_masked(i));
447 mdb_printf("%-8d", evtchn_pending(i));
449 /* ISR */
450 print_isr(irq);
452 mdb_printf("\n");
455 /* ARGSUSED */
456 static int
457 evtchns_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
459 int i;
461 option_flags = 0;
462 if (mdb_getopts(argc, argv,
463 'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
464 NULL) != argc)
465 return (DCMD_USAGE);
467 if (!update_tables())
468 return (DCMD_ERR);
470 if (flags & DCMD_ADDRSPEC) {
472 * Note: we allow the invalid evtchn 0, as it can help catch if
473 * we incorrectly try to configure it.
475 if ((int)addr >= NR_EVENT_CHANNELS) {
476 mdb_warn("Invalid event channel %d.\n", (int)addr);
477 return (DCMD_ERR);
481 mdb_printf("%<u>Type Evtchn IRQ IPL CPU ");
482 if (have_shared_info)
483 mdb_printf("Masked Pending ");
485 mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
486 "Driver Name(s)" : "ISR(s)");
488 if (flags & DCMD_ADDRSPEC) {
489 evtchn_dump((int)addr);
490 return (DCMD_OK);
493 for (i = 0; i < NR_EVENT_CHANNELS; i++) {
494 if (evtchn_tbl[i] == INVALID_IRQ)
495 continue;
497 evtchn_dump(i);
500 return (DCMD_OK);
503 static void
504 evtchns_help(void)
506 mdb_printf("Print valid event channels\n"
507 "If %<u>addr%</u> is given, interpret it as an evtchn to print "
508 "details of.\n"
509 "By default, only interrupt service routine names are printed.\n\n"
510 "Switches:\n"
511 " -d instead of ISR, print <driver_name><instance#>\n");
514 static const mdb_dcmd_t dcmds[] = {
515 { "interrupts", "?[-di]", "print interrupts", interrupts_dump,
516 interrupt_help },
517 { "evtchns", "?[-d]", "print event channels", evtchns_dump,
518 evtchns_help },
519 { "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump,
520 soft_interrupt_help},
521 { NULL }
524 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL };
526 const mdb_modinfo_t *
527 _mdb_init(void)
529 GElf_Sym sym;
531 if (mdb_lookup_by_name("gld_intr", &sym) != -1)
532 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
533 gld_intr_addr = (uintptr_t)sym.st_value;
535 return (&modinfo);