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
n2piupc_biterr_attach(void ** arg)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
n2piupc_biterr_detach(void * arg)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
n2piupc_biterr_write(n2piupc_t * n2piupc_p,int regid,uint64_t data_in)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
n2piupc_biterr_read(n2piupc_t * n2piupc_p,int regid,uint64_t * data)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