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