sd: remove 'ssd' driver support
[unleashed/tickless.git] / usr / src / cmd / mdb / i86xpv / modules / xpv_uppc / xpv_uppc.c
blobf5b41442850455df9bc631bb1e8c602dd642a2b9
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 2008 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>
34 #include "intr_common.h"
36 typedef struct mdb_shared_info {
37 unsigned long evtchn_pending[sizeof (unsigned long) * NBBY];
38 unsigned long evtchn_mask[sizeof (unsigned long) * NBBY];
39 } mdb_shared_info_t;
41 static mdb_shared_info_t shared_info;
42 static struct av_head avec_tbl[NR_IRQS];
43 static uint16_t shared_tbl[MAX_ISA_IRQ + 1];
44 static irq_info_t irq_tbl[NR_IRQS];
45 static mec_info_t virq_tbl[NR_VIRQS];
46 static short evtchn_tbl[NR_EVENT_CHANNELS];
48 static int
49 update_tables(void)
51 uintptr_t shared_info_addr;
53 if (mdb_readvar(&irq_tbl, "irq_info") == -1) {
54 mdb_warn("failed to read irq_info");
55 return (0);
58 if (mdb_readvar(&virq_tbl, "virq_info") == -1) {
59 mdb_warn("failed to read virq_info");
60 return (0);
63 if (mdb_readvar(&evtchn_tbl, "evtchn_to_irq") == -1) {
64 mdb_warn("failed to read evtchn_to_irq");
65 return (0);
68 if (mdb_readvar(&avec_tbl, "autovect") == -1) {
69 mdb_warn("failed to read autovect");
70 return (0);
73 if (mdb_readvar(&shared_tbl, "xen_uppc_irq_shared_table") == -1) {
74 mdb_warn("failed to read xen_uppc_irq_shared_table");
75 return (0);
78 if (mdb_readvar(&shared_info_addr, "HYPERVISOR_shared_info") == -1) {
79 mdb_warn("failed to read HYPERVISOR_shared_info");
80 return (0);
83 if (mdb_ctf_vread(&shared_info, "shared_info_t", "mdb_shared_info_t",
84 shared_info_addr, 0) == -1)
85 return (0);
87 return (1);
91 static char *
92 interrupt_print_bus(uintptr_t dip_addr)
94 char bind_name[MAXPATHLEN + 1];
95 struct dev_info dev_info;
97 if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) {
98 mdb_warn("failed to read child dip");
99 return ("-");
102 while (dev_info.devi_parent != 0) {
103 if (mdb_vread(&dev_info, sizeof (dev_info),
104 (uintptr_t)dev_info.devi_parent) == -1)
105 break;
107 (void) mdb_readstr(bind_name, sizeof (bind_name),
108 (uintptr_t)dev_info.devi_binding_name);
109 if (strcmp(bind_name, "isa") == 0)
110 return ("ISA");
111 else if (strcmp(bind_name, "pci") == 0 ||
112 strcmp(bind_name, "npe") == 0)
113 return ("PCI");
115 return ("-");
118 static const char *
119 virq_type(int irq)
121 int i;
123 for (i = 0; i < NR_VIRQS; i++) {
124 if (virq_tbl[i].mi_irq == irq)
125 break;
128 switch (i) {
129 case VIRQ_TIMER:
130 return ("virq:timer");
131 case VIRQ_DEBUG:
132 return ("virq:debug");
133 case VIRQ_CONSOLE:
134 return ("virq:console");
135 case VIRQ_DOM_EXC:
136 return ("virq:dom exc");
137 case VIRQ_DEBUGGER:
138 return ("virq:debugger");
139 default:
140 break;
143 return ("virq:?");
146 static const char *
147 irq_type(int irq, int extended)
149 switch (irq_tbl[irq].ii_type) {
150 case IRQT_UNBOUND:
151 return ("unset");
152 case IRQT_PIRQ:
153 return ("pirq");
154 case IRQT_VIRQ:
155 if (extended)
156 return (virq_type(irq));
157 return ("virq");
158 case IRQT_IPI:
159 return ("ipi");
160 case IRQT_EVTCHN:
161 return ("evtchn");
162 case IRQT_DEV_EVTCHN:
163 return ("device");
166 return ("?");
169 static void
170 print_isr(int i)
172 struct autovec avhp;
174 if (avec_tbl[i].avh_link == NULL)
175 return;
177 (void) mdb_vread(&avhp, sizeof (struct autovec),
178 (uintptr_t)avec_tbl[i].avh_link);
180 interrupt_print_isr((uintptr_t)avhp.av_vector,
181 (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
183 while (avhp.av_link != NULL &&
184 mdb_vread(&avhp, sizeof (struct autovec),
185 (uintptr_t)avhp.av_link) != -1) {
186 mdb_printf(", ");
187 interrupt_print_isr((uintptr_t)avhp.av_vector,
188 (uintptr_t)avhp.av_intarg1, (uintptr_t)avhp.av_dip);
192 static int
193 evtchn_masked(int i)
195 return (TEST_EVTCHN_BIT(i, &shared_info.evtchn_mask[0]) != 0);
198 static int
199 evtchn_pending(int i)
201 return (TEST_EVTCHN_BIT(i, &shared_info.evtchn_pending[0]) != 0);
204 static void
205 pic_interrupt_dump(int i, struct autovec *avhp, int evtchn)
207 if (option_flags & INTR_DISPLAY_INTRSTAT) {
208 mdb_printf("%-3d ", 0);
209 print_isr(i);
210 mdb_printf("\n");
211 return;
214 mdb_printf("%-3d 0x%2x %-6d %6d/%-2d %-3s %-6s %-5d ",
215 i, i + PIC_VECTBASE, evtchn, avec_tbl[i].avh_lo_pri,
216 avec_tbl[i].avh_hi_pri, avhp->av_dip ?
217 interrupt_print_bus((uintptr_t)avhp->av_dip) : "-",
218 irq_type(i, 0), shared_tbl[i]);
220 print_isr(i);
222 mdb_printf("\n");
225 static void
226 ec_interrupt_dump(int i)
228 irq_info_t *irqp = &irq_tbl[i];
229 struct autovec avhp;
230 char evtchn[8];
232 if (irqp->ii_type == IRQT_UNBOUND)
233 return;
235 if (option_flags & INTR_DISPLAY_INTRSTAT) {
236 mdb_printf("%-3d ", 0);
237 print_isr(i);
238 mdb_printf("\n");
239 return;
243 memset(&avhp, 0, sizeof (avhp));
244 if (avec_tbl[i].avh_link != NULL)
245 (void) mdb_vread(&avhp, sizeof (struct autovec),
246 (uintptr_t)avec_tbl[i].avh_link);
248 switch (irqp->ii_type) {
249 case IRQT_EVTCHN:
250 case IRQT_VIRQ:
251 if (irqp->ii_u.index == VIRQ_TIMER) {
252 strcpy(evtchn, "T");
253 } else {
254 mdb_snprintf(evtchn, sizeof (evtchn), "%-7d",
255 irqp->ii_u.evtchn);
257 break;
258 case IRQT_IPI:
259 strcpy(evtchn, "I");
260 break;
261 case IRQT_DEV_EVTCHN:
262 strcpy(evtchn, "D");
263 break;
266 /* IRQ */
267 mdb_printf("%3d ", i);
268 /* Vector */
269 mdb_printf("- ");
270 /* Evtchn */
271 mdb_printf("%-7s", evtchn);
272 /* IPL */
273 mdb_printf("%6d/%-2d ", irq_tbl[i].ii_u2.ipl, irq_tbl[i].ii_u2.ipl);
274 /* Bus */
275 mdb_printf("%-3s ", avhp.av_dip
276 ? interrupt_print_bus((uintptr_t)avhp.av_dip) : "-");
277 /* Type */
278 mdb_printf("%-6s ", irq_type(i, 0));
279 /* Share */
280 mdb_printf("- ");
282 print_isr(i);
284 mdb_printf("\n");
288 * uppc_interrupt_dump:
289 * Dump uppc(7d) interrupt information.
291 /* ARGSUSED */
293 xen_uppc_interrupt_dump(uintptr_t addr, uint_t flags, int argc,
294 const mdb_arg_t *argv)
296 int i;
297 boolean_t found = B_FALSE;
298 struct autovec avhp;
300 option_flags = 0;
301 if (mdb_getopts(argc, argv,
302 'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
303 'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags,
304 NULL) != argc)
305 return (DCMD_USAGE);
307 if (!update_tables())
308 return (DCMD_ERR);
311 * By default, on all x86 systems ::interrupts from xen_uppc(7d) gets
312 * loaded first. For APIC systems the ::interrupts from xpv_psm(7d)
313 * ought to be executed. Confusion stems as both modules export the
314 * same dcmd.
316 for (i = 0; i < MAX_ISA_IRQ + 1; i++)
317 if (shared_tbl[i]) {
318 found = B_TRUE;
319 break;
322 if (found == B_FALSE) {
323 if (mdb_lookup_by_obj("xpv_psm", "apic_irq_table",
324 NULL) == 0) {
325 return (mdb_call_dcmd("xpv_psm`interrupts",
326 addr, flags, argc, argv));
330 /* Print the header first */
331 if (option_flags & INTR_DISPLAY_INTRSTAT)
332 mdb_printf("%<u>CPU ");
333 else
334 mdb_printf("%<u>IRQ Vect Evtchn IPL(lo/hi) Bus Type Share ");
335 mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
336 "Driver Name(s)" : "ISR(s)");
338 for (i = 0; i < NR_IRQS; i++) {
339 if (irq_tbl[i].ii_type == IRQT_PIRQ) {
340 if (irq_tbl[i].ii_u.evtchn == 0)
341 continue;
343 /* Read the entry, if invalid continue */
344 if (mdb_vread(&avhp, sizeof (struct autovec),
345 (uintptr_t)avec_tbl[i].avh_link) == -1)
346 continue;
348 pic_interrupt_dump(i, &avhp, irq_tbl[i].ii_u.evtchn);
349 continue;
352 ec_interrupt_dump(i);
355 return (DCMD_OK);
359 static void
360 evtchn_dump(int i)
362 int irq = evtchn_tbl[i];
364 if (irq == INVALID_IRQ) {
365 mdb_printf("%-14s%-7d%-4s%-7s", "unassigned", i, "-", "-");
366 mdb_printf("%-4d", 0);
367 mdb_printf("%-7d", evtchn_masked(i));
368 mdb_printf("%-8d", evtchn_pending(i));
369 mdb_printf("\n");
370 return;
373 /* Type */
374 mdb_printf("%-14s", irq_type(irq, 1));
375 /* Evtchn */
376 mdb_printf("%-7d", i);
377 /* IRQ */
378 mdb_printf("%-4d", irq);
379 /* IPL */
380 mdb_printf("%6d/%-2d ", irq_tbl[irq].ii_u2.ipl,
381 irq_tbl[irq].ii_u2.ipl);
382 /* CPU */
383 mdb_printf("%-4d", 0);
384 /* Masked/Pending */
385 mdb_printf("%-7d", evtchn_masked(i));
386 mdb_printf("%-8d", evtchn_pending(i));
387 /* ISR */
388 print_isr(irq);
390 mdb_printf("\n");
393 /* ARGSUSED */
394 static int
395 evtchns_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
397 int i;
398 boolean_t found = B_FALSE;
400 option_flags = 0;
401 if (mdb_getopts(argc, argv,
402 'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
403 NULL) != argc)
404 return (DCMD_USAGE);
406 if (!update_tables())
407 return (DCMD_ERR);
410 * By default, on all x86 systems ::evtchns from xen_uppc(7d) gets
411 * loaded first. For APIC systems the ::evtchns from xpv_psm(7d)
412 * ought to be executed. Confusion stems as both modules export the
413 * same dcmd.
415 for (i = 0; i < MAX_ISA_IRQ + 1; i++)
416 if (shared_tbl[i]) {
417 found = B_TRUE;
418 break;
421 if (found == B_FALSE) {
422 if (mdb_lookup_by_obj("xpv_psm", "apic_irq_table",
423 NULL) == 0) {
424 return (mdb_call_dcmd("xpv_psm`evtchns",
425 addr, flags, argc, argv));
429 if (flags & DCMD_ADDRSPEC) {
431 * Note: we allow the invalid evtchn 0, as it can help catch if
432 * we incorrectly try to configure it.
434 if ((int)addr >= NR_EVENT_CHANNELS) {
435 mdb_warn("Invalid event channel %d.\n", (int)addr);
436 return (DCMD_ERR);
440 mdb_printf("%<u>Type Evtchn IRQ IPL(lo/hi) CPU "
441 "Masked Pending ");
442 mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
443 "Driver Name(s)" : "ISR(s)");
445 if (flags & DCMD_ADDRSPEC) {
446 evtchn_dump((int)addr);
447 return (DCMD_OK);
450 for (i = 0; i < NR_EVENT_CHANNELS; i++) {
451 if (evtchn_tbl[i] == INVALID_IRQ)
452 continue;
454 evtchn_dump(i);
457 return (DCMD_OK);
460 static void
461 evtchns_help(void)
463 mdb_printf("Print valid event channels\n"
464 "If %<u>addr%</u> is given, interpret it as an evtchn to print "
465 "details of.\n"
466 "By default, only interrupt service routine names are printed.\n\n"
467 "Switches:\n"
468 " -d instead of ISR, print <driver_name><instance#>\n");
472 * MDB module linkage information:
474 static const mdb_dcmd_t dcmds[] = {
475 { "interrupts", "?[-di]", "print interrupts", xen_uppc_interrupt_dump,
476 interrupt_help},
477 { "evtchns", "?[-d]", "print event channels", evtchns_dump,
478 evtchns_help },
479 { "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump,
480 soft_interrupt_help},
481 { NULL }
484 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL };
486 const mdb_modinfo_t *
487 _mdb_init(void)
489 GElf_Sym sym;
491 if (mdb_lookup_by_name("gld_intr", &sym) != -1)
492 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
493 gld_intr_addr = (uintptr_t)sym.st_value;
495 return (&modinfo);