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