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