xref: /titanic_51/usr/src/uts/sun4v/io/n2piupc/n2piupc_biterr.c (revision ea1a228c80597366447774aa1988868492330eb5)
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