xref: /titanic_44/usr/src/cmd/mdb/sparc/modules/intr/intr.c (revision 298b7f4ca426d69789dddfabc7fd2863cf7a0ea4)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/mdb_modapi.h>
30 #include <mdb/mdb_ks.h>
31 #include <sys/async.h>		/* ecc_flt for pci_ecc.h */
32 #include <sys/ddi_subrdefs.h>
33 #include <sys/pci/pci_obj.h>
34 #include "px_obj.h"
35 
36 static int intr_pci_walk_step(mdb_walk_state_t *);
37 static int intr_px_walk_step(mdb_walk_state_t *);
38 static void intr_pci_print_items(mdb_walk_state_t *);
39 static void intr_px_print_items(mdb_walk_state_t *);
40 static char *intr_get_intr_type(msiq_rec_type_t);
41 static void intr_print_line(int);
42 static void intr_print_banner(void);
43 
44 typedef struct intr_info {
45 	uint32_t	cpuid;
46 	uint32_t	inum;
47 	uint32_t	num;
48 	uint32_t	pil;
49 	uint16_t	mondo;
50 	uint8_t		ino_ino;
51 	uint_t		intr_state;
52 	int		instance;
53 	int		shared;
54 	msiq_rec_type_t intr_type;
55 	char		driver_name[12];
56 	char		pathname[MAXNAMELEN];
57 }
58 intr_info_t;
59 
60 static void intr_print_elements(intr_info_t);
61 static int detailed = 0; /* Print detailed view */
62 
63 
64 static int
65 intr_walk_init(mdb_walk_state_t *wsp)
66 {
67 	wsp->walk_addr = NULL;
68 
69 	return (WALK_NEXT);
70 }
71 
72 static int
73 intr_walk_step(mdb_walk_state_t *wsp)
74 {
75 	pci_t		*pci_per_p;
76 	px_t		*px_state_p;
77 
78 	/* read globally declared structures in the pci driver */
79 	if (mdb_readvar(&pci_per_p, "per_pci_state") != -1) {
80 		wsp->walk_addr = (uintptr_t)pci_per_p;
81 		intr_pci_walk_step(wsp);
82 	}
83 
84 	/* read globally declared structures in the px driver */
85 	if (mdb_readvar(&px_state_p, "px_state_p") != -1) {
86 		wsp->walk_addr = (uintptr_t)px_state_p;
87 		intr_px_walk_step(wsp);
88 	}
89 
90 	return (WALK_DONE);
91 }
92 
93 static int
94 intr_pci_walk_step(mdb_walk_state_t *wsp)
95 {
96 	pci_t		*pci_per_p;
97 	pci_t		pci_per;
98 	uintptr_t	start_addr;
99 
100 	/* Read start of state structure array */
101 	if (mdb_vread(&pci_per_p, sizeof (uintptr_t),
102 	    (uintptr_t)wsp->walk_addr) == -1) {
103 		mdb_warn("intr: failed to read the initial pci_per_p "
104 		    "structure\n");
105 		return (WALK_ERR);
106 	}
107 
108 	/* Figure out how many items are here */
109 	start_addr = (uintptr_t)pci_per_p;
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 	while (mdb_vread(&px_state_p, sizeof (uintptr_t),
147 	    (uintptr_t)start_addr) != -1) {
148 		/* Read until nothing is left */
149 		if (mdb_vread(&px_state, sizeof (px_t),
150 		    (uintptr_t)px_state_p) == -1) {
151 			return (WALK_DONE);
152 		}
153 
154 		wsp->walk_addr = (uintptr_t)px_state.px_ib_p;
155 		intr_px_print_items(wsp);
156 
157 		start_addr += sizeof (uintptr_t);
158 	}
159 
160 	return (WALK_DONE);
161 }
162 
163 static void
164 intr_pci_print_items(mdb_walk_state_t *wsp)
165 {
166 	ib_t			pci_ib;
167 	ib_ino_info_t		*ib_ino_lst;
168 	ib_ino_info_t		list;
169 	ih_t			ih;
170 	int			count;
171 	char			name[MODMAXNAMELEN + 1];
172 	struct dev_info		devinfo;
173 	intr_info_t		info;
174 
175 	if (mdb_vread(&pci_ib, sizeof (ib_t),
176 	    (uintptr_t)wsp->walk_addr) == -1) {
177 		mdb_warn("intr: failed to read pci interrupt block "
178 		    "structure\n");
179 		return;
180 	}
181 
182 	/* Read in ib_ino_info_t structure at address */
183 	ib_ino_lst = pci_ib.ib_ino_lst;
184 	if (mdb_vread(&list, sizeof (ib_ino_info_t),
185 	    (uintptr_t)ib_ino_lst) == -1) {
186 		/* Nothing here to read from */
187 		return;
188 	}
189 
190 	intr_print_line(77);
191 	intr_print_banner();
192 	intr_print_line(77);
193 
194 	do {
195 		if (mdb_vread(&ih, sizeof (ih_t),
196 		    (uintptr_t)list.ino_ih_start) == -1) {
197 			mdb_warn("intr: failed to read pci interrupt entry "
198 			    "structure\n");
199 			return;
200 		}
201 
202 		count = 0;
203 
204 		do {
205 			bzero((void *)&info, sizeof (intr_info_t));
206 
207 			if (list.ino_ih_size > 1) {
208 				info.shared = 1;
209 			}
210 
211 			(void) mdb_devinfo2driver((uintptr_t)ih.ih_dip,
212 			    name, sizeof (name));
213 
214 			(void) mdb_ddi_pathname((uintptr_t)ih.ih_dip,
215 			    info.pathname, sizeof (info.pathname));
216 
217 			/* Get instance */
218 			if (mdb_vread(&devinfo, sizeof (struct dev_info),
219 			    (uintptr_t)ih.ih_dip) == -1) {
220 				mdb_warn("intr: failed to read DIP "
221 				    "structure\n");
222 				return;
223 			}
224 
225 			/* Make sure the name doesn't over run */
226 			(void) mdb_snprintf(info.driver_name,
227 			    sizeof (info.driver_name), "%s", name);
228 
229 			info.instance = devinfo.devi_instance;
230 			info.inum = ih.ih_inum;
231 			info.intr_type = INTX_REC;
232 			info.num = 0;
233 			info.intr_state = ih.ih_intr_state;
234 			info.ino_ino = list.ino_ino;
235 			info.mondo = list.ino_mondo;
236 			info.pil = list.ino_pil;
237 			info.cpuid = list.ino_cpuid;
238 
239 			intr_print_elements(info);
240 			count++;
241 
242 			(void) mdb_vread(&ih, sizeof (ih_t),
243 			    (uintptr_t)ih.ih_next);
244 
245 		} while (count < list.ino_ih_size);
246 
247 	} while (mdb_vread(&list, sizeof (ib_ino_info_t),
248 	    (uintptr_t)list.ino_next) != -1);
249 
250 	intr_print_line(77);
251 }
252 
253 static void
254 intr_px_print_items(mdb_walk_state_t *wsp)
255 {
256 	px_ib_t			px_ib;
257 	px_ib_ino_info_t	*px_ib_ino_lst;
258 	px_ib_ino_info_t	px_list;
259 	px_ih_t			px_ih;
260 	int			count;
261 	char			name[MODMAXNAMELEN + 1];
262 	struct dev_info		devinfo;
263 	intr_info_t		info;
264 
265 	if (mdb_vread(&px_ib, sizeof (px_ib_t), wsp->walk_addr) == -1) {
266 		mdb_warn("intr: failed to read px interrupt block "
267 		    "structure\n");
268 		return;
269 	}
270 
271 	/* Read in px_ib_ino_info_t structure at address */
272 	px_ib_ino_lst = px_ib.ib_ino_lst;
273 	if (mdb_vread(&px_list, sizeof (px_ib_ino_info_t),
274 	    (uintptr_t)px_ib_ino_lst) == -1) {
275 		/* Nothing here to read from */
276 		return;
277 	}
278 
279 	intr_print_line(77);
280 	intr_print_banner();
281 	intr_print_line(77);
282 
283 	do {
284 		if (mdb_vread(&px_ih, sizeof (px_ih_t),
285 		    (uintptr_t)px_list.ino_ih_start) == -1) {
286 			mdb_warn("intr: failed to read px interrupt entry "
287 			    "structure\n");
288 			return;
289 		}
290 
291 		count = 0;
292 
293 		do {
294 			bzero((void *)&info, sizeof (intr_info_t));
295 
296 			if (px_list.ino_ih_size > 1) {
297 				info.shared = 1;
298 			}
299 
300 			(void) mdb_devinfo2driver((uintptr_t)px_ih.ih_dip,
301 			    name, sizeof (name));
302 
303 			(void) mdb_ddi_pathname((uintptr_t)px_ih.ih_dip,
304 			    info.pathname, sizeof (info.pathname));
305 
306 			/* Get instance */
307 			if (mdb_vread(&devinfo, sizeof (struct dev_info),
308 			    (uintptr_t)px_ih.ih_dip) == -1) {
309 				mdb_warn("intr: failed to read DIP "
310 				    "structure\n");
311 				return;
312 			}
313 
314 			/* Make sure the name doesn't over run */
315 			(void) mdb_snprintf(info.driver_name,
316 			    sizeof (info.driver_name), "%s", name);
317 
318 			info.instance = devinfo.devi_instance;
319 			info.inum = px_ih.ih_inum;
320 			info.intr_type = px_ih.ih_rec_type;
321 			info.num = px_ih.ih_msg_code;
322 			info.intr_state = px_ih.ih_intr_state;
323 			info.ino_ino = px_list.ino_ino;
324 			info.mondo = px_list.ino_sysino;
325 			info.pil = px_list.ino_pil;
326 			info.cpuid = px_list.ino_cpuid;
327 
328 			intr_print_elements(info);
329 			count++;
330 
331 			(void) mdb_vread(&px_ih, sizeof (ih_t),
332 			    (uintptr_t)px_ih.ih_next);
333 
334 		} while (count < px_list.ino_ih_size);
335 
336 	} while (mdb_vread(&px_list, sizeof (px_ib_ino_info_t),
337 	    (uintptr_t)px_list.ino_next) != -1);
338 
339 	intr_print_line(77);
340 }
341 
342 static char *
343 intr_get_intr_type(msiq_rec_type_t rec_type)
344 {
345 	switch (rec_type) {
346 		case	MSG_REC:
347 			return ("PCIe");
348 		case	MSI32_REC:
349 		case	MSI64_REC:
350 			return ("MSI");
351 		case	INTX_REC:
352 		default:
353 			return ("Fixed");
354 	}
355 }
356 
357 static void
358 intr_print_line(int cnt)
359 {
360 	int	x;
361 
362 	if (!detailed) {
363 		mdb_printf("+");
364 		for (x = 0; x < cnt; x++) {
365 			mdb_printf("-");
366 		}
367 		mdb_printf("+\n");
368 	}
369 }
370 
371 static void
372 intr_print_banner(void)
373 {
374 	if (!detailed) {
375 		mdb_printf("|    Device\t"
376 		    "| Shard\t"
377 		    "| Type\t"
378 		    "| MSG #\t"
379 		    "| State "
380 		    "| INO\t"
381 		    "| Mondo\t"
382 		    "|  Pil\t"
383 		    "| CPU "
384 		    "|\n");
385 	}
386 }
387 
388 static void
389 intr_print_elements(intr_info_t info)
390 {
391 	if (!detailed) {
392 		mdb_printf("| %11s#%d\t", info.driver_name, info.instance);
393 		mdb_printf("| %s\t",
394 		    info.shared ? "yes" : "no");
395 		mdb_printf("| %s\t", intr_get_intr_type(info.intr_type));
396 		if (strcmp("Fixed", intr_get_intr_type(info.intr_type)) == 0) {
397 			mdb_printf("|  --- \t");
398 		} else {
399 			mdb_printf("| %4d\t", info.num);
400 		}
401 
402 		mdb_printf("| %2s\t",
403 		    info.intr_state ? "enbl" : "disbl");
404 		mdb_printf("| 0x%x\t", info.ino_ino);
405 		mdb_printf("| 0x%x", info.mondo);
406 		if (!(info.mondo & 0xF000)) {  /* Don't overrun table width */
407 			mdb_printf("\t");
408 		}
409 		mdb_printf("| %4d\t", info.pil);
410 		mdb_printf("| %3d |\n", info.cpuid);
411 	} else {
412 		mdb_printf("\n-------------------------------------------\n");
413 		mdb_printf("Device:\t\t%s\n", info.driver_name);
414 		mdb_printf("Instance:\t%d\n", info.instance);
415 		mdb_printf("Path:\t\t%s\n", info.pathname);
416 		mdb_printf("Inum:\t\t%d\n", info.inum);
417 		mdb_printf("Interrupt Type:\t%s\n",
418 		    intr_get_intr_type(info.intr_type));
419 		if (strcmp("MSI", intr_get_intr_type(info.intr_type)) == 0)
420 			mdb_printf("MSI/X Number:\t%s\n", info.num);
421 
422 		mdb_printf("Shared Intr:\t%s\n",
423 		    info.shared ? "yes" : "no");
424 		mdb_printf("State:\t\t%d (%s)\n", info.intr_state,
425 		    info.intr_state ? "Enabled" : "Disabled");
426 		mdb_printf("INO:\t\t0x%x\n", info.ino_ino);
427 		mdb_printf("Mondo:\t\t0x%x\n", info.mondo);
428 		mdb_printf("Pil:\t\t%d\n", info.pil);
429 		mdb_printf("CPU:\t\t%d\n", info.cpuid);
430 	}
431 }
432 
433 /*ARGSUSED*/
434 static void
435 intr_walk_fini(mdb_walk_state_t *wsp)
436 {
437 	/* Nothing to do here */
438 }
439 
440 /*ARGSUSED*/
441 static int
442 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
443 {
444 	detailed = 0;
445 
446 	if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed,
447 	    NULL) != argc)
448 		return (DCMD_USAGE);
449 
450 	if (!(flags & DCMD_ADDRSPEC)) {
451 		if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv)
452 		    == -1) {
453 			mdb_warn("can't walk pci/px buffer entries\n");
454 			return (DCMD_ERR);
455 		}
456 		return (DCMD_OK);
457 	}
458 
459 	return (DCMD_OK);
460 }
461 
462 /*
463  * MDB module linkage information:
464  */
465 
466 static const mdb_dcmd_t dcmds[] = {
467 	{ "interrupts", "[-d]", "display the interrupt info registered with "
468 	    "the PCI/PX nexus drivers", intr_intr },
469 	{ NULL }
470 };
471 
472 static const mdb_walker_t walkers[] = {
473 	{ "interrupts", "walk PCI/PX interrupt structures",
474 		intr_walk_init, intr_walk_step, intr_walk_fini },
475 	{ NULL }
476 };
477 
478 static const mdb_modinfo_t modinfo = {
479 	MDB_API_VERSION, dcmds, walkers
480 };
481 
482 const mdb_modinfo_t *
483 _mdb_init(void)
484 {
485 	return (&modinfo);
486 }
487