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