xref: /titanic_41/usr/src/cmd/mdb/sparc/modules/intr/intr.c (revision 26fd77009b17f8c8fb32eb362584cfd635e87ad9)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/mdb_modapi.h>
27 #include <mdb/mdb_ks.h>
28 #include <sys/async.h>		/* ecc_flt for pci_ecc.h */
29 #include <sys/ddi_subrdefs.h>
30 #include <sys/pci/pci_obj.h>
31 #include "px_obj.h"
32 
33 static int intr_pci_walk_step(mdb_walk_state_t *);
34 static int intr_px_walk_step(mdb_walk_state_t *);
35 static void intr_pci_print_items(mdb_walk_state_t *);
36 static void intr_px_print_items(mdb_walk_state_t *);
37 static char *intr_get_intr_type(uint16_t type);
38 static void intr_print_banner(void);
39 
40 typedef struct intr_info {
41 	uint32_t	cpuid;
42 	uint32_t	inum;
43 	uint32_t	num;
44 	uint32_t	pil;
45 	uint16_t	intr_type;
46 	uint16_t	mondo;
47 	uint8_t		ino_ino;
48 	uint_t		intr_state;
49 	int		instance;
50 	int		shared;
51 	char		driver_name[12];
52 	char		pathname[MAXNAMELEN];
53 }
54 intr_info_t;
55 
56 #define	PX_MAX_ENTRIES		32
57 
58 static void intr_print_elements(intr_info_t);
59 static int detailed = 0; /* Print detailed view */
60 
61 
62 static int
63 intr_walk_init(mdb_walk_state_t *wsp)
64 {
65 	wsp->walk_addr = NULL;
66 
67 	return (WALK_NEXT);
68 }
69 
70 static int
71 intr_walk_step(mdb_walk_state_t *wsp)
72 {
73 	pci_t		*pci_per_p;
74 	px_t		*px_state_p;
75 
76 	/* read globally declared structures in the pci driver */
77 	if (mdb_readvar(&pci_per_p, "per_pci_state") != -1) {
78 		wsp->walk_addr = (uintptr_t)pci_per_p;
79 		intr_pci_walk_step(wsp);
80 	}
81 
82 	/* read globally declared structures in the px driver */
83 	if (mdb_readvar(&px_state_p, "px_state_p") != -1) {
84 		wsp->walk_addr = (uintptr_t)px_state_p;
85 		intr_px_walk_step(wsp);
86 	}
87 
88 	return (WALK_DONE);
89 }
90 
91 static int
92 intr_pci_walk_step(mdb_walk_state_t *wsp)
93 {
94 	pci_t		*pci_per_p;
95 	pci_t		pci_per;
96 	uintptr_t	start_addr;
97 
98 	/* Read start of state structure array */
99 	if (mdb_vread(&pci_per_p, sizeof (uintptr_t),
100 	    (uintptr_t)wsp->walk_addr) == -1) {
101 		mdb_warn("intr: failed to read the initial pci_per_p "
102 		    "structure\n");
103 		return (WALK_ERR);
104 	}
105 
106 	/* Figure out how many items are here */
107 	start_addr = (uintptr_t)pci_per_p;
108 
109 	intr_print_banner();
110 
111 	while (mdb_vread(&pci_per_p, sizeof (uintptr_t),
112 	    (uintptr_t)start_addr) != -1) {
113 		/* Read until nothing is left */
114 		if (mdb_vread(&pci_per, sizeof (pci_t),
115 		    (uintptr_t)pci_per_p) == -1) {
116 			return (WALK_DONE);
117 		}
118 
119 		wsp->walk_addr = (uintptr_t)pci_per.pci_ib_p;
120 		intr_pci_print_items(wsp);
121 
122 		start_addr += sizeof (uintptr_t);
123 	}
124 
125 	return (WALK_DONE);
126 }
127 
128 static int
129 intr_px_walk_step(mdb_walk_state_t *wsp)
130 {
131 	px_t		*px_state_p;
132 	px_t		px_state;
133 	uintptr_t	start_addr;
134 	int		x;
135 
136 	/* Read start of state structure array */
137 	if (mdb_vread(&px_state_p, sizeof (uintptr_t),
138 	    (uintptr_t)wsp->walk_addr) == -1) {
139 		mdb_warn("intr: failed to read the initial px_per_p "
140 		    "structure\n");
141 		return (WALK_ERR);
142 	}
143 
144 	/* Figure out how many items are here */
145 	start_addr = (uintptr_t)px_state_p;
146 
147 	intr_print_banner();
148 
149 	for (x = 0; x < PX_MAX_ENTRIES; x++) {
150 		(void) mdb_vread(&px_state_p, sizeof (uintptr_t),
151 		    (uintptr_t)start_addr);
152 
153 		start_addr += sizeof (uintptr_t);
154 
155 		/* Read if anything is there */
156 		if (mdb_vread(&px_state, sizeof (px_t),
157 		    (uintptr_t)px_state_p) == -1) {
158 			continue;
159 		}
160 
161 		wsp->walk_addr = (uintptr_t)px_state.px_ib_p;
162 		intr_px_print_items(wsp);
163 	}
164 
165 	return (WALK_DONE);
166 }
167 
168 static void
169 intr_pci_print_items(mdb_walk_state_t *wsp)
170 {
171 	ib_t			ib;
172 	ib_ino_info_t		ino;
173 	ib_ino_pil_t		ipil;
174 	ih_t			ih;
175 	int			count;
176 	char			name[MODMAXNAMELEN + 1];
177 	struct dev_info		dev;
178 	intr_info_t		info;
179 
180 	if (mdb_vread(&ib, sizeof (ib_t),
181 	    (uintptr_t)wsp->walk_addr) == -1) {
182 		mdb_warn("intr: failed to read pci interrupt block "
183 		    "structure\n");
184 		return;
185 	}
186 
187 	/* Read in ib_ino_info_t structure at address */
188 	if (mdb_vread(&ino, sizeof (ib_ino_info_t),
189 	    (uintptr_t)ib.ib_ino_lst) == -1) {
190 		/* Nothing here to read from */
191 		return;
192 	}
193 
194 	do {
195 		if (mdb_vread(&ipil, sizeof (ib_ino_pil_t),
196 		    (uintptr_t)ino.ino_ipil_p) == -1) {
197 			mdb_warn("intr: failed to read pci interrupt "
198 			    "ib_ino_pil_t structure\n");
199 			return;
200 		}
201 
202 		do {
203 			if (mdb_vread(&ih, sizeof (ih_t),
204 			    (uintptr_t)ipil.ipil_ih_start) == -1) {
205 				mdb_warn("intr: failed to read pci interrupt "
206 				    "ih_t structure\n");
207 				return;
208 			}
209 
210 			count = 0;
211 
212 			do {
213 				bzero((void *)&info, sizeof (intr_info_t));
214 
215 				if ((ino.ino_ipil_size > 1) ||
216 				    (ipil.ipil_ih_size > 1)) {
217 					info.shared = 1;
218 				}
219 
220 				(void) mdb_devinfo2driver((uintptr_t)ih.ih_dip,
221 				    name, sizeof (name));
222 
223 				(void) mdb_ddi_pathname((uintptr_t)ih.ih_dip,
224 				    info.pathname, sizeof (info.pathname));
225 
226 				/* Get instance */
227 				if (mdb_vread(&dev, sizeof (struct dev_info),
228 				    (uintptr_t)ih.ih_dip) == -1) {
229 					mdb_warn("intr: failed to read DIP "
230 					    "structure\n");
231 					return;
232 				}
233 
234 				/* Make sure the name doesn't over run */
235 				(void) mdb_snprintf(info.driver_name,
236 				    sizeof (info.driver_name), "%s", name);
237 
238 				info.instance = dev.devi_instance;
239 				info.inum = ih.ih_inum;
240 				info.intr_type = DDI_INTR_TYPE_FIXED;
241 				info.num = 0;
242 				info.intr_state = ih.ih_intr_state;
243 				info.ino_ino = ino.ino_ino;
244 				info.mondo = ino.ino_mondo;
245 				info.pil = ipil.ipil_pil;
246 				info.cpuid = ino.ino_cpuid;
247 
248 				intr_print_elements(info);
249 				count++;
250 
251 				(void) mdb_vread(&ih, sizeof (ih_t),
252 				    (uintptr_t)ih.ih_next);
253 
254 			} while (count < ipil.ipil_ih_size);
255 
256 		} while (mdb_vread(&ipil, sizeof (ib_ino_pil_t),
257 		    (uintptr_t)ipil.ipil_next_p) != -1);
258 
259 	} while (mdb_vread(&ino, sizeof (ib_ino_info_t),
260 	    (uintptr_t)ino.ino_next_p) != -1);
261 }
262 
263 static void
264 intr_px_print_items(mdb_walk_state_t *wsp)
265 {
266 	px_ib_t		ib;
267 	px_ino_t	ino;
268 	px_ino_pil_t	ipil;
269 	px_ih_t		ih;
270 	int		count;
271 	char		name[MODMAXNAMELEN + 1];
272 	struct dev_info	dev;
273 	intr_info_t	info;
274 	devinfo_intr_t	intr_p;
275 
276 	if (mdb_vread(&ib, sizeof (px_ib_t), wsp->walk_addr) == -1) {
277 		return;
278 	}
279 
280 	/* Read in px_ino_t structure at address */
281 	if (mdb_vread(&ino, sizeof (px_ino_t),
282 	    (uintptr_t)ib.ib_ino_lst) == -1) {
283 		/* Nothing here to read from */
284 		return;
285 	}
286 
287 	do { /* ino_next_p loop */
288 		if (mdb_vread(&ipil, sizeof (px_ino_pil_t),
289 		    (uintptr_t)ino.ino_ipil_p) == -1) {
290 			continue;
291 		}
292 
293 		do { /* ipil_next_p loop */
294 			if (mdb_vread(&ih, sizeof (px_ih_t),
295 			    (uintptr_t)ipil.ipil_ih_start) == -1) {
296 				continue;
297 			}
298 
299 			count = 0;
300 
301 			do { /* ipil_ih_size loop */
302 				bzero((void *)&info, sizeof (intr_info_t));
303 
304 				(void) mdb_devinfo2driver((uintptr_t)ih.ih_dip,
305 				    name, sizeof (name));
306 
307 				(void) mdb_ddi_pathname((uintptr_t)ih.ih_dip,
308 				    info.pathname, sizeof (info.pathname));
309 
310 				/* Get instance */
311 				if (mdb_vread(&dev, sizeof (struct dev_info),
312 				    (uintptr_t)ih.ih_dip) == -1) {
313 					mdb_warn("intr: failed to read DIP "
314 					    "structure\n");
315 					return;
316 				}
317 
318 				/* Make sure the name doesn't over run */
319 				(void) mdb_snprintf(info.driver_name,
320 				    sizeof (info.driver_name), "%s", name);
321 
322 				info.instance = dev.devi_instance;
323 				info.inum = ih.ih_inum;
324 
325 				/*
326 				 * Read the type used, keep PCIe messages
327 				 * separate.
328 				 */
329 				(void) mdb_vread(&intr_p,
330 				    sizeof (devinfo_intr_t),
331 				    (uintptr_t)dev.devi_intr_p);
332 
333 				if (ih.ih_rec_type != MSG_REC) {
334 					info.intr_type =
335 					    intr_p.devi_intr_curr_type;
336 				}
337 
338 				if ((info.intr_type == DDI_INTR_TYPE_FIXED) &&
339 				    ((ino.ino_ipil_size > 1) ||
340 				    (ipil.ipil_ih_size > 1))) {
341 					info.shared = 1;
342 				}
343 
344 				info.num = ih.ih_msg_code;
345 				info.intr_state = ih.ih_intr_state;
346 				info.ino_ino = ino.ino_ino;
347 				info.mondo = ino.ino_sysino;
348 				info.pil = ipil.ipil_pil;
349 				info.cpuid = ino.ino_cpuid;
350 
351 				intr_print_elements(info);
352 				count++;
353 
354 				(void) mdb_vread(&ih, sizeof (px_ih_t),
355 				    (uintptr_t)ih.ih_next);
356 
357 			} while (count < ipil.ipil_ih_size);
358 
359 		} while ((ipil.ipil_next_p != NULL) &&
360 		    (mdb_vread(&ipil, sizeof (px_ino_pil_t),
361 		    (uintptr_t)ipil.ipil_next_p) != -1));
362 
363 	} while ((ino.ino_next_p != NULL) && (mdb_vread(&ino, sizeof (px_ino_t),
364 	    (uintptr_t)ino.ino_next_p) != -1));
365 }
366 
367 static char *
368 intr_get_intr_type(uint16_t type)
369 {
370 	switch (type) {
371 		case	DDI_INTR_TYPE_FIXED:
372 			return ("Fixed");
373 		case	DDI_INTR_TYPE_MSI:
374 			return ("MSI");
375 		case	DDI_INTR_TYPE_MSIX:
376 			return ("MSI-X");
377 		default:
378 			return ("PCIe");
379 	}
380 }
381 
382 static void
383 intr_print_banner(void)
384 {
385 	if (!detailed) {
386 		mdb_printf("\n%<u>\tDevice\t"
387 		    " Shared\t"
388 		    " Type\t"
389 		    " MSG #\t"
390 		    " State\t"
391 		    " INO\t"
392 		    " Mondo\t"
393 		    "  Pil\t"
394 		    " CPU   %</u>"
395 		    "\n");
396 	}
397 }
398 
399 static void
400 intr_print_elements(intr_info_t info)
401 {
402 	if (!detailed) {
403 		mdb_printf(" %11s#%d\t", info.driver_name, info.instance);
404 		mdb_printf(" %5s\t",
405 		    info.shared ? "yes" : "no");
406 		mdb_printf(" %s\t", intr_get_intr_type(info.intr_type));
407 		if (info.intr_type == DDI_INTR_TYPE_FIXED) {
408 			mdb_printf("  --- \t");
409 		} else {
410 			mdb_printf(" %4d\t", info.num);
411 		}
412 
413 		mdb_printf(" %2s\t",
414 		    info.intr_state ? "enbl" : "disbl");
415 		mdb_printf(" 0x%x\t", info.ino_ino);
416 		mdb_printf(" 0x%x\t", info.mondo);
417 		mdb_printf(" %4d\t", info.pil);
418 		mdb_printf(" %3d \n", info.cpuid);
419 	} else {
420 		mdb_printf("\n-------------------------------------------\n");
421 		mdb_printf("Device:\t\t%s\n", info.driver_name);
422 		mdb_printf("Instance:\t%d\n", info.instance);
423 		mdb_printf("Path:\t\t%s\n", info.pathname);
424 		mdb_printf("Inum:\t\t%d\n", info.inum);
425 		mdb_printf("Interrupt Type:\t%s\n",
426 		    intr_get_intr_type(info.intr_type));
427 		if (info.intr_type == DDI_INTR_TYPE_MSI) {
428 			mdb_printf("MSI Number:\t%d\n", info.num);
429 		} else if (info.intr_type == DDI_INTR_TYPE_MSIX) {
430 			mdb_printf("MSI-X Number:\t%d\n", info.num);
431 		} else if (!info.intr_type) {
432 			mdb_printf("PCIe Message #:\t%d\n", info.num);
433 		}
434 
435 		mdb_printf("Shared Intr:\t%s\n",
436 		    info.shared ? "yes" : "no");
437 		mdb_printf("State:\t\t%d (%s)\n", info.intr_state,
438 		    info.intr_state ? "Enabled" : "Disabled");
439 		mdb_printf("INO:\t\t0x%x\n", info.ino_ino);
440 		mdb_printf("Mondo:\t\t0x%x\n", info.mondo);
441 		mdb_printf("Pil:\t\t%d\n", info.pil);
442 		mdb_printf("CPU:\t\t%d\n", info.cpuid);
443 	}
444 }
445 
446 /*ARGSUSED*/
447 static void
448 intr_walk_fini(mdb_walk_state_t *wsp)
449 {
450 	/* Nothing to do here */
451 }
452 
453 /*ARGSUSED*/
454 static int
455 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
456 {
457 	detailed = 0;
458 
459 	if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed,
460 	    NULL) != argc)
461 		return (DCMD_USAGE);
462 
463 	if (!(flags & DCMD_ADDRSPEC)) {
464 		if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv)
465 		    == -1) {
466 			mdb_warn("can't walk pci/px buffer entries\n");
467 			return (DCMD_ERR);
468 		}
469 		return (DCMD_OK);
470 	}
471 
472 	return (DCMD_OK);
473 }
474 
475 /*
476  * MDB module linkage information:
477  */
478 
479 static const mdb_dcmd_t dcmds[] = {
480 	{ "interrupts", "[-d]", "display the interrupt info registered with "
481 	    "the PCI/PX nexus drivers", intr_intr },
482 	{ NULL }
483 };
484 
485 static const mdb_walker_t walkers[] = {
486 	{ "interrupts", "walk PCI/PX interrupt structures",
487 		intr_walk_init, intr_walk_step, intr_walk_fini },
488 	{ NULL }
489 };
490 
491 static const mdb_modinfo_t modinfo = {
492 	MDB_API_VERSION, dcmds, walkers
493 };
494 
495 const mdb_modinfo_t *
496 _mdb_init(void)
497 {
498 	return (&modinfo);
499 }
500