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 /* 23 * Copyright 2006 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 * "Virtual register" implementation for the bit error performance counters. 31 * See n2piupc-biterr.h for a description of the registers. 32 */ 33 34 #include <sys/types.h> 35 #include "n2piupc_acc.h" 36 #include "n2piupc_tables.h" 37 #include "n2piupc.h" 38 #include "n2piupc_biterr.h" 39 40 /* The real register's Link Bit Error fields are 6 bits wide. */ 41 #define REAL_BE2_8_10_MASK 0x3full 42 43 typedef struct { 44 uint64_t sw_biterr_events; 45 } n2piupc_sw_biterr_t; 46 47 /* 48 * Per-instance initialization required by this module. Returns an arg which 49 * is opaque to the outside. 50 */ 51 int 52 n2piupc_biterr_attach(void **arg) 53 { 54 *arg = kmem_zalloc(sizeof (n2piupc_sw_biterr_t), KM_SLEEP); 55 return (DDI_SUCCESS); 56 } 57 58 /* 59 * Per-instance cleanup. Takes opaque arg delivered by n2piupc_biterr_attach. 60 */ 61 void 62 n2piupc_biterr_detach(void *arg) 63 { 64 if (arg != NULL) 65 kmem_free(arg, sizeof (n2piupc_sw_biterr_t)); 66 } 67 68 /* 69 * Exported write interface. Takes same args as n2piupc_write. Translates to 70 * real register interfaces. 71 */ 72 int 73 n2piupc_biterr_write(n2piupc_t *n2piupc_p, int regid, uint64_t data_in) 74 { 75 uint64_t dev_data; /* Write this to the device. */ 76 cntr_handle_t handle = n2piupc_p->n2piupc_handle; 77 n2piupc_sw_biterr_t *biterr_p = n2piupc_p->n2piupc_biterr_p; 78 int rval = SUCCESS; 79 80 switch (regid) { 81 82 case SW_N2PIU_BITERR_SEL: 83 /* 84 * Write out only the biterr enable to the device. 85 * Note: the entire register (which has events for PIC3 as well) 86 * will be saved in sw_biterr_events. 87 */ 88 dev_data = data_in & BTERR_CTR_ENABLE; 89 break; 90 91 case SW_N2PIU_BITERR_CLR: 92 /* Write out existing enable bit ORed with the zero request. */ 93 dev_data = (biterr_p->sw_biterr_events & BTERR_CTR_ENABLE) | 94 (data_in & BTERR_CTR_CLR); 95 break; 96 97 /* 98 * All other registers, including the virtual biterr counter registers 99 * which are read-only, are not legal. 100 */ 101 default: 102 N2PIUPC_DBG1("n2piupc_biterr_write: regid %d is invalid\n", 103 regid); 104 return (EIO); 105 } 106 107 /* 108 * Enable and clear requests go to counter 1. Note that bits 62 and 63 109 * of the real counter 1 maps to same bits of the respective virtual 110 * clear and select registers. 111 */ 112 if (n2piupc_set_perfreg(handle, HVIO_N2PIU_PERFREG_BITERR_CNT1, 113 dev_data) != H_EOK) { 114 rval = EIO; 115 116 /* 117 * Extra handling for virtual select register: Save all the data 118 * (events) for CNT2 as well as the overall biterr enable. 119 */ 120 } else if (regid == SW_N2PIU_BITERR_SEL) { 121 N2PIUPC_DBG1( 122 "n2piupc_biterr_write: Saving 0x%lx to bterr_sel, " 123 "write 0x%lx to dev\n", data_in, dev_data); 124 biterr_p->sw_biterr_events = data_in; 125 } 126 127 N2PIUPC_DBG2("n2piupc_biterr_write: eventsreg:0x%lx, status:%d\n", 128 biterr_p->sw_biterr_events, rval); 129 return (rval); 130 } 131 132 133 /* 134 * Exported read interface. Takes same args as n2piupc_read. Translates to 135 * real register interfaces. 136 */ 137 int 138 n2piupc_biterr_read(n2piupc_t *n2piupc_p, int regid, uint64_t *data) 139 { 140 uint64_t raw_data; 141 uint64_t biterr_cnt2_events; 142 n2piupc_sw_biterr_t *biterr_p = n2piupc_p->n2piupc_biterr_p; 143 cntr_handle_t handle = n2piupc_p->n2piupc_handle; 144 int rval = SUCCESS; 145 146 N2PIUPC_DBG1("n2piupc_biterr_read enter: handle:0x%lx, regid:%d\n", 147 handle, regid); 148 149 switch (regid) { 150 case SW_N2PIU_BITERR_CNT1_DATA: 151 /* Virtual counter 1 maps directly to its real equivalent. */ 152 if (n2piupc_get_perfreg(handle, HVIO_N2PIU_PERFREG_BITERR_CNT1, 153 &raw_data) != H_EOK) { 154 rval = EIO; 155 } 156 break; 157 158 case SW_N2PIU_BITERR_CNT2_DATA: 159 160 biterr_cnt2_events = biterr_p->sw_biterr_events & 161 (BTERR_CTR_3_EVT_MASK << BTERR_CTR_3_EVT_OFF); 162 163 /* 164 * Virtual counter 2 can return one lane of data at a time, or 165 * all lanes at once, depending on the event selected for it. 166 */ 167 N2PIUPC_DBG1("n2piupc_biterr_read: counter2 data, evt:%ld\n", 168 biterr_cnt2_events); 169 170 /* No event selected, return 0 */ 171 if (biterr_cnt2_events == BTERR3_EVT_ENC_NONE) { 172 *data = 0ull; 173 break; 174 175 } 176 177 /* All other events require reading real register. */ 178 if (n2piupc_get_perfreg(handle, HVIO_N2PIU_PERFREG_BITERR_CNT2, 179 &raw_data) != H_EOK) { 180 rval = EIO; 181 break; 182 } 183 184 N2PIUPC_DBG1("n2piupc_read: n2piupc_get_perfreg: data:0x%lx\n", 185 raw_data); 186 187 /* 188 * Note that biterr counter 2 supports the register which 189 * busstat calls PIC3. This is why events are BTERR3_... 190 */ 191 192 switch (biterr_cnt2_events) { 193 194 case BTERR3_EVT_ENC_ALL: 195 /* Return the whole register if all lanes requested. */ 196 *data = raw_data; 197 break; 198 199 case BTERR3_EVT_ENC_LANE_0: 200 case BTERR3_EVT_ENC_LANE_1: 201 case BTERR3_EVT_ENC_LANE_2: 202 case BTERR3_EVT_ENC_LANE_3: 203 case BTERR3_EVT_ENC_LANE_4: 204 case BTERR3_EVT_ENC_LANE_5: 205 case BTERR3_EVT_ENC_LANE_6: 206 case BTERR3_EVT_ENC_LANE_7: 207 /* 208 * Return an individual lane. Each lane is a 6 bit 209 * field with lsb lining up with byte lsbs. 210 */ 211 *data = raw_data >> 212 ((biterr_cnt2_events - BTERR3_EVT_ENC_LANE_0) * 8) & 213 REAL_BE2_8_10_MASK; 214 N2PIUPC_DBG2( 215 "DATA: raw:0x%lx, >> (%ld * 8) & 0x%llx = 0x%lx\n", 216 raw_data, 217 (biterr_cnt2_events - BTERR3_EVT_ENC_LANE_0), 218 REAL_BE2_8_10_MASK, *data); 219 break; 220 221 default: 222 cmn_err(CE_WARN, 223 "n2piupc: Invalid bterr PIC3 event: 0x%lx\n", 224 biterr_cnt2_events); 225 rval = EINVAL; 226 break; 227 } 228 break; 229 230 case SW_N2PIU_BITERR_SEL: 231 /* 232 * Return the virtual select register data. 233 * No need to read the device. 234 */ 235 N2PIUPC_DBG2("n2piupc_biterr_read: returning events: 0x%lx\n", 236 biterr_p->sw_biterr_events); 237 *data = biterr_p->sw_biterr_events; 238 break; 239 240 default: 241 N2PIUPC_DBG1("n2piupc_biterr_read: invalid regid: %d\n", regid); 242 rval = EIO; 243 break; 244 } 245 246 N2PIUPC_DBG1("n2piupc_read exit: data:0x%lx, status:%d\n", *data, 247 rval); 248 249 return (rval); 250 } 251