numam-dpdk/drivers/net/ixgbe/ixgbe_bypass.c
Bruce Richardson 5566a3e358 drivers: use SPDX tag for Intel copyright files
Replace the BSD license header with the SPDX tag for files
with only an Intel copyright on them.

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
2018-01-04 22:41:39 +01:00

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.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;
}