Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <time.h>
6 : : #include <ethdev_driver.h>
7 : : #include "ixgbe_ethdev.h"
8 : : #include "ixgbe_bypass_api.h"
9 : : #include "rte_pmd_ixgbe.h"
10 : :
11 : : #define BYPASS_STATUS_OFF_MASK 3
12 : :
13 : : /* Macros to check for invalid function pointers. */
14 : : #define FUNC_PTR_OR_ERR_RET(func, retval) do { \
15 : : if ((func) == NULL) { \
16 : : PMD_DRV_LOG(ERR, "%s:%d function not supported", \
17 : : __func__, __LINE__); \
18 : : return retval; \
19 : : } \
20 : : } while (0)
21 : :
22 : : #define FUNC_PTR_OR_RET(func) do { \
23 : : if ((func) == NULL) { \
24 : : PMD_DRV_LOG(ERR, "%s:%d function not supported", \
25 : : __func__, __LINE__); \
26 : : return; \
27 : : } \
28 : : } while (0)
29 : :
30 : :
31 : : /**
32 : : * ixgbe_bypass_set_time - Set bypass FW time epoc.
33 : : *
34 : : * @hw: pointer to hardware structure
35 : : *
36 : : * This function with sync the FW date stamp with that of the
37 : : * system clock.
38 : : **/
39 : : static void
40 : 0 : ixgbe_bypass_set_time(struct ixgbe_adapter *adapter)
41 : : {
42 : : u32 mask, value;
43 : : u32 sec;
44 : 0 : struct ixgbe_hw *hw = &adapter->hw;
45 : :
46 : : sec = 0;
47 : :
48 : : /*
49 : : * Send the FW our current time and turn on time_valid and
50 : : * timer_reset bits.
51 : : */
52 : : mask = BYPASS_CTL1_TIME_M |
53 : : BYPASS_CTL1_VALID_M |
54 : : BYPASS_CTL1_OFFTRST_M;
55 : : value = (sec & BYPASS_CTL1_TIME_M) |
56 : : BYPASS_CTL1_VALID |
57 : : BYPASS_CTL1_OFFTRST;
58 : :
59 [ # # ]: 0 : FUNC_PTR_OR_RET(adapter->bps.ops.bypass_set);
60 : :
61 : : /* Store FW reset time (in seconds from epoch). */
62 : 0 : adapter->bps.reset_tm = time(NULL);
63 : :
64 : : /* reset FW timer. */
65 : 0 : adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
66 : : }
67 : :
68 : : /**
69 : : * ixgbe_bypass_init - Make some environment changes for bypass
70 : : *
71 : : * @adapter: pointer to ixgbe_adapter structure for access to state bits
72 : : *
73 : : * This function collects all the modifications needed by the bypass
74 : : * driver.
75 : : **/
76 : : void
77 : 0 : ixgbe_bypass_init(struct rte_eth_dev *dev)
78 : : {
79 : : struct ixgbe_adapter *adapter;
80 : : struct ixgbe_hw *hw;
81 : :
82 : 0 : adapter = IXGBE_DEV_TO_ADPATER(dev);
83 : : hw = &adapter->hw;
84 : :
85 : : /* Only allow BYPASS ops on the first port */
86 [ # # ]: 0 : if (hw->device_id != IXGBE_DEV_ID_82599_BYPASS ||
87 [ # # ]: 0 : hw->bus.func != 0) {
88 : 0 : PMD_DRV_LOG(ERR, "bypass function is not supported on that device");
89 : 0 : return;
90 : : }
91 : :
92 : : /* set bypass ops. */
93 : 0 : adapter->bps.ops.bypass_rw = &ixgbe_bypass_rw_generic;
94 : 0 : adapter->bps.ops.bypass_valid_rd = &ixgbe_bypass_valid_rd_generic;
95 : 0 : adapter->bps.ops.bypass_set = &ixgbe_bypass_set_generic;
96 : 0 : adapter->bps.ops.bypass_rd_eep = &ixgbe_bypass_rd_eep_generic;
97 : :
98 : : /* set the time for logging. */
99 : 0 : ixgbe_bypass_set_time(adapter);
100 : :
101 : : /* Don't have the SDP to the laser */
102 : 0 : hw->mac.ops.disable_tx_laser = NULL;
103 : 0 : hw->mac.ops.enable_tx_laser = NULL;
104 : 0 : hw->mac.ops.flap_tx_laser = NULL;
105 : : }
106 : :
107 : : s32
108 : 0 : ixgbe_bypass_state_show(struct rte_eth_dev *dev, u32 *state)
109 : : {
110 : : struct ixgbe_hw *hw;
111 : : s32 ret_val;
112 : : u32 cmd;
113 : 0 : u32 by_ctl = 0;
114 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
115 : :
116 : 0 : hw = &adapter->hw;
117 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
118 : :
119 : : cmd = BYPASS_PAGE_CTL0;
120 : 0 : ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
121 : :
122 : : /* Assume bypass_rw didn't error out, if it did state will
123 : : * be ignored anyway.
124 : : */
125 : 0 : *state = (by_ctl >> BYPASS_STATUS_OFF_SHIFT) & BYPASS_STATUS_OFF_MASK;
126 : :
127 : 0 : return ret_val;
128 : : }
129 : :
130 : :
131 : : s32
132 : 0 : ixgbe_bypass_state_store(struct rte_eth_dev *dev, u32 *new_state)
133 : : {
134 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
135 : : struct ixgbe_hw *hw;
136 : : s32 ret_val;
137 : :
138 : 0 : hw = &adapter->hw;
139 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
140 : :
141 : : /* Set the new state */
142 : 0 : ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
143 : : BYPASS_MODE_OFF_M, *new_state);
144 [ # # ]: 0 : if (ret_val)
145 : 0 : goto exit;
146 : :
147 : : /* Set AUTO back on so FW can receive events */
148 : 0 : ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
149 : : BYPASS_MODE_OFF_M, BYPASS_AUTO);
150 : :
151 : : exit:
152 : : return ret_val;
153 : :
154 : : }
155 : :
156 : : s32
157 : 0 : ixgbe_bypass_event_show(struct rte_eth_dev *dev, u32 event,
158 : : u32 *state)
159 : : {
160 : : struct ixgbe_hw *hw;
161 : : s32 ret_val;
162 : : u32 shift;
163 : : u32 cmd;
164 : 0 : u32 by_ctl = 0;
165 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
166 : :
167 : 0 : hw = &adapter->hw;
168 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
169 : :
170 : : cmd = BYPASS_PAGE_CTL0;
171 : 0 : ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
172 : :
173 : : /* Assume bypass_rw didn't error out, if it did event will
174 : : * be ignored anyway.
175 : : */
176 : : switch (event) {
177 : : case BYPASS_EVENT_WDT_TO:
178 : : shift = BYPASS_WDTIMEOUT_SHIFT;
179 : : break;
180 : : case BYPASS_EVENT_MAIN_ON:
181 : : shift = BYPASS_MAIN_ON_SHIFT;
182 : : break;
183 : : case BYPASS_EVENT_MAIN_OFF:
184 : : shift = BYPASS_MAIN_OFF_SHIFT;
185 : : break;
186 : : case BYPASS_EVENT_AUX_ON:
187 : : shift = BYPASS_AUX_ON_SHIFT;
188 : : break;
189 : : case BYPASS_EVENT_AUX_OFF:
190 : : shift = BYPASS_AUX_OFF_SHIFT;
191 : : break;
192 : : default:
193 : : return EINVAL;
194 : : }
195 : :
196 : 0 : *state = (by_ctl >> shift) & 0x3;
197 : :
198 : 0 : return ret_val;
199 : : }
200 : :
201 : : s32
202 : 0 : ixgbe_bypass_event_store(struct rte_eth_dev *dev, u32 event,
203 : : u32 state)
204 : : {
205 : : struct ixgbe_hw *hw;
206 : : u32 status;
207 : : u32 off;
208 : : s32 ret_val;
209 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
210 : :
211 : 0 : hw = &adapter->hw;
212 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
213 : :
214 [ # # # # : 0 : switch (event) {
# # ]
215 : 0 : case BYPASS_EVENT_WDT_TO:
216 : : off = BYPASS_WDTIMEOUT_M;
217 : 0 : status = state << BYPASS_WDTIMEOUT_SHIFT;
218 : 0 : break;
219 : 0 : case BYPASS_EVENT_MAIN_ON:
220 : : off = BYPASS_MAIN_ON_M;
221 : 0 : status = state << BYPASS_MAIN_ON_SHIFT;
222 : 0 : break;
223 : 0 : case BYPASS_EVENT_MAIN_OFF:
224 : : off = BYPASS_MAIN_OFF_M;
225 : 0 : status = state << BYPASS_MAIN_OFF_SHIFT;
226 : 0 : break;
227 : 0 : case BYPASS_EVENT_AUX_ON:
228 : : off = BYPASS_AUX_ON_M;
229 : 0 : status = state << BYPASS_AUX_ON_SHIFT;
230 : 0 : break;
231 : 0 : case BYPASS_EVENT_AUX_OFF:
232 : : off = BYPASS_AUX_OFF_M;
233 : 0 : status = state << BYPASS_AUX_OFF_SHIFT;
234 : 0 : break;
235 : : default:
236 : : return EINVAL;
237 : : }
238 : :
239 : 0 : ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
240 : : off, status);
241 : :
242 : 0 : return ret_val;
243 : : }
244 : :
245 : : s32
246 : 0 : ixgbe_bypass_wd_timeout_store(struct rte_eth_dev *dev, u32 timeout)
247 : : {
248 : : struct ixgbe_hw *hw;
249 : : u32 status;
250 : : u32 mask;
251 : : s32 ret_val;
252 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
253 : :
254 : 0 : hw = &adapter->hw;
255 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
256 : :
257 : : /* disable the timer with timeout of zero */
258 [ # # ]: 0 : if (timeout == RTE_PMD_IXGBE_BYPASS_TMT_OFF) {
259 : : status = 0x0; /* WDG enable off */
260 : : mask = BYPASS_WDT_ENABLE_M;
261 : : } else {
262 : : /* set time out value */
263 : : mask = BYPASS_WDT_VALUE_M;
264 : :
265 : : /* enable the timer */
266 : 0 : status = timeout << BYPASS_WDT_TIME_SHIFT;
267 : 0 : status |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
268 : : mask |= BYPASS_WDT_ENABLE_M;
269 : : }
270 : :
271 : 0 : ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
272 : : mask, status);
273 : :
274 : 0 : return ret_val;
275 : : }
276 : :
277 : : s32
278 : 0 : ixgbe_bypass_ver_show(struct rte_eth_dev *dev, u32 *ver)
279 : : {
280 : : struct ixgbe_hw *hw;
281 : : u32 cmd;
282 : : u32 status;
283 : : s32 ret_val;
284 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
285 : :
286 : 0 : hw = &adapter->hw;
287 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
288 : :
289 : : cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
290 : : cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) &
291 : : BYPASS_CTL2_OFFSET_M;
292 : 0 : ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
293 [ # # ]: 0 : if (ret_val)
294 : 0 : goto exit;
295 : :
296 : : /* wait for the write to stick */
297 : 0 : msleep(100);
298 : :
299 : : /* Now read the results */
300 : : cmd &= ~BYPASS_WE;
301 : 0 : ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
302 [ # # ]: 0 : if (ret_val)
303 : 0 : goto exit;
304 : :
305 : 0 : *ver = status & BYPASS_CTL2_DATA_M; /* only one byte of date */
306 : :
307 : : exit:
308 : : return ret_val;
309 : : }
310 : :
311 : : s32
312 : 0 : ixgbe_bypass_wd_timeout_show(struct rte_eth_dev *dev, u32 *wd_timeout)
313 : : {
314 : : struct ixgbe_hw *hw;
315 : 0 : u32 by_ctl = 0;
316 : : u32 cmd;
317 : : u32 wdg;
318 : : s32 ret_val;
319 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
320 : :
321 : 0 : hw = &adapter->hw;
322 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
323 : :
324 : : cmd = BYPASS_PAGE_CTL0;
325 : 0 : ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
326 : :
327 : 0 : wdg = by_ctl & BYPASS_WDT_ENABLE_M;
328 [ # # ]: 0 : if (!wdg)
329 : 0 : *wd_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
330 : : else
331 : 0 : *wd_timeout = (by_ctl >> BYPASS_WDT_TIME_SHIFT) &
332 : : BYPASS_WDT_MASK;
333 : :
334 : : return ret_val;
335 : : }
336 : :
337 : : s32
338 : 0 : ixgbe_bypass_wd_reset(struct rte_eth_dev *dev)
339 : : {
340 : : u32 cmd;
341 : : u32 status;
342 : : u32 sec;
343 : : u32 count = 0;
344 : : s32 ret_val;
345 : : struct ixgbe_hw *hw;
346 : 0 : struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
347 : :
348 : 0 : hw = &adapter->hw;
349 : :
350 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
351 [ # # ]: 0 : FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_valid_rd, -ENOTSUP);
352 : :
353 : : /* Use the lower level bit-bang functions since we don't need
354 : : * to read the register first to get it's current state as we
355 : : * are setting every thing in this write.
356 : : */
357 : : /* Set up WD pet */
358 : : cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
359 : :
360 : : /* Resync the FW time while writing to CTL1 anyway */
361 : 0 : adapter->bps.reset_tm = time(NULL);
362 : : sec = 0;
363 : :
364 : : cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
365 : :
366 : : /* reset FW timer offset since we are resetting the clock */
367 : : cmd |= BYPASS_CTL1_OFFTRST;
368 : :
369 : 0 : ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
370 : :
371 : : /* Read until it matches what we wrote, or we time out */
372 : : do {
373 [ # # ]: 0 : if (count++ > 10) {
374 : : ret_val = IXGBE_BYPASS_FW_WRITE_FAILURE;
375 : : break;
376 : : }
377 : :
378 [ # # ]: 0 : if (adapter->bps.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &status)) {
379 : : ret_val = IXGBE_ERR_INVALID_ARGUMENT;
380 : : break;
381 : : }
382 [ # # ]: 0 : } while (!adapter->bps.ops.bypass_valid_rd(cmd, status));
383 : :
384 : : return ret_val;
385 : : }
|