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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2014 Intel Corporation
*/
#ifndef _IXGBE_BYPASS_API_H_
#define _IXGBE_BYPASS_API_H_
#ifdef RTE_LIBRTE_IXGBE_BYPASS
#include "ixgbe_bypass_defines.h"
/**
* ixgbe_bypass_rw_generic - Bit bang data into by_pass FW
*
* @hw: pointer to hardware structure
* @cmd: Command we send to the FW
* @status: The reply from the FW
*
* Bit-bangs the cmd to the by_pass FW status points to what is returned.
**/
#define IXGBE_BYPASS_BB_WAIT 1
static s32 ixgbe_bypass_rw_generic(struct ixgbe_hw *hw, u32 cmd, u32 *status)
{
int i;
u32 sck, sdi, sdo, dir_sck, dir_sdi, dir_sdo;
u32 esdp;
if (!status)
return IXGBE_ERR_PARAM;
*status = 0;
/* SDP vary by MAC type */
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
sck = IXGBE_ESDP_SDP7;
sdi = IXGBE_ESDP_SDP0;
sdo = IXGBE_ESDP_SDP6;
dir_sck = IXGBE_ESDP_SDP7_DIR;
dir_sdi = IXGBE_ESDP_SDP0_DIR;
dir_sdo = IXGBE_ESDP_SDP6_DIR;
break;
case ixgbe_mac_X540:
sck = IXGBE_ESDP_SDP2;
sdi = IXGBE_ESDP_SDP0;
sdo = IXGBE_ESDP_SDP1;
dir_sck = IXGBE_ESDP_SDP2_DIR;
dir_sdi = IXGBE_ESDP_SDP0_DIR;
dir_sdo = IXGBE_ESDP_SDP1_DIR;
break;
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
case ixgbe_mac_X550EM_a:
sck = IXGBE_ESDP_SDP2;
sdi = IXGBE_ESDP_SDP0;
sdo = IXGBE_ESDP_SDP1;
dir_sck = IXGBE_ESDP_SDP2_DIR;
dir_sdi = IXGBE_ESDP_SDP0_DIR;
dir_sdo = IXGBE_ESDP_SDP1_DIR;
break;
default:
return IXGBE_ERR_DEVICE_NOT_SUPPORTED;
}
/* Set SDP pins direction */
esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
esdp |= dir_sck; /* SCK as output */
esdp |= dir_sdi; /* SDI as output */
esdp &= ~dir_sdo; /* SDO as input */
esdp |= sck;
esdp |= sdi;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
// TODO:
msleep(IXGBE_BYPASS_BB_WAIT);
/* Generate start condition */
esdp &= ~sdi;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
msleep(IXGBE_BYPASS_BB_WAIT);
esdp &= ~sck;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
msleep(IXGBE_BYPASS_BB_WAIT);
/* Clock out the new control word and clock in the status */
for (i = 0; i < 32; i++) {
if ((cmd >> (31 - i)) & 0x01) {
esdp |= sdi;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
} else {
esdp &= ~sdi;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
}
IXGBE_WRITE_FLUSH(hw);
msleep(IXGBE_BYPASS_BB_WAIT);
esdp |= sck;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
msleep(IXGBE_BYPASS_BB_WAIT);
esdp &= ~sck;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
msleep(IXGBE_BYPASS_BB_WAIT);
esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
if (esdp & sdo)
*status = (*status << 1) | 0x01;
else
*status = (*status << 1) | 0x00;
msleep(IXGBE_BYPASS_BB_WAIT);
}
/* stop condition */
esdp |= sck;
esdp &= ~sdi;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
msleep(IXGBE_BYPASS_BB_WAIT);
esdp |= sdi;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
/* set the page bits to match the cmd that the status it belongs to */
*status = (*status & 0x3fffffff) | (cmd & 0xc0000000);
return 0;
}
/**
* ixgbe_bypass_valid_rd_generic - Verify valid return from bit-bang.
*
* If we send a write we can't be sure it took until we can read back
* that same register. It can be a problem as some of the feilds may
* for valid reasons change between the time wrote the register and
* we read it again to verify. So this function check everything we
* can check and then assumes it worked.
*
* @u32 in_reg - The register cmd for the bit-bang read.
* @u32 out_reg - The register returned from a bit-bang read.
**/
static bool ixgbe_bypass_valid_rd_generic(u32 in_reg, u32 out_reg)
{
u32 mask;
/* Page must match for all control pages */
if ((in_reg & BYPASS_PAGE_M) != (out_reg & BYPASS_PAGE_M))
return false;
switch (in_reg & BYPASS_PAGE_M) {
case BYPASS_PAGE_CTL0:
/* All the following can't change since the last write
* - All the event actions
* - The timeout value
*/
mask = BYPASS_AUX_ON_M | BYPASS_MAIN_ON_M |
BYPASS_MAIN_OFF_M | BYPASS_AUX_OFF_M |
BYPASS_WDTIMEOUT_M |
BYPASS_WDT_VALUE_M;
if ((out_reg & mask) != (in_reg & mask))
return false;
/* 0x0 is never a valid value for bypass status */
if (!(out_reg & BYPASS_STATUS_OFF_M))
return false;
break;
case BYPASS_PAGE_CTL1:
/* All the following can't change since the last write
* - time valid bit
* - time we last sent
*/
mask = BYPASS_CTL1_VALID_M | BYPASS_CTL1_TIME_M;
if ((out_reg & mask) != (in_reg & mask))
return false;
break;
case BYPASS_PAGE_CTL2:
/* All we can check in this page is control number
* which is already done above.
*/
break;
}
/* We are as sure as we can be return true */
return true;
}
/**
* ixgbe_bypass_set_generic - Set a bypass field in the FW CTRL Regiter.
*
* @hw: pointer to hardware structure
* @cmd: The control word we are setting.
* @event: The event we are setting in the FW. This also happens to
* be the mask for the event we are setting (handy)
* @action: The action we set the event to in the FW. This is in a
* bit field that happens to be what we want to put in
* the event spot (also handy)
**/
static s32 ixgbe_bypass_set_generic(struct ixgbe_hw *hw, u32 ctrl, u32 event,
u32 action)
{
u32 by_ctl = 0;
u32 cmd, verify;
u32 count = 0;
/* Get current values */
cmd = ctrl; /* just reading only need control number */
if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl))
return IXGBE_ERR_INVALID_ARGUMENT;
/* Set to new action */
cmd = (by_ctl & ~event) | BYPASS_WE | action;
if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl))
return IXGBE_ERR_INVALID_ARGUMENT;
/* Page 0 force a FW eeprom write which is slow so verify */
if ((cmd & BYPASS_PAGE_M) == BYPASS_PAGE_CTL0) {
verify = BYPASS_PAGE_CTL0;
do {
if (count++ > 5)
return IXGBE_BYPASS_FW_WRITE_FAILURE;
if (ixgbe_bypass_rw_generic(hw, verify, &by_ctl))
return IXGBE_ERR_INVALID_ARGUMENT;
} while (!ixgbe_bypass_valid_rd_generic(cmd, by_ctl));
} else {
/* We have give the FW time for the write to stick */
msleep(100);
}
return 0;
}
/**
* ixgbe_bypass_rd_eep_generic - Read the bypass FW eeprom address.
*
* @hw: pointer to hardware structure
* @addr: The bypass eeprom address to read.
* @value: The 8b of data at the address above.
**/
static s32 ixgbe_bypass_rd_eep_generic(struct ixgbe_hw *hw, u32 addr, u8 *value)
{
u32 cmd;
u32 status;
/* send the request */
cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
cmd |= (addr << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
if (ixgbe_bypass_rw_generic(hw, cmd, &status))
return IXGBE_ERR_INVALID_ARGUMENT;
/* We have give the FW time for the write to stick */
msleep(100);
/* now read the results */
cmd &= ~BYPASS_WE;
if (ixgbe_bypass_rw_generic(hw, cmd, &status))
return IXGBE_ERR_INVALID_ARGUMENT;
*value = status & BYPASS_CTL2_DATA_M;
return 0;
}
#endif /* RTE_LIBRTE_IXGBE_BYPASS */
#endif /* _IXGBE_BYPASS_API_H_ */
|