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 (c) 2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/async.h> 29 #include <sys/sunddi.h> 30 #include <sys/sunndi.h> 31 #include <sys/ddi_impldefs.h> 32 #include <sys/pci/pci_obj.h> 33 #include <sys/machsystm.h> /* lddphys() */ 34 #include <sys/kstat.h> 35 36 /*LINTLIBRARY*/ 37 38 static kstat_t *pci_create_picN_kstat(char *, int, int, int, 39 pci_kev_mask_t *); 40 41 void 42 pci_kstat_create(pci_t *pci_p) 43 { 44 pci_common_t *cmn_p = pci_p->pci_common_p; 45 46 if (cmn_p->pci_common_attachcnt == 0) 47 pci_add_upstream_kstat(pci_p); 48 49 pci_add_pci_kstat(pci_p); 50 } 51 52 void 53 pci_kstat_destroy(pci_t *pci_p) 54 { 55 pci_common_t *cmn_p = pci_p->pci_common_p; 56 57 pci_rem_pci_kstat(pci_p); 58 59 if (cmn_p->pci_common_attachcnt == 0) 60 pci_rem_upstream_kstat(pci_p); 61 } 62 63 void 64 pci_create_name_kstat(char *name, pci_ksinfo_t *pp, pci_kev_mask_t *ev) 65 { 66 int i; 67 68 for (i = 0; i < NUM_OF_PICS; i++) { 69 pp->pic_name_ksp[i] = pci_create_picN_kstat(name, 70 i, pp->pic_shift[i], pp->pic_no_evs, ev); 71 72 if (pp->pic_name_ksp[i] == NULL) { 73 cmn_err(CE_WARN, "pci: unable to create name kstat"); 74 } 75 } 76 } 77 78 void 79 pci_delete_name_kstat(pci_ksinfo_t *pp) 80 { 81 int i; 82 83 if (pp != NULL) { 84 for (i = 0; i < NUM_OF_PICS; i++) { 85 if (pp->pic_name_ksp[i] != NULL) 86 kstat_delete(pp->pic_name_ksp[i]); 87 } 88 } 89 } 90 91 /* 92 * Create the picN kstat. Returns a pointer to the 93 * kstat which the driver must store to allow it 94 * to be deleted when necessary. 95 */ 96 static kstat_t * 97 pci_create_picN_kstat(char *mod_name, int pic, int pic_shift, 98 int num_ev, pci_kev_mask_t *ev_array) 99 { 100 struct kstat_named *pic_named_data; 101 int inst = 0; 102 int event; 103 char pic_name[30]; 104 kstat_t *picN_ksp = NULL; 105 106 (void) sprintf(pic_name, "pic%d", pic); 107 if ((picN_ksp = kstat_create(mod_name, inst, pic_name, 108 "bus", KSTAT_TYPE_NAMED, num_ev, 0)) == NULL) { 109 cmn_err(CE_WARN, "%s %s : kstat create failed", 110 mod_name, pic_name); 111 112 /* 113 * It is up to the calling function to delete any kstats 114 * that may have been created already. We just 115 * return NULL to indicate an error has occured. 116 */ 117 return (NULL); 118 } 119 120 pic_named_data = (struct kstat_named *)picN_ksp->ks_data; 121 122 /* 123 * Write event names and their associated pcr masks. The 124 * last entry in the array (clear_pic) is added seperately 125 * below as the pic value must be inverted. 126 */ 127 for (event = 0; event < num_ev - 1; event++) { 128 pic_named_data[event].value.ui64 = 129 (ev_array[event].pcr_mask << pic_shift); 130 131 kstat_named_init(&pic_named_data[event], 132 ev_array[event].event_name, KSTAT_DATA_UINT64); 133 } 134 135 /* 136 * add the clear_pic entry. 137 */ 138 pic_named_data[event].value.ui64 = 139 (uint64_t)~(ev_array[event].pcr_mask << pic_shift); 140 141 kstat_named_init(&pic_named_data[event], 142 ev_array[event].event_name, KSTAT_DATA_UINT64); 143 144 kstat_install(picN_ksp); 145 146 return (picN_ksp); 147 } 148 149 /* 150 * Create the "counters" kstat. 151 */ 152 kstat_t *pci_create_cntr_kstat(pci_t *pci_p, char *name, 153 int num_pics, int (*update)(kstat_t *, int), 154 void *cntr_addr_p) 155 { 156 struct kstat *counters_ksp; 157 struct kstat_named *counters_named_data; 158 dev_info_t *dip = pci_p->pci_dip; 159 char *drv_name = (char *)ddi_driver_name(dip); 160 int drv_instance = ddi_get_instance(dip); 161 char pic_str[10]; 162 int i; 163 164 /* 165 * Size of kstat is num_pics + 1 as it 166 * also contains the %pcr 167 */ 168 if ((counters_ksp = kstat_create(name, drv_instance, 169 "counters", "bus", KSTAT_TYPE_NAMED, num_pics + 1, 170 KSTAT_FLAG_WRITABLE)) == NULL) { 171 172 cmn_err(CE_WARN, "%s%d counters kstat_create failed", 173 drv_name, drv_instance); 174 return (NULL); 175 } 176 177 counters_named_data = 178 (struct kstat_named *)(counters_ksp->ks_data); 179 180 /* initialize the named kstats */ 181 kstat_named_init(&counters_named_data[0], 182 "pcr", KSTAT_DATA_UINT64); 183 184 for (i = 0; i < num_pics; i++) { 185 (void) sprintf(pic_str, "pic%d", i); 186 187 kstat_named_init(&counters_named_data[i+1], 188 pic_str, KSTAT_DATA_UINT64); 189 } 190 191 /* 192 * Store the register offset's in the kstat's 193 * private field so that they are available 194 * to the update function. 195 */ 196 counters_ksp->ks_private = (void *)cntr_addr_p; 197 counters_ksp->ks_update = update; 198 199 kstat_install(counters_ksp); 200 201 return (counters_ksp); 202 } 203 204 /* 205 * kstat update function. Handles reads/writes 206 * from/to kstat. 207 */ 208 int 209 pci_cntr_kstat_update(kstat_t *ksp, int rw) 210 { 211 struct kstat_named *data_p; 212 pci_cntr_addr_t *cntr_addr_p = ksp->ks_private; 213 uint64_t pic; 214 215 data_p = (struct kstat_named *)ksp->ks_data; 216 217 if (rw == KSTAT_WRITE) { 218 *cntr_addr_p->pcr_addr = data_p[0].value.ui64; 219 return (0); 220 } else { 221 pic = *cntr_addr_p->pic_addr; 222 data_p[0].value.ui64 = *cntr_addr_p->pcr_addr; 223 224 /* pic0 : lo 32 bits */ 225 data_p[1].value.ui64 = (pic <<32) >> 32; 226 /* pic1 : hi 32 bits */ 227 data_p[2].value.ui64 = pic >> 32; 228 } 229 return (0); 230 } 231 232 /* 233 * kstat update function using physical addresses. 234 */ 235 int 236 pci_cntr_kstat_pa_update(kstat_t *ksp, int rw) 237 { 238 struct kstat_named *data_p; 239 pci_cntr_pa_t *cntr_pa_p = (pci_cntr_pa_t *)ksp->ks_private; 240 uint64_t pic; 241 242 data_p = (struct kstat_named *)ksp->ks_data; 243 244 if (rw == KSTAT_WRITE) { 245 stdphysio(cntr_pa_p->pcr_pa, data_p[0].value.ui64); 246 return (0); 247 } else { 248 pic = lddphysio(cntr_pa_p->pic_pa); 249 data_p[0].value.ui64 = lddphysio(cntr_pa_p->pcr_pa); 250 251 /* pic0 : lo 32 bits */ 252 data_p[1].value.ui64 = (pic << 32) >> 32; 253 /* pic1 : hi 32 bits */ 254 data_p[2].value.ui64 = pic >> 32; 255 } 256 return (0); 257 } 258 259 260 /* 261 * Matched with pci_add_upstream_kstat() 262 */ 263 void 264 pci_rem_upstream_kstat(pci_t *pci_p) 265 { 266 pci_common_t *cmn_p = pci_p->pci_common_p; 267 268 if (cmn_p->pci_common_uksp != NULL) 269 kstat_delete(cmn_p->pci_common_uksp); 270 cmn_p->pci_common_uksp = NULL; 271 } 272