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