xref: /titanic_51/usr/src/cmd/mdb/sparc/modules/intr/intr.c (revision fd845fc0cb4fbc8e85f974e2e4eaacca1cc26e81)
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			pci_ib;
169 	ib_ino_info_t		*ib_ino_lst;
170 	ib_ino_info_t		list;
171 	ih_t			ih;
172 	int			count;
173 	char			name[MODMAXNAMELEN + 1];
174 	struct dev_info		devinfo;
175 	intr_info_t		info;
176 
177 	if (mdb_vread(&pci_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 	ib_ino_lst = pci_ib.ib_ino_lst;
186 	if (mdb_vread(&list, sizeof (ib_ino_info_t),
187 	    (uintptr_t)ib_ino_lst) == -1) {
188 		/* Nothing here to read from */
189 		return;
190 	}
191 
192 	do {
193 		if (mdb_vread(&ih, sizeof (ih_t),
194 		    (uintptr_t)list.ino_ih_start) == -1) {
195 			mdb_warn("intr: failed to read pci interrupt entry "
196 			    "structure\n");
197 			return;
198 		}
199 
200 		count = 0;
201 
202 		do {
203 			bzero((void *)&info, sizeof (intr_info_t));
204 
205 			if (list.ino_ih_size > 1) {
206 				info.shared = 1;
207 			}
208 
209 			(void) mdb_devinfo2driver((uintptr_t)ih.ih_dip,
210 			    name, sizeof (name));
211 
212 			(void) mdb_ddi_pathname((uintptr_t)ih.ih_dip,
213 			    info.pathname, sizeof (info.pathname));
214 
215 			/* Get instance */
216 			if (mdb_vread(&devinfo, sizeof (struct dev_info),
217 			    (uintptr_t)ih.ih_dip) == -1) {
218 				mdb_warn("intr: failed to read DIP "
219 				    "structure\n");
220 				return;
221 			}
222 
223 			/* Make sure the name doesn't over run */
224 			(void) mdb_snprintf(info.driver_name,
225 			    sizeof (info.driver_name), "%s", name);
226 
227 			info.instance = devinfo.devi_instance;
228 			info.inum = ih.ih_inum;
229 			info.intr_type = DDI_INTR_TYPE_FIXED;
230 			info.num = 0;
231 			info.intr_state = ih.ih_intr_state;
232 			info.ino_ino = list.ino_ino;
233 			info.mondo = list.ino_mondo;
234 			info.pil = list.ino_pil;
235 			info.cpuid = list.ino_cpuid;
236 
237 			intr_print_elements(info);
238 			count++;
239 
240 			(void) mdb_vread(&ih, sizeof (ih_t),
241 			    (uintptr_t)ih.ih_next);
242 
243 		} while (count < list.ino_ih_size);
244 
245 	} while (mdb_vread(&list, sizeof (ib_ino_info_t),
246 	    (uintptr_t)list.ino_next) != -1);
247 }
248 
249 static void
250 intr_px_print_items(mdb_walk_state_t *wsp)
251 {
252 	px_ib_t			px_ib;
253 	px_ib_ino_info_t	*px_ib_ino_lst;
254 	px_ib_ino_info_t	px_list;
255 	px_ih_t			px_ih;
256 	int			count;
257 	char			name[MODMAXNAMELEN + 1];
258 	struct dev_info		devinfo;
259 	intr_info_t		info;
260 	devinfo_intr_t		intr_p;
261 
262 	if (mdb_vread(&px_ib, sizeof (px_ib_t), wsp->walk_addr) == -1) {
263 		mdb_warn("intr: failed to read px interrupt block "
264 		    "structure\n");
265 		return;
266 	}
267 
268 	/* Read in px_ib_ino_info_t structure at address */
269 	px_ib_ino_lst = px_ib.ib_ino_lst;
270 	if (mdb_vread(&px_list, sizeof (px_ib_ino_info_t),
271 	    (uintptr_t)px_ib_ino_lst) == -1) {
272 		/* Nothing here to read from */
273 		return;
274 	}
275 
276 	do {
277 		if (mdb_vread(&px_ih, sizeof (px_ih_t),
278 		    (uintptr_t)px_list.ino_ih_start) == -1) {
279 			mdb_warn("intr: failed to read px interrupt entry "
280 			    "structure\n");
281 			return;
282 		}
283 
284 		count = 0;
285 
286 		do {
287 			bzero((void *)&info, sizeof (intr_info_t));
288 
289 			if (px_list.ino_ih_size > 1) {
290 				info.shared = 1;
291 			}
292 
293 			(void) mdb_devinfo2driver((uintptr_t)px_ih.ih_dip,
294 			    name, sizeof (name));
295 
296 			(void) mdb_ddi_pathname((uintptr_t)px_ih.ih_dip,
297 			    info.pathname, sizeof (info.pathname));
298 
299 			/* Get instance */
300 			if (mdb_vread(&devinfo, sizeof (struct dev_info),
301 			    (uintptr_t)px_ih.ih_dip) == -1) {
302 				mdb_warn("intr: failed to read DIP "
303 				    "structure\n");
304 				return;
305 			}
306 
307 			/* Make sure the name doesn't over run */
308 			(void) mdb_snprintf(info.driver_name,
309 			    sizeof (info.driver_name), "%s", name);
310 
311 			info.instance = devinfo.devi_instance;
312 			info.inum = px_ih.ih_inum;
313 
314 			/* Read the type used, keep PCIe messages separate */
315 			(void) mdb_vread(&intr_p, sizeof (devinfo_intr_t),
316 			    (uintptr_t)devinfo.devi_intr_p);
317 			if (px_ih.ih_rec_type != MSG_REC) {
318 				info.intr_type = intr_p.devi_intr_curr_type;
319 			}
320 
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 
340 static char *
341 intr_get_intr_type(uint16_t type)
342 {
343 	switch (type) {
344 		case	DDI_INTR_TYPE_FIXED:
345 			return ("Fixed");
346 		case	DDI_INTR_TYPE_MSI:
347 			return ("MSI");
348 		case	DDI_INTR_TYPE_MSIX:
349 			return ("MSI-X");
350 		default:
351 			return ("PCIe");
352 	}
353 }
354 
355 static void
356 intr_print_banner(void)
357 {
358 	if (!detailed) {
359 		mdb_printf("\n%<u>\tDevice\t"
360 		    " Shared\t"
361 		    " Type\t"
362 		    " MSG #\t"
363 		    " State\t"
364 		    " INO\t"
365 		    " Mondo\t"
366 		    "  Pil\t"
367 		    " CPU   %</u>"
368 		    "\n");
369 	}
370 }
371 
372 static void
373 intr_print_elements(intr_info_t info)
374 {
375 	if (!detailed) {
376 		mdb_printf(" %11s#%d\t", info.driver_name, info.instance);
377 		mdb_printf(" %5s\t",
378 		    info.shared ? "yes" : "no");
379 		mdb_printf(" %s\t", intr_get_intr_type(info.intr_type));
380 		if (info.intr_type == DDI_INTR_TYPE_FIXED) {
381 			mdb_printf("  --- \t");
382 		} else {
383 			mdb_printf(" %4d\t", info.num);
384 		}
385 
386 		mdb_printf(" %2s\t",
387 		    info.intr_state ? "enbl" : "disbl");
388 		mdb_printf(" 0x%x\t", info.ino_ino);
389 		mdb_printf(" 0x%x\t", info.mondo);
390 		mdb_printf(" %4d\t", info.pil);
391 		mdb_printf(" %3d \n", info.cpuid);
392 	} else {
393 		mdb_printf("\n-------------------------------------------\n");
394 		mdb_printf("Device:\t\t%s\n", info.driver_name);
395 		mdb_printf("Instance:\t%d\n", info.instance);
396 		mdb_printf("Path:\t\t%s\n", info.pathname);
397 		mdb_printf("Inum:\t\t%d\n", info.inum);
398 		mdb_printf("Interrupt Type:\t%s\n",
399 		    intr_get_intr_type(info.intr_type));
400 		if (info.intr_type == DDI_INTR_TYPE_MSI) {
401 			mdb_printf("MSI Number:\t%d\n", info.num);
402 		} else if (info.intr_type == DDI_INTR_TYPE_MSIX) {
403 			mdb_printf("MSI-X Number:\t%d\n", info.num);
404 		} else if (!info.intr_type) {
405 			mdb_printf("PCIe Message #:\t%d\n", info.num);
406 		}
407 
408 		mdb_printf("Shared Intr:\t%s\n",
409 		    info.shared ? "yes" : "no");
410 		mdb_printf("State:\t\t%d (%s)\n", info.intr_state,
411 		    info.intr_state ? "Enabled" : "Disabled");
412 		mdb_printf("INO:\t\t0x%x\n", info.ino_ino);
413 		mdb_printf("Mondo:\t\t0x%x\n", info.mondo);
414 		mdb_printf("Pil:\t\t%d\n", info.pil);
415 		mdb_printf("CPU:\t\t%d\n", info.cpuid);
416 	}
417 }
418 
419 /*ARGSUSED*/
420 static void
421 intr_walk_fini(mdb_walk_state_t *wsp)
422 {
423 	/* Nothing to do here */
424 }
425 
426 /*ARGSUSED*/
427 static int
428 intr_intr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
429 {
430 	detailed = 0;
431 
432 	if (mdb_getopts(argc, argv, 'd', MDB_OPT_SETBITS, TRUE, &detailed,
433 	    NULL) != argc)
434 		return (DCMD_USAGE);
435 
436 	if (!(flags & DCMD_ADDRSPEC)) {
437 		if (mdb_walk_dcmd("interrupts", "interrupts", argc, argv)
438 		    == -1) {
439 			mdb_warn("can't walk pci/px buffer entries\n");
440 			return (DCMD_ERR);
441 		}
442 		return (DCMD_OK);
443 	}
444 
445 	return (DCMD_OK);
446 }
447 
448 /*
449  * MDB module linkage information:
450  */
451 
452 static const mdb_dcmd_t dcmds[] = {
453 	{ "interrupts", "[-d]", "display the interrupt info registered with "
454 	    "the PCI/PX nexus drivers", intr_intr },
455 	{ NULL }
456 };
457 
458 static const mdb_walker_t walkers[] = {
459 	{ "interrupts", "walk PCI/PX interrupt structures",
460 		intr_walk_init, intr_walk_step, intr_walk_fini },
461 	{ NULL }
462 };
463 
464 static const mdb_modinfo_t modinfo = {
465 	MDB_API_VERSION, dcmds, walkers
466 };
467 
468 const mdb_modinfo_t *
469 _mdb_init(void)
470 {
471 	return (&modinfo);
472 }
473