xref: /illumos-gate/usr/src/uts/i86pc/io/pci/pci_kstats.c (revision 7a364d25fde47aa82704b12b5251bf7fac37f02e)
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 /*
30  *	Kstat support for X86 PCI driver
31  */
32 
33 #include <sys/conf.h>
34 #include <sys/mach_intr.h>
35 #include <sys/psm.h>
36 #include <sys/clock.h>
37 #include <io/pcplusmp/apic.h>
38 #include <io/pci/pci_var.h>
39 
40 typedef struct pci_kstat_private {
41 	ddi_intr_handle_impl_t	*hdlp;
42 	dev_info_t		*rootnex_dip;
43 } pci_kstat_private_t;
44 
45 static struct {
46 	kstat_named_t ihks_name;
47 	kstat_named_t ihks_type;
48 	kstat_named_t ihks_cpu;
49 	kstat_named_t ihks_pil;
50 	kstat_named_t ihks_time;
51 	kstat_named_t ihks_ino;
52 	kstat_named_t ihks_cookie;
53 	kstat_named_t ihks_devpath;
54 	kstat_named_t ihks_buspath;
55 } pci_ks_template = {
56 	{ "name",	KSTAT_DATA_CHAR },
57 	{ "type",	KSTAT_DATA_CHAR },
58 	{ "cpu",	KSTAT_DATA_UINT64 },
59 	{ "pil",	KSTAT_DATA_UINT64 },
60 	{ "time",	KSTAT_DATA_UINT64 },
61 	{ "ino",	KSTAT_DATA_UINT64 },
62 	{ "cookie",	KSTAT_DATA_UINT64 },
63 	{ "devpath",	KSTAT_DATA_STRING },
64 	{ "buspath",	KSTAT_DATA_STRING },
65 };
66 
67 static uint32_t pci_ks_inst;
68 static kmutex_t pci_ks_template_lock;
69 
70 /*ARGSUSED*/
71 static int
72 pci_ih_ks_update(kstat_t *ksp, int rw)
73 {
74 	pci_kstat_private_t	*private_data =
75 				    (pci_kstat_private_t *)ksp->ks_private;
76 	dev_info_t		*rootnex_dip = private_data->rootnex_dip;
77 	ddi_intr_handle_impl_t	*ih_p = private_data->hdlp;
78 	dev_info_t		*dip = ih_p->ih_dip;
79 	int			maxlen =
80 				    sizeof (pci_ks_template.ihks_name.value.c);
81 	char			ih_devpath[MAXPATHLEN];
82 	char			ih_buspath[MAXPATHLEN];
83 	apic_get_intr_t	intrinfo;
84 
85 	(void) snprintf(pci_ks_template.ihks_name.value.c, maxlen, "%s%d",
86 	    ddi_driver_name(dip), ddi_get_instance(dip));
87 	(void) strcpy(pci_ks_template.ihks_type.value.c,
88 	    DDI_INTR_IS_MSI_OR_MSIX(ih_p->ih_type) ? "msi" : "fixed");
89 	pci_ks_template.ihks_pil.value.ui64 = ih_p->ih_pri;
90 	pci_ks_template.ihks_time.value.ui64 =
91 	    ((ihdl_plat_t *)ih_p->ih_private)->ip_ticks;
92 	tsc_scalehrtime((hrtime_t *)&pci_ks_template.ihks_time.value.ui64);
93 	pci_ks_template.ihks_cookie.value.ui64 = ih_p->ih_vector;
94 
95 	/*
96 	 * Return a vector since that's what PCItool will require intrd to use.
97 	 *
98 	 * PCItool will change the CPU routing of the IRQ that vector maps to.
99 	 *
100 	 * Note that although possibly multiple vectors can map to an IRQ, the
101 	 * vector returned below will always be the same for a given IRQ
102 	 * specified, and so all kstats for a given IRQ will report the same
103 	 * value for the ino field.
104 	 */
105 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID | PSMGI_REQ_VECTOR;
106 	if (pci_get_intr_from_vecirq(&intrinfo,  ih_p->ih_vector, IS_IRQ) !=
107 	    DDI_SUCCESS) {
108 		/* again, shouldn't happen */
109 		pci_ks_template.ihks_cpu.value.ui64 = 0;
110 		/* XXX Setting this value seems to be harmless. */
111 		pci_ks_template.ihks_cookie.value.ui64 = ih_p->ih_vector;
112 	} else {
113 		pci_ks_template.ihks_cpu.value.ui64 =
114 		    intrinfo.avgi_cpu_id & ~PSMGI_CPU_FLAGS;
115 		pci_ks_template.ihks_ino.value.ui64 = intrinfo.avgi_vector;
116 	}
117 
118 	(void) ddi_pathname(dip, ih_devpath);
119 	(void) ddi_pathname(rootnex_dip, ih_buspath);
120 	kstat_named_setstr(&pci_ks_template.ihks_devpath, ih_devpath);
121 	kstat_named_setstr(&pci_ks_template.ihks_buspath, ih_buspath);
122 
123 	return (0);
124 }
125 
126 
127 void pci_kstat_create(kstat_t **kspp, dev_info_t *rootnex_dip,
128     ddi_intr_handle_impl_t *hdlp)
129 {
130 	pci_kstat_private_t *private_data;
131 
132 	*kspp = kstat_create("pci_intrs", atomic_inc_32_nv(&pci_ks_inst),
133 	    "config", "interrupts", KSTAT_TYPE_NAMED,
134 	    sizeof (pci_ks_template) / sizeof (kstat_named_t),
135 	    KSTAT_FLAG_VIRTUAL);
136 	if (*kspp != NULL) {
137 
138 		private_data =
139 		    kmem_zalloc(sizeof (pci_kstat_private_t), KM_SLEEP);
140 		private_data->hdlp = hdlp;
141 		private_data->rootnex_dip = rootnex_dip;
142 
143 		(*kspp)->ks_private = private_data;
144 		(*kspp)->ks_data_size += MAXPATHLEN * 2;
145 		(*kspp)->ks_lock = &pci_ks_template_lock;
146 		(*kspp)->ks_data = &pci_ks_template;
147 		(*kspp)->ks_update = pci_ih_ks_update;
148 		kstat_install(*kspp);
149 	}
150 }
151 
152 void
153 pci_kstat_delete(kstat_t *ksp)
154 {
155 	pci_kstat_private_t *kstat_private;
156 
157 	if (ksp) {
158 		kstat_private = ksp->ks_private;
159 
160 		/*
161 		 * Delete the kstat before removing the private pointer, to
162 		 * prevent a kstat update from coming after private is freed.
163 		 */
164 		kstat_delete(ksp);
165 
166 		if (kstat_private)
167 			kmem_free(kstat_private, sizeof (pci_kstat_private_t));
168 	}
169 }
170