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