ffc905f3b8
Create a rte_ethdev_driver.h file and move PMD specific APIs here. Drivers updated to include this new header file. There is no update in header content and since ethdev.h included by ethdev_driver.h, nothing changed from driver point of view, only logically grouping of APIs. From applications point of view they can't access to driver specific APIs anymore and they shouldn't. More PMD specific data structures still remain in ethdev.h because of inline functions in header use them. Those will be handled separately. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> Acked-by: Andrew Rybchenko <arybchenko@solarflare.com> Acked-by: Thomas Monjalon <thomas@monjalon.net>
387 lines
9.0 KiB
C
387 lines
9.0 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2010-2014 Intel Corporation
|
|
*/
|
|
|
|
#include <time.h>
|
|
#include <rte_atomic.h>
|
|
#include <rte_ethdev_driver.h>
|
|
#include "ixgbe_ethdev.h"
|
|
#include "ixgbe_bypass_api.h"
|
|
#include "rte_pmd_ixgbe.h"
|
|
|
|
#define BYPASS_STATUS_OFF_MASK 3
|
|
|
|
/* Macros to check for invlaid function pointers. */
|
|
#define FUNC_PTR_OR_ERR_RET(func, retval) do { \
|
|
if ((func) == NULL) { \
|
|
PMD_DRV_LOG(ERR, "%s:%d function not supported", \
|
|
__func__, __LINE__); \
|
|
return retval; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define FUNC_PTR_OR_RET(func) do { \
|
|
if ((func) == NULL) { \
|
|
PMD_DRV_LOG(ERR, "%s:%d function not supported", \
|
|
__func__, __LINE__); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
|
|
/**
|
|
* ixgbe_bypass_set_time - Set bypass FW time epoc.
|
|
*
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* This function with sync the FW date stamp with that of the
|
|
* system clock.
|
|
**/
|
|
static void
|
|
ixgbe_bypass_set_time(struct ixgbe_adapter *adapter)
|
|
{
|
|
u32 mask, value;
|
|
u32 sec;
|
|
struct ixgbe_hw *hw = &adapter->hw;
|
|
|
|
sec = 0;
|
|
|
|
/*
|
|
* Send the FW our current time and turn on time_valid and
|
|
* timer_reset bits.
|
|
*/
|
|
mask = BYPASS_CTL1_TIME_M |
|
|
BYPASS_CTL1_VALID_M |
|
|
BYPASS_CTL1_OFFTRST_M;
|
|
value = (sec & BYPASS_CTL1_TIME_M) |
|
|
BYPASS_CTL1_VALID |
|
|
BYPASS_CTL1_OFFTRST;
|
|
|
|
FUNC_PTR_OR_RET(adapter->bps.ops.bypass_set);
|
|
|
|
/* Store FW reset time (in seconds from epoch). */
|
|
adapter->bps.reset_tm = time(NULL);
|
|
|
|
/* reset FW timer. */
|
|
adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
|
|
}
|
|
|
|
/**
|
|
* ixgbe_bypass_init - Make some environment changes for bypass
|
|
*
|
|
* @adapter: pointer to ixgbe_adapter structure for access to state bits
|
|
*
|
|
* This function collects all the modifications needed by the bypass
|
|
* driver.
|
|
**/
|
|
void
|
|
ixgbe_bypass_init(struct rte_eth_dev *dev)
|
|
{
|
|
struct ixgbe_adapter *adapter;
|
|
struct ixgbe_hw *hw;
|
|
|
|
adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
hw = &adapter->hw;
|
|
|
|
/* Only allow BYPASS ops on the first port */
|
|
if (hw->device_id != IXGBE_DEV_ID_82599_BYPASS ||
|
|
hw->bus.func != 0) {
|
|
PMD_DRV_LOG(ERR, "bypass function is not supported on that device");
|
|
return;
|
|
}
|
|
|
|
/* set bypass ops. */
|
|
adapter->bps.ops.bypass_rw = &ixgbe_bypass_rw_generic;
|
|
adapter->bps.ops.bypass_valid_rd = &ixgbe_bypass_valid_rd_generic;
|
|
adapter->bps.ops.bypass_set = &ixgbe_bypass_set_generic;
|
|
adapter->bps.ops.bypass_rd_eep = &ixgbe_bypass_rd_eep_generic;
|
|
|
|
/* set the time for logging. */
|
|
ixgbe_bypass_set_time(adapter);
|
|
|
|
/* Don't have the SDP to the laser */
|
|
hw->mac.ops.disable_tx_laser = NULL;
|
|
hw->mac.ops.enable_tx_laser = NULL;
|
|
hw->mac.ops.flap_tx_laser = NULL;
|
|
}
|
|
|
|
s32
|
|
ixgbe_bypass_state_show(struct rte_eth_dev *dev, u32 *state)
|
|
{
|
|
struct ixgbe_hw *hw;
|
|
s32 ret_val;
|
|
u32 cmd;
|
|
u32 by_ctl = 0;
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
|
|
hw = &adapter->hw;
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
|
|
|
|
cmd = BYPASS_PAGE_CTL0;
|
|
ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
|
|
|
|
/* Assume bypass_rw didn't error out, if it did state will
|
|
* be ignored anyway.
|
|
*/
|
|
*state = (by_ctl >> BYPASS_STATUS_OFF_SHIFT) & BYPASS_STATUS_OFF_MASK;
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
s32
|
|
ixgbe_bypass_state_store(struct rte_eth_dev *dev, u32 *new_state)
|
|
{
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
struct ixgbe_hw *hw;
|
|
s32 ret_val;
|
|
|
|
hw = &adapter->hw;
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
|
|
|
|
/* Set the new state */
|
|
ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
|
|
BYPASS_MODE_OFF_M, *new_state);
|
|
if (ret_val)
|
|
goto exit;
|
|
|
|
/* Set AUTO back on so FW can receive events */
|
|
ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
|
|
BYPASS_MODE_OFF_M, BYPASS_AUTO);
|
|
|
|
exit:
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
s32
|
|
ixgbe_bypass_event_show(struct rte_eth_dev *dev, u32 event,
|
|
u32 *state)
|
|
{
|
|
struct ixgbe_hw *hw;
|
|
s32 ret_val;
|
|
u32 shift;
|
|
u32 cmd;
|
|
u32 by_ctl = 0;
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
|
|
hw = &adapter->hw;
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
|
|
|
|
cmd = BYPASS_PAGE_CTL0;
|
|
ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
|
|
|
|
/* Assume bypass_rw didn't error out, if it did event will
|
|
* be ignored anyway.
|
|
*/
|
|
switch (event) {
|
|
case BYPASS_EVENT_WDT_TO:
|
|
shift = BYPASS_WDTIMEOUT_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_MAIN_ON:
|
|
shift = BYPASS_MAIN_ON_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_MAIN_OFF:
|
|
shift = BYPASS_MAIN_OFF_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_AUX_ON:
|
|
shift = BYPASS_AUX_ON_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_AUX_OFF:
|
|
shift = BYPASS_AUX_OFF_SHIFT;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
|
|
*state = (by_ctl >> shift) & 0x3;
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
s32
|
|
ixgbe_bypass_event_store(struct rte_eth_dev *dev, u32 event,
|
|
u32 state)
|
|
{
|
|
struct ixgbe_hw *hw;
|
|
u32 status;
|
|
u32 off;
|
|
s32 ret_val;
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
|
|
hw = &adapter->hw;
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
|
|
|
|
switch (event) {
|
|
case BYPASS_EVENT_WDT_TO:
|
|
off = BYPASS_WDTIMEOUT_M;
|
|
status = state << BYPASS_WDTIMEOUT_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_MAIN_ON:
|
|
off = BYPASS_MAIN_ON_M;
|
|
status = state << BYPASS_MAIN_ON_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_MAIN_OFF:
|
|
off = BYPASS_MAIN_OFF_M;
|
|
status = state << BYPASS_MAIN_OFF_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_AUX_ON:
|
|
off = BYPASS_AUX_ON_M;
|
|
status = state << BYPASS_AUX_ON_SHIFT;
|
|
break;
|
|
case BYPASS_EVENT_AUX_OFF:
|
|
off = BYPASS_AUX_OFF_M;
|
|
status = state << BYPASS_AUX_OFF_SHIFT;
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
|
|
ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
|
|
off, status);
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
s32
|
|
ixgbe_bypass_wd_timeout_store(struct rte_eth_dev *dev, u32 timeout)
|
|
{
|
|
struct ixgbe_hw *hw;
|
|
u32 status;
|
|
u32 mask;
|
|
s32 ret_val;
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
|
|
hw = &adapter->hw;
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
|
|
|
|
/* disable the timer with timeout of zero */
|
|
if (timeout == RTE_PMD_IXGBE_BYPASS_TMT_OFF) {
|
|
status = 0x0; /* WDG enable off */
|
|
mask = BYPASS_WDT_ENABLE_M;
|
|
} else {
|
|
/* set time out value */
|
|
mask = BYPASS_WDT_VALUE_M;
|
|
|
|
/* enable the timer */
|
|
status = timeout << BYPASS_WDT_TIME_SHIFT;
|
|
status |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
|
|
mask |= BYPASS_WDT_ENABLE_M;
|
|
}
|
|
|
|
ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
|
|
mask, status);
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
s32
|
|
ixgbe_bypass_ver_show(struct rte_eth_dev *dev, u32 *ver)
|
|
{
|
|
struct ixgbe_hw *hw;
|
|
u32 cmd;
|
|
u32 status;
|
|
s32 ret_val;
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
|
|
hw = &adapter->hw;
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
|
|
|
|
cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
|
|
cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) &
|
|
BYPASS_CTL2_OFFSET_M;
|
|
ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
|
|
if (ret_val)
|
|
goto exit;
|
|
|
|
/* wait for the write to stick */
|
|
msleep(100);
|
|
|
|
/* Now read the results */
|
|
cmd &= ~BYPASS_WE;
|
|
ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
|
|
if (ret_val)
|
|
goto exit;
|
|
|
|
*ver = status & BYPASS_CTL2_DATA_M; /* only one byte of date */
|
|
|
|
exit:
|
|
return ret_val;
|
|
}
|
|
|
|
s32
|
|
ixgbe_bypass_wd_timeout_show(struct rte_eth_dev *dev, u32 *wd_timeout)
|
|
{
|
|
struct ixgbe_hw *hw;
|
|
u32 by_ctl = 0;
|
|
u32 cmd;
|
|
u32 wdg;
|
|
s32 ret_val;
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
|
|
hw = &adapter->hw;
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
|
|
|
|
cmd = BYPASS_PAGE_CTL0;
|
|
ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
|
|
|
|
wdg = by_ctl & BYPASS_WDT_ENABLE_M;
|
|
if (!wdg)
|
|
*wd_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
|
|
else
|
|
*wd_timeout = (by_ctl >> BYPASS_WDT_TIME_SHIFT) &
|
|
BYPASS_WDT_MASK;
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
s32
|
|
ixgbe_bypass_wd_reset(struct rte_eth_dev *dev)
|
|
{
|
|
u32 cmd;
|
|
u32 status;
|
|
u32 sec;
|
|
u32 count = 0;
|
|
s32 ret_val;
|
|
struct ixgbe_hw *hw;
|
|
struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
|
|
|
|
hw = &adapter->hw;
|
|
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
|
|
FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_valid_rd, -ENOTSUP);
|
|
|
|
/* Use the lower level bit-bang functions since we don't need
|
|
* to read the register first to get it's current state as we
|
|
* are setting every thing in this write.
|
|
*/
|
|
/* Set up WD pet */
|
|
cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
|
|
|
|
/* Resync the FW time while writing to CTL1 anyway */
|
|
adapter->bps.reset_tm = time(NULL);
|
|
sec = 0;
|
|
|
|
cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
|
|
|
|
/* reset FW timer offset since we are resetting the clock */
|
|
cmd |= BYPASS_CTL1_OFFTRST;
|
|
|
|
ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
|
|
|
|
/* Read until it matches what we wrote, or we time out */
|
|
do {
|
|
if (count++ > 10) {
|
|
ret_val = IXGBE_BYPASS_FW_WRITE_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (adapter->bps.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &status)) {
|
|
ret_val = IXGBE_ERR_INVALID_ARGUMENT;
|
|
break;
|
|
}
|
|
} while (!adapter->bps.ops.bypass_valid_rd(cmd, status));
|
|
|
|
return ret_val;
|
|
}
|