4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
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"
41 #define BYPASS_STATUS_OFF_MASK 3
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__); \
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__); \
62 * ixgbe_bypass_set_time - Set bypass FW time epoc.
64 * @hw: pointer to hardware structure
66 * This function with sync the FW date stamp with that of the
70 ixgbe_bypass_set_time(struct ixgbe_adapter *adapter)
74 struct ixgbe_hw *hw = &adapter->hw;
79 * Send the FW our current time and turn on time_valid and
82 mask = BYPASS_CTL1_TIME_M |
84 BYPASS_CTL1_OFFTRST_M;
85 value = (sec & BYPASS_CTL1_TIME_M) |
89 FUNC_PTR_OR_RET(adapter->bps.ops.bypass_set);
91 /* Store FW reset time (in seconds from epoch). */
92 adapter->bps.reset_tm = time(NULL);
95 adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
99 * ixgbe_bypass_init - Make some environment changes for bypass
101 * @adapter: pointer to ixgbe_adapter structure for access to state bits
103 * This function collects all the modifications needed by the bypass
107 ixgbe_bypass_init(struct rte_eth_dev *dev)
109 struct ixgbe_adapter *adapter;
112 adapter = IXGBE_DEV_TO_ADPATER(dev);
115 /* Only allow BYPASS ops on the first port */
116 if (hw->device_id != IXGBE_DEV_ID_82599_BYPASS ||
118 PMD_DRV_LOG(ERR, "bypass function is not supported on that device");
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;
128 /* set the time for logging. */
129 ixgbe_bypass_set_time(adapter);
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;
138 ixgbe_bypass_state_show(struct rte_eth_dev *dev, u32 *state)
144 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
147 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
149 cmd = BYPASS_PAGE_CTL0;
150 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
152 /* Assume bypass_rw didn't error out, if it did state will
155 *state = (by_ctl >> BYPASS_STATUS_OFF_SHIFT) & BYPASS_STATUS_OFF_MASK;
162 ixgbe_bypass_state_store(struct rte_eth_dev *dev, u32 *new_state)
164 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
169 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
171 /* Set the new state */
172 ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
173 BYPASS_MODE_OFF_M, *new_state);
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);
187 ixgbe_bypass_event_show(struct rte_eth_dev *dev, u32 event,
195 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
198 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
200 cmd = BYPASS_PAGE_CTL0;
201 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
203 /* Assume bypass_rw didn't error out, if it did event will
207 case BYPASS_EVENT_WDT_TO:
208 shift = BYPASS_WDTIMEOUT_SHIFT;
210 case BYPASS_EVENT_MAIN_ON:
211 shift = BYPASS_MAIN_ON_SHIFT;
213 case BYPASS_EVENT_MAIN_OFF:
214 shift = BYPASS_MAIN_OFF_SHIFT;
216 case BYPASS_EVENT_AUX_ON:
217 shift = BYPASS_AUX_ON_SHIFT;
219 case BYPASS_EVENT_AUX_OFF:
220 shift = BYPASS_AUX_OFF_SHIFT;
226 *state = (by_ctl >> shift) & 0x3;
232 ixgbe_bypass_event_store(struct rte_eth_dev *dev, u32 event,
239 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
242 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
245 case BYPASS_EVENT_WDT_TO:
246 off = BYPASS_WDTIMEOUT_M;
247 status = state << BYPASS_WDTIMEOUT_SHIFT;
249 case BYPASS_EVENT_MAIN_ON:
250 off = BYPASS_MAIN_ON_M;
251 status = state << BYPASS_MAIN_ON_SHIFT;
253 case BYPASS_EVENT_MAIN_OFF:
254 off = BYPASS_MAIN_OFF_M;
255 status = state << BYPASS_MAIN_OFF_SHIFT;
257 case BYPASS_EVENT_AUX_ON:
258 off = BYPASS_AUX_ON_M;
259 status = state << BYPASS_AUX_ON_SHIFT;
261 case BYPASS_EVENT_AUX_OFF:
262 off = BYPASS_AUX_OFF_M;
263 status = state << BYPASS_AUX_OFF_SHIFT;
269 ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
276 ixgbe_bypass_wd_timeout_store(struct rte_eth_dev *dev, u32 timeout)
282 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
285 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
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;
292 /* set time out value */
293 mask = BYPASS_WDT_VALUE_M;
295 /* enable the timer */
296 status = timeout << BYPASS_WDT_TIME_SHIFT;
297 status |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
298 mask |= BYPASS_WDT_ENABLE_M;
301 ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
308 ixgbe_bypass_ver_show(struct rte_eth_dev *dev, u32 *ver)
314 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
317 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
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);
326 /* wait for the write to stick */
329 /* Now read the results */
331 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
335 *ver = status & BYPASS_CTL2_DATA_M; /* only one byte of date */
342 ixgbe_bypass_wd_timeout_show(struct rte_eth_dev *dev, u32 *wd_timeout)
349 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
352 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
354 cmd = BYPASS_PAGE_CTL0;
355 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
357 wdg = by_ctl & BYPASS_WDT_ENABLE_M;
359 *wd_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
361 *wd_timeout = (by_ctl >> BYPASS_WDT_TIME_SHIFT) &
368 ixgbe_bypass_wd_reset(struct rte_eth_dev *dev)
376 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
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);
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.
388 cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
390 /* Resync the FW time while writing to CTL1 anyway */
391 adapter->bps.reset_tm = time(NULL);
394 cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
396 /* reset FW timer offset since we are resetting the clock */
397 cmd |= BYPASS_CTL1_OFFTRST;
399 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
401 /* Read until it matches what we wrote, or we time out */
404 ret_val = IXGBE_BYPASS_FW_WRITE_FAILURE;
408 if (adapter->bps.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &status)) {
409 ret_val = IXGBE_ERR_INVALID_ARGUMENT;
412 } while (!adapter->bps.ops.bypass_valid_rd(cmd, status));