1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
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"
12 #define BYPASS_STATUS_OFF_MASK 3
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__); \
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__); \
33 * ixgbe_bypass_set_time - Set bypass FW time epoc.
35 * @hw: pointer to hardware structure
37 * This function with sync the FW date stamp with that of the
41 ixgbe_bypass_set_time(struct ixgbe_adapter *adapter)
45 struct ixgbe_hw *hw = &adapter->hw;
50 * Send the FW our current time and turn on time_valid and
53 mask = BYPASS_CTL1_TIME_M |
55 BYPASS_CTL1_OFFTRST_M;
56 value = (sec & BYPASS_CTL1_TIME_M) |
60 FUNC_PTR_OR_RET(adapter->bps.ops.bypass_set);
62 /* Store FW reset time (in seconds from epoch). */
63 adapter->bps.reset_tm = time(NULL);
66 adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
70 * ixgbe_bypass_init - Make some environment changes for bypass
72 * @adapter: pointer to ixgbe_adapter structure for access to state bits
74 * This function collects all the modifications needed by the bypass
78 ixgbe_bypass_init(struct rte_eth_dev *dev)
80 struct ixgbe_adapter *adapter;
83 adapter = IXGBE_DEV_TO_ADPATER(dev);
86 /* Only allow BYPASS ops on the first port */
87 if (hw->device_id != IXGBE_DEV_ID_82599_BYPASS ||
89 PMD_DRV_LOG(ERR, "bypass function is not supported on that device");
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;
99 /* set the time for logging. */
100 ixgbe_bypass_set_time(adapter);
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;
109 ixgbe_bypass_state_show(struct rte_eth_dev *dev, u32 *state)
115 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
118 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
120 cmd = BYPASS_PAGE_CTL0;
121 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
123 /* Assume bypass_rw didn't error out, if it did state will
126 *state = (by_ctl >> BYPASS_STATUS_OFF_SHIFT) & BYPASS_STATUS_OFF_MASK;
133 ixgbe_bypass_state_store(struct rte_eth_dev *dev, u32 *new_state)
135 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
140 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
142 /* Set the new state */
143 ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
144 BYPASS_MODE_OFF_M, *new_state);
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);
158 ixgbe_bypass_event_show(struct rte_eth_dev *dev, u32 event,
166 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
169 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
171 cmd = BYPASS_PAGE_CTL0;
172 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
174 /* Assume bypass_rw didn't error out, if it did event will
178 case BYPASS_EVENT_WDT_TO:
179 shift = BYPASS_WDTIMEOUT_SHIFT;
181 case BYPASS_EVENT_MAIN_ON:
182 shift = BYPASS_MAIN_ON_SHIFT;
184 case BYPASS_EVENT_MAIN_OFF:
185 shift = BYPASS_MAIN_OFF_SHIFT;
187 case BYPASS_EVENT_AUX_ON:
188 shift = BYPASS_AUX_ON_SHIFT;
190 case BYPASS_EVENT_AUX_OFF:
191 shift = BYPASS_AUX_OFF_SHIFT;
197 *state = (by_ctl >> shift) & 0x3;
203 ixgbe_bypass_event_store(struct rte_eth_dev *dev, u32 event,
210 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
213 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
216 case BYPASS_EVENT_WDT_TO:
217 off = BYPASS_WDTIMEOUT_M;
218 status = state << BYPASS_WDTIMEOUT_SHIFT;
220 case BYPASS_EVENT_MAIN_ON:
221 off = BYPASS_MAIN_ON_M;
222 status = state << BYPASS_MAIN_ON_SHIFT;
224 case BYPASS_EVENT_MAIN_OFF:
225 off = BYPASS_MAIN_OFF_M;
226 status = state << BYPASS_MAIN_OFF_SHIFT;
228 case BYPASS_EVENT_AUX_ON:
229 off = BYPASS_AUX_ON_M;
230 status = state << BYPASS_AUX_ON_SHIFT;
232 case BYPASS_EVENT_AUX_OFF:
233 off = BYPASS_AUX_OFF_M;
234 status = state << BYPASS_AUX_OFF_SHIFT;
240 ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
247 ixgbe_bypass_wd_timeout_store(struct rte_eth_dev *dev, u32 timeout)
253 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
256 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
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;
263 /* set time out value */
264 mask = BYPASS_WDT_VALUE_M;
266 /* enable the timer */
267 status = timeout << BYPASS_WDT_TIME_SHIFT;
268 status |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
269 mask |= BYPASS_WDT_ENABLE_M;
272 ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
279 ixgbe_bypass_ver_show(struct rte_eth_dev *dev, u32 *ver)
285 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
288 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
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);
297 /* wait for the write to stick */
300 /* Now read the results */
302 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
306 *ver = status & BYPASS_CTL2_DATA_M; /* only one byte of date */
313 ixgbe_bypass_wd_timeout_show(struct rte_eth_dev *dev, u32 *wd_timeout)
320 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
323 FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
325 cmd = BYPASS_PAGE_CTL0;
326 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
328 wdg = by_ctl & BYPASS_WDT_ENABLE_M;
330 *wd_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
332 *wd_timeout = (by_ctl >> BYPASS_WDT_TIME_SHIFT) &
339 ixgbe_bypass_wd_reset(struct rte_eth_dev *dev)
347 struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
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);
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.
359 cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
361 /* Resync the FW time while writing to CTL1 anyway */
362 adapter->bps.reset_tm = time(NULL);
365 cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
367 /* reset FW timer offset since we are resetting the clock */
368 cmd |= BYPASS_CTL1_OFFTRST;
370 ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
372 /* Read until it matches what we wrote, or we time out */
375 ret_val = IXGBE_BYPASS_FW_WRITE_FAILURE;
379 if (adapter->bps.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &status)) {
380 ret_val = IXGBE_ERR_INVALID_ARGUMENT;
383 } while (!adapter->bps.ops.bypass_valid_rd(cmd, status));