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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/async.h> 30 #include <sys/sunddi.h> 31 #include <sys/sunndi.h> 32 #include <sys/ddi_impldefs.h> 33 #include <sys/pcicmu/pcicmu.h> 34 #include <sys/machsystm.h> 35 #include <sys/kstat.h> 36 37 /*LINTLIBRARY*/ 38 39 static kstat_t *pcmu_create_picN_kstat(char *, int, int, int, 40 pcmu_kev_mask_t *); 41 42 void 43 pcmu_kstat_create(pcmu_t *pcmu_p) 44 { 45 pcmu_add_upstream_kstat(pcmu_p); 46 } 47 48 void 49 pcmu_kstat_destroy(pcmu_t *pcmu_p) 50 { 51 pcmu_rem_upstream_kstat(pcmu_p); 52 } 53 54 void 55 pcmu_create_name_kstat(char *name, pcmu_ksinfo_t *pp, pcmu_kev_mask_t *ev) 56 { 57 int i; 58 59 for (i = 0; i < NUM_OF_PICS; i++) { 60 pp->pic_name_ksp[i] = pcmu_create_picN_kstat(name, 61 i, pp->pic_shift[i], pp->pic_no_evs, ev); 62 63 if (pp->pic_name_ksp[i] == NULL) { 64 cmn_err(CE_WARN, "pci: unable to create name kstat"); 65 } 66 } 67 } 68 69 void 70 pcmu_delete_name_kstat(pcmu_ksinfo_t *pp) 71 { 72 int i; 73 74 if (pp == NULL) { 75 return; 76 } 77 for (i = 0; i < NUM_OF_PICS; i++) { 78 if (pp->pic_name_ksp[i] != NULL) 79 kstat_delete(pp->pic_name_ksp[i]); 80 } 81 } 82 83 /* 84 * Create the picN kstat. Returns a pointer to the 85 * kstat which the driver must store to allow it 86 * to be deleted when necessary. 87 */ 88 static kstat_t * 89 pcmu_create_picN_kstat(char *mod_name, int pic, int pic_shift, 90 int num_ev, pcmu_kev_mask_t *ev_array) 91 { 92 struct kstat_named *pic_named_data; 93 int inst = 0; 94 int event; 95 char pic_name[30]; 96 kstat_t *picN_ksp = NULL; 97 98 (void) sprintf(pic_name, "pic%d", pic); 99 if ((picN_ksp = kstat_create(mod_name, inst, pic_name, 100 "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) { 101 cmn_err(CE_WARN, "%s %s : kstat create failed", 102 mod_name, pic_name); 103 104 /* 105 * It is up to the calling function to delete any kstats 106 * that may have been created already. We just 107 * return NULL to indicate an error has occured. 108 */ 109 return (NULL); 110 } 111 112 pic_named_data = (struct kstat_named *)picN_ksp->ks_data; 113 114 /* 115 * Write event names and their associated pcr masks. The 116 * last entry in the array (clear_pic) is added seperately 117 * below as the pic value must be inverted. 118 */ 119 for (event = 0; event < num_ev - 1; event++) { 120 pic_named_data[event].value.ui64 = 121 (ev_array[event].pcr_mask << pic_shift); 122 123 kstat_named_init(&pic_named_data[event], 124 ev_array[event].event_name, KSTAT_DATA_UINT64); 125 } 126 127 /* 128 * add the clear_pic entry. 129 */ 130 pic_named_data[event].value.ui64 = 131 (uint64_t)~(ev_array[event].pcr_mask << pic_shift); 132 133 kstat_named_init(&pic_named_data[event], 134 ev_array[event].event_name, KSTAT_DATA_UINT64); 135 136 kstat_install(picN_ksp); 137 return (picN_ksp); 138 } 139 140 /* 141 * Create the "counters" kstat. 142 */ 143 kstat_t *pcmu_create_cntr_kstat(pcmu_t *pcmu_p, char *name, 144 int num_pics, int (*update)(kstat_t *, int), 145 void *cntr_addr_p) 146 { 147 struct kstat_named *counters_named_data; 148 struct kstat *counters_ksp; 149 dev_info_t *dip = pcmu_p->pcmu_dip; 150 char *drv_name = (char *)ddi_driver_name(dip); 151 int drv_instance = ddi_get_instance(dip); 152 char pic_str[10]; 153 int i; 154 155 /* 156 * Size of kstat is num_pics + 1 as it 157 * also contains the %pcr 158 */ 159 if ((counters_ksp = kstat_create(name, drv_instance, 160 "counters", "bus", KSTAT_TYPE_NAMED, num_pics + 1, 161 KSTAT_FLAG_WRITABLE)) == NULL) { 162 cmn_err(CE_WARN, "%s%d counters kstat_create failed", 163 drv_name, drv_instance); 164 return (NULL); 165 } 166 167 counters_named_data = (struct kstat_named *)(counters_ksp->ks_data); 168 169 /* initialize the named kstats */ 170 kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64); 171 172 for (i = 0; i < num_pics; i++) { 173 (void) sprintf(pic_str, "pic%d", i); 174 kstat_named_init(&counters_named_data[i+1], 175 pic_str, KSTAT_DATA_UINT64); 176 } 177 178 /* 179 * Store the register offset's in the kstat's 180 * private field so that they are available 181 * to the update function. 182 */ 183 counters_ksp->ks_private = (void *)cntr_addr_p; 184 counters_ksp->ks_update = update; 185 kstat_install(counters_ksp); 186 return (counters_ksp); 187 } 188 189 /* 190 * kstat update function. Handles reads/writes 191 * from/to kstat. 192 */ 193 int 194 pcmu_cntr_kstat_update(kstat_t *ksp, int rw) 195 { 196 struct kstat_named *data_p; 197 pcmu_cntr_addr_t *cntr_addr_p = ksp->ks_private; 198 uint64_t pic; 199 200 data_p = (struct kstat_named *)ksp->ks_data; 201 if (rw == KSTAT_WRITE) { 202 *cntr_addr_p->pcr_addr = data_p[0].value.ui64; 203 return (0); 204 } else { 205 pic = *cntr_addr_p->pic_addr; 206 data_p[0].value.ui64 = *cntr_addr_p->pcr_addr; 207 208 /* pic0 : lo 32 bits */ 209 data_p[1].value.ui64 = (pic <<32) >> 32; 210 /* pic1 : hi 32 bits */ 211 data_p[2].value.ui64 = pic >> 32; 212 } 213 return (0); 214 } 215 216 /* 217 * kstat update function using physical addresses. 218 */ 219 int 220 pcmu_cntr_kstat_pa_update(kstat_t *ksp, int rw) 221 { 222 struct kstat_named *data_p; 223 pcmu_cntr_pa_t *cntr_pa_p = (pcmu_cntr_pa_t *)ksp->ks_private; 224 uint64_t pic; 225 226 data_p = (struct kstat_named *)ksp->ks_data; 227 228 if (rw == KSTAT_WRITE) { 229 stdphysio(cntr_pa_p->pcr_pa, data_p[0].value.ui64); 230 return (0); 231 } else { 232 pic = lddphysio(cntr_pa_p->pic_pa); 233 data_p[0].value.ui64 = lddphysio(cntr_pa_p->pcr_pa); 234 235 /* pic0 : lo 32 bits */ 236 data_p[1].value.ui64 = (pic << 32) >> 32; 237 /* pic1 : hi 32 bits */ 238 data_p[2].value.ui64 = pic >> 32; 239 } 240 return (0); 241 } 242 243 244 /* 245 * Matched with pcmu_add_upstream_kstat() 246 */ 247 void 248 pcmu_rem_upstream_kstat(pcmu_t *pcmu_p) 249 { 250 if (pcmu_p->pcmu_uksp != NULL) 251 kstat_delete(pcmu_p->pcmu_uksp); 252 pcmu_p->pcmu_uksp = NULL; 253 } 254