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