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