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