xref: /onnv-gate/usr/src/uts/i86pc/io/pci/pci_kstats.c (revision 12825:e35468461453)
1916Sschwartz /*
2916Sschwartz  * CDDL HEADER START
3916Sschwartz  *
4916Sschwartz  * The contents of this file are subject to the terms of the
51811Sesolom  * Common Development and Distribution License (the "License").
61811Sesolom  * You may not use this file except in compliance with the License.
7916Sschwartz  *
8916Sschwartz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9916Sschwartz  * or http://www.opensolaris.org/os/licensing.
10916Sschwartz  * See the License for the specific language governing permissions
11916Sschwartz  * and limitations under the License.
12916Sschwartz  *
13916Sschwartz  * When distributing Covered Code, include this CDDL HEADER in each
14916Sschwartz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15916Sschwartz  * If applicable, add the following below this CDDL HEADER, with the
16916Sschwartz  * fields enclosed by brackets "[]" replaced with your own identifying
17916Sschwartz  * information: Portions Copyright [yyyy] [name of copyright owner]
18916Sschwartz  *
19916Sschwartz  * CDDL HEADER END
20916Sschwartz  */
21916Sschwartz /*
22*12825SJimmy.Vetayases@oracle.com  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23916Sschwartz  */
24916Sschwartz /*
25916Sschwartz  *	Kstat support for X86 PCI driver
26916Sschwartz  */
27916Sschwartz 
28916Sschwartz #include <sys/conf.h>
29916Sschwartz #include <sys/mach_intr.h>
30916Sschwartz #include <sys/psm.h>
31916Sschwartz #include <sys/clock.h>
323446Smrj #include <sys/apic.h>
33916Sschwartz #include <io/pci/pci_var.h>
34916Sschwartz 
35916Sschwartz typedef struct pci_kstat_private {
36916Sschwartz 	ddi_intr_handle_impl_t	*hdlp;
37916Sschwartz 	dev_info_t		*rootnex_dip;
38916Sschwartz } pci_kstat_private_t;
39916Sschwartz 
40916Sschwartz static struct {
41916Sschwartz 	kstat_named_t ihks_name;
42916Sschwartz 	kstat_named_t ihks_type;
43916Sschwartz 	kstat_named_t ihks_cpu;
44916Sschwartz 	kstat_named_t ihks_pil;
45916Sschwartz 	kstat_named_t ihks_time;
46916Sschwartz 	kstat_named_t ihks_ino;
47916Sschwartz 	kstat_named_t ihks_cookie;
48916Sschwartz 	kstat_named_t ihks_devpath;
49916Sschwartz 	kstat_named_t ihks_buspath;
50916Sschwartz } pci_ks_template = {
51916Sschwartz 	{ "name",	KSTAT_DATA_CHAR },
52916Sschwartz 	{ "type",	KSTAT_DATA_CHAR },
53916Sschwartz 	{ "cpu",	KSTAT_DATA_UINT64 },
54916Sschwartz 	{ "pil",	KSTAT_DATA_UINT64 },
55916Sschwartz 	{ "time",	KSTAT_DATA_UINT64 },
56916Sschwartz 	{ "ino",	KSTAT_DATA_UINT64 },
57916Sschwartz 	{ "cookie",	KSTAT_DATA_UINT64 },
58916Sschwartz 	{ "devpath",	KSTAT_DATA_STRING },
59916Sschwartz 	{ "buspath",	KSTAT_DATA_STRING },
60916Sschwartz };
61916Sschwartz 
621811Sesolom static char ih_devpath[MAXPATHLEN];
631811Sesolom static char ih_buspath[MAXPATHLEN];
64916Sschwartz static uint32_t pci_ks_inst;
65916Sschwartz static kmutex_t pci_ks_template_lock;
66916Sschwartz 
6712683SJimmy.Vetayases@oracle.com extern int		(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
6812683SJimmy.Vetayases@oracle.com 			    psm_intr_op_t, int *);
6912683SJimmy.Vetayases@oracle.com 
70916Sschwartz /*ARGSUSED*/
71916Sschwartz static int
pci_ih_ks_update(kstat_t * ksp,int rw)72916Sschwartz pci_ih_ks_update(kstat_t *ksp, int rw)
73916Sschwartz {
744397Sschwartz 	pci_kstat_private_t *private_data =
754397Sschwartz 	    (pci_kstat_private_t *)ksp->ks_private;
764397Sschwartz 	dev_info_t *rootnex_dip = private_data->rootnex_dip;
7712683SJimmy.Vetayases@oracle.com 	ddi_intr_handle_impl_t tmp_hdl, *ih_p = private_data->hdlp;
784397Sschwartz 	dev_info_t *dip = ih_p->ih_dip;
794397Sschwartz 	int maxlen = sizeof (pci_ks_template.ihks_name.value.c);
80916Sschwartz 	apic_get_intr_t	intrinfo;
81916Sschwartz 
82916Sschwartz 	(void) snprintf(pci_ks_template.ihks_name.value.c, maxlen, "%s%d",
83916Sschwartz 	    ddi_driver_name(dip), ddi_get_instance(dip));
841087Sschwartz 	(void) ddi_pathname(dip, ih_devpath);
851087Sschwartz 	(void) ddi_pathname(rootnex_dip, ih_buspath);
861087Sschwartz 	kstat_named_setstr(&pci_ks_template.ihks_devpath, ih_devpath);
871087Sschwartz 	kstat_named_setstr(&pci_ks_template.ihks_buspath, ih_buspath);
88916Sschwartz 
89916Sschwartz 	/*
90916Sschwartz 	 * Note that although possibly multiple vectors can map to an IRQ, the
91916Sschwartz 	 * vector returned below will always be the same for a given IRQ
92916Sschwartz 	 * specified, and so all kstats for a given IRQ will report the same
93916Sschwartz 	 * value for the ino field.
941087Sschwartz 	 *
951087Sschwartz 	 * ---
961087Sschwartz 	 *
971087Sschwartz 	 * Check for the enabled state, since kstats are set up when the ISR is
981087Sschwartz 	 * added, not enabled.  There may be a period where interrupts are not
991087Sschwartz 	 * enabled even though they may have been added.
1001087Sschwartz 	 *
1011087Sschwartz 	 * It is also possible that the vector is for a dummy interrupt.
1021087Sschwartz 	 * pci_get_intr_from_vecirq will return failure in this case.
103916Sschwartz 	 */
10412683SJimmy.Vetayases@oracle.com 	bcopy(ih_p, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
10512683SJimmy.Vetayases@oracle.com 	tmp_hdl.ih_private = (void *)&intrinfo;
10612683SJimmy.Vetayases@oracle.com 	intrinfo.avgi_cpu_id = 0; /* In case psm_intr_ops fails */
107916Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID | PSMGI_REQ_VECTOR;
10812683SJimmy.Vetayases@oracle.com 	intrinfo.avgi_req_flags |= PSMGI_INTRBY_DEFAULT;
10912683SJimmy.Vetayases@oracle.com 
1101087Sschwartz 	if ((ih_p->ih_state != DDI_IHDL_STATE_ENABLE) ||
11112683SJimmy.Vetayases@oracle.com 	    ((*psm_intr_ops)(NULL, &tmp_hdl, PSM_INTR_OP_GET_INTR, NULL) !=
1124397Sschwartz 	    DDI_SUCCESS) ||
1131087Sschwartz 	    (intrinfo.avgi_cpu_id & PSMGI_CPU_FLAGS)) {
1141087Sschwartz 
1151087Sschwartz 		(void) strcpy(pci_ks_template.ihks_type.value.c, "disabled");
1161087Sschwartz 		pci_ks_template.ihks_pil.value.ui64 = 0;
1171087Sschwartz 		pci_ks_template.ihks_time.value.ui64 = 0;
1181087Sschwartz 		pci_ks_template.ihks_cookie.value.ui64 = 0;
119916Sschwartz 		pci_ks_template.ihks_cpu.value.ui64 = 0;
1201087Sschwartz 		pci_ks_template.ihks_ino.value.ui64 = 0;
1211087Sschwartz 
1221087Sschwartz 		/* Interrupt is user-bound.  Remove kstat. */
1231087Sschwartz 		if (intrinfo.avgi_cpu_id & PSMGI_CPU_FLAGS)
1241087Sschwartz 			(void) taskq_dispatch(system_taskq,
1251087Sschwartz 			    (void (*)(void *))pci_kstat_delete, ksp, TQ_SLEEP);
1261087Sschwartz 
1271087Sschwartz 		return (0);
128916Sschwartz 	}
129916Sschwartz 
1301087Sschwartz 	/*
1311087Sschwartz 	 * Interrupt is valid (not a dummy), not user-bound to a specific cpu,
1321087Sschwartz 	 * and enabled.  Update kstat fields.
1331087Sschwartz 	 */
1344397Sschwartz 	switch (ih_p->ih_type) {
1354397Sschwartz 	case DDI_INTR_TYPE_MSI:
1364397Sschwartz 		(void) strcpy(pci_ks_template.ihks_type.value.c, "msi");
1374397Sschwartz 		break;
1384397Sschwartz 	case DDI_INTR_TYPE_MSIX:
1394397Sschwartz 		(void) strcpy(pci_ks_template.ihks_type.value.c, "msix");
1404397Sschwartz 		break;
1414397Sschwartz 	default:
1424397Sschwartz 		(void) strcpy(pci_ks_template.ihks_type.value.c, "fixed");
1434397Sschwartz 		break;
1444397Sschwartz 	}
1451087Sschwartz 	pci_ks_template.ihks_pil.value.ui64 = ih_p->ih_pri;
1461087Sschwartz 	pci_ks_template.ihks_time.value.ui64 =
1471087Sschwartz 	    ((ihdl_plat_t *)ih_p->ih_private)->ip_ticks;
1485084Sjohnlev 	scalehrtime((hrtime_t *)&pci_ks_template.ihks_time.value.ui64);
1491087Sschwartz 	pci_ks_template.ihks_cookie.value.ui64 = ih_p->ih_vector;
1501087Sschwartz 	/* CPU won't be user bound at this point. */
1511087Sschwartz 	pci_ks_template.ihks_cpu.value.ui64 = intrinfo.avgi_cpu_id;
1521087Sschwartz 	pci_ks_template.ihks_ino.value.ui64 = intrinfo.avgi_vector;
153916Sschwartz 
154916Sschwartz 	return (0);
155916Sschwartz }
156916Sschwartz 
157916Sschwartz 
pci_kstat_create(kstat_t ** kspp,dev_info_t * rootnex_dip,ddi_intr_handle_impl_t * hdlp)158916Sschwartz void pci_kstat_create(kstat_t **kspp, dev_info_t *rootnex_dip,
159916Sschwartz     ddi_intr_handle_impl_t *hdlp)
160916Sschwartz {
161916Sschwartz 	pci_kstat_private_t *private_data;
162916Sschwartz 
163916Sschwartz 	*kspp = kstat_create("pci_intrs", atomic_inc_32_nv(&pci_ks_inst),
1641813Sschwartz 	    _MODULE_NAME, "interrupts", KSTAT_TYPE_NAMED,
165916Sschwartz 	    sizeof (pci_ks_template) / sizeof (kstat_named_t),
166916Sschwartz 	    KSTAT_FLAG_VIRTUAL);
167916Sschwartz 	if (*kspp != NULL) {
168916Sschwartz 
169916Sschwartz 		private_data =
170916Sschwartz 		    kmem_zalloc(sizeof (pci_kstat_private_t), KM_SLEEP);
171916Sschwartz 		private_data->hdlp = hdlp;
172916Sschwartz 		private_data->rootnex_dip = rootnex_dip;
173916Sschwartz 
174916Sschwartz 		(*kspp)->ks_private = private_data;
175916Sschwartz 		(*kspp)->ks_data_size += MAXPATHLEN * 2;
176916Sschwartz 		(*kspp)->ks_lock = &pci_ks_template_lock;
177916Sschwartz 		(*kspp)->ks_data = &pci_ks_template;
178916Sschwartz 		(*kspp)->ks_update = pci_ih_ks_update;
179916Sschwartz 		kstat_install(*kspp);
180916Sschwartz 	}
181916Sschwartz }
182916Sschwartz 
1831087Sschwartz 
1841087Sschwartz /*
1851087Sschwartz  * This function is invoked in two ways:
1861087Sschwartz  * - Thru taskq thread via pci_ih_ks_update to remove kstats for user-bound
1871087Sschwartz  *   interrupts.
1881087Sschwartz  * - From the REMISR introp when an interrupt is being removed.
1891087Sschwartz  */
190916Sschwartz void
pci_kstat_delete(kstat_t * ksp)191916Sschwartz pci_kstat_delete(kstat_t *ksp)
192916Sschwartz {
1934397Sschwartz 	pci_kstat_private_t *kstat_private;
1944397Sschwartz 	ddi_intr_handle_impl_t *hdlp;
195916Sschwartz 
196916Sschwartz 	if (ksp) {
197916Sschwartz 		kstat_private = ksp->ks_private;
1981087Sschwartz 		hdlp = kstat_private->hdlp;
1991087Sschwartz 		((ihdl_plat_t *)hdlp->ih_private)->ip_ksp = NULL;
200916Sschwartz 
201916Sschwartz 		/*
202916Sschwartz 		 * Delete the kstat before removing the private pointer, to
203916Sschwartz 		 * prevent a kstat update from coming after private is freed.
204916Sschwartz 		 */
205916Sschwartz 		kstat_delete(ksp);
206916Sschwartz 
2071087Sschwartz 		kmem_free(kstat_private, sizeof (pci_kstat_private_t));
208916Sschwartz 	}
209916Sschwartz }
210