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