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