dpdk/drivers/net/ixgbe/ixgbe_bypass.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2010-2014 Intel Corporation
   3 */
   4
   5#include <time.h>
   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"
  11
  12#define BYPASS_STATUS_OFF_MASK  3
  13
  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__);            \
  19                return retval;                            \
  20        }                                                   \
  21} while (0)
  22
  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__);            \
  27                return;                                     \
  28        }                                                   \
  29} while (0)
  30
  31
  32/**
  33 *  ixgbe_bypass_set_time - Set bypass FW time epoc.
  34 *
  35 *  @hw: pointer to hardware structure
  36 *
  37 *  This function with sync the FW date stamp with that of the
  38 *  system clock.
  39 **/
  40static void
  41ixgbe_bypass_set_time(struct ixgbe_adapter *adapter)
  42{
  43        u32 mask, value;
  44        u32 sec;
  45        struct ixgbe_hw *hw = &adapter->hw;
  46
  47        sec = 0;
  48
  49        /*
  50         * Send the FW our current time and turn on time_valid and
  51         * timer_reset bits.
  52         */
  53        mask = BYPASS_CTL1_TIME_M |
  54               BYPASS_CTL1_VALID_M |
  55               BYPASS_CTL1_OFFTRST_M;
  56        value = (sec & BYPASS_CTL1_TIME_M) |
  57                BYPASS_CTL1_VALID |
  58                BYPASS_CTL1_OFFTRST;
  59
  60        FUNC_PTR_OR_RET(adapter->bps.ops.bypass_set);
  61
  62        /* Store FW reset time (in seconds from epoch). */
  63        adapter->bps.reset_tm = time(NULL);
  64
  65        /* reset FW timer. */
  66        adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
  67}
  68
  69/**
  70 * ixgbe_bypass_init - Make some environment changes for bypass
  71 *
  72 * @adapter: pointer to ixgbe_adapter structure for access to state bits
  73 *
  74 * This function collects all the modifications needed by the bypass
  75 * driver.
  76 **/
  77void
  78ixgbe_bypass_init(struct rte_eth_dev *dev)
  79{
  80        struct ixgbe_adapter *adapter;
  81        struct ixgbe_hw *hw;
  82
  83        adapter = IXGBE_DEV_TO_ADPATER(dev);
  84        hw = &adapter->hw;
  85
  86        /* Only allow BYPASS ops on the first port */
  87        if (hw->device_id != IXGBE_DEV_ID_82599_BYPASS ||
  88                        hw->bus.func != 0) {
  89                PMD_DRV_LOG(ERR, "bypass function is not supported on that device");
  90                return;
  91        }
  92
  93        /* set bypass ops. */
  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;
  98
  99        /* set the time for logging. */
 100        ixgbe_bypass_set_time(adapter);
 101
 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;
 106}
 107
 108s32
 109ixgbe_bypass_state_show(struct rte_eth_dev *dev, u32 *state)
 110{
 111        struct ixgbe_hw *hw;
 112        s32 ret_val;
 113        u32 cmd;
 114        u32 by_ctl = 0;
 115        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 116
 117        hw = &adapter->hw;
 118        FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
 119
 120        cmd = BYPASS_PAGE_CTL0;
 121        ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
 122
 123        /* Assume bypass_rw didn't error out, if it did state will
 124         * be ignored anyway.
 125         */
 126        *state = (by_ctl >> BYPASS_STATUS_OFF_SHIFT) &  BYPASS_STATUS_OFF_MASK;
 127
 128        return ret_val;
 129}
 130
 131
 132s32
 133ixgbe_bypass_state_store(struct rte_eth_dev *dev, u32 *new_state)
 134{
 135        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 136        struct ixgbe_hw *hw;
 137        s32 ret_val;
 138
 139        hw = &adapter->hw;
 140        FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
 141
 142        /* Set the new state */
 143        ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
 144                                         BYPASS_MODE_OFF_M, *new_state);
 145        if (ret_val)
 146                goto exit;
 147
 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);
 151
 152exit:
 153        return ret_val;
 154
 155}
 156
 157s32
 158ixgbe_bypass_event_show(struct rte_eth_dev *dev, u32 event,
 159                            u32 *state)
 160{
 161        struct ixgbe_hw *hw;
 162        s32 ret_val;
 163        u32 shift;
 164        u32 cmd;
 165        u32 by_ctl = 0;
 166        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 167
 168        hw = &adapter->hw;
 169        FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
 170
 171        cmd = BYPASS_PAGE_CTL0;
 172        ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
 173
 174        /* Assume bypass_rw didn't error out, if it did event will
 175         * be ignored anyway.
 176         */
 177        switch (event) {
 178        case BYPASS_EVENT_WDT_TO:
 179                shift = BYPASS_WDTIMEOUT_SHIFT;
 180                break;
 181        case BYPASS_EVENT_MAIN_ON:
 182                shift = BYPASS_MAIN_ON_SHIFT;
 183                break;
 184        case BYPASS_EVENT_MAIN_OFF:
 185                shift = BYPASS_MAIN_OFF_SHIFT;
 186                break;
 187        case BYPASS_EVENT_AUX_ON:
 188                shift = BYPASS_AUX_ON_SHIFT;
 189                break;
 190        case BYPASS_EVENT_AUX_OFF:
 191                shift = BYPASS_AUX_OFF_SHIFT;
 192                break;
 193        default:
 194                return EINVAL;
 195        }
 196
 197        *state = (by_ctl >> shift) & 0x3;
 198
 199        return ret_val;
 200}
 201
 202s32
 203ixgbe_bypass_event_store(struct rte_eth_dev *dev, u32 event,
 204                             u32 state)
 205{
 206        struct ixgbe_hw *hw;
 207        u32 status;
 208        u32 off;
 209        s32 ret_val;
 210        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 211
 212        hw = &adapter->hw;
 213        FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
 214
 215        switch (event) {
 216        case BYPASS_EVENT_WDT_TO:
 217                off = BYPASS_WDTIMEOUT_M;
 218                status = state << BYPASS_WDTIMEOUT_SHIFT;
 219                break;
 220        case BYPASS_EVENT_MAIN_ON:
 221                off = BYPASS_MAIN_ON_M;
 222                status = state << BYPASS_MAIN_ON_SHIFT;
 223                break;
 224        case BYPASS_EVENT_MAIN_OFF:
 225                off = BYPASS_MAIN_OFF_M;
 226                status = state << BYPASS_MAIN_OFF_SHIFT;
 227                break;
 228        case BYPASS_EVENT_AUX_ON:
 229                off = BYPASS_AUX_ON_M;
 230                status = state << BYPASS_AUX_ON_SHIFT;
 231                break;
 232        case BYPASS_EVENT_AUX_OFF:
 233                off = BYPASS_AUX_OFF_M;
 234                status = state << BYPASS_AUX_OFF_SHIFT;
 235                break;
 236        default:
 237                return EINVAL;
 238        }
 239
 240        ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
 241                off, status);
 242
 243        return ret_val;
 244}
 245
 246s32
 247ixgbe_bypass_wd_timeout_store(struct rte_eth_dev *dev, u32 timeout)
 248{
 249        struct ixgbe_hw *hw;
 250        u32 status;
 251        u32 mask;
 252        s32 ret_val;
 253        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 254
 255        hw = &adapter->hw;
 256        FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
 257
 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;
 262        } else {
 263                /* set time out value */
 264                mask = BYPASS_WDT_VALUE_M;
 265
 266                /* enable the timer */
 267                status = timeout << BYPASS_WDT_TIME_SHIFT;
 268                status |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
 269                mask |= BYPASS_WDT_ENABLE_M;
 270        }
 271
 272        ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
 273                mask, status);
 274
 275        return ret_val;
 276}
 277
 278s32
 279ixgbe_bypass_ver_show(struct rte_eth_dev *dev, u32 *ver)
 280{
 281        struct ixgbe_hw *hw;
 282        u32 cmd;
 283        u32 status;
 284        s32 ret_val;
 285        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 286
 287        hw = &adapter->hw;
 288        FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
 289
 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);
 294        if (ret_val)
 295                goto exit;
 296
 297        /* wait for the write to stick */
 298        msleep(100);
 299
 300        /* Now read the results */
 301        cmd &= ~BYPASS_WE;
 302        ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
 303        if (ret_val)
 304                goto exit;
 305
 306        *ver = status & BYPASS_CTL2_DATA_M;      /* only one byte of date */
 307
 308exit:
 309        return ret_val;
 310}
 311
 312s32
 313ixgbe_bypass_wd_timeout_show(struct rte_eth_dev *dev, u32 *wd_timeout)
 314{
 315        struct ixgbe_hw *hw;
 316        u32 by_ctl = 0;
 317        u32 cmd;
 318        u32 wdg;
 319        s32 ret_val;
 320        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 321
 322        hw = &adapter->hw;
 323        FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
 324
 325        cmd = BYPASS_PAGE_CTL0;
 326        ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
 327
 328        wdg = by_ctl & BYPASS_WDT_ENABLE_M;
 329        if (!wdg)
 330                *wd_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
 331        else
 332                *wd_timeout = (by_ctl >> BYPASS_WDT_TIME_SHIFT) &
 333                        BYPASS_WDT_MASK;
 334
 335        return ret_val;
 336}
 337
 338s32
 339ixgbe_bypass_wd_reset(struct rte_eth_dev *dev)
 340{
 341        u32 cmd;
 342        u32 status;
 343        u32 sec;
 344        u32 count = 0;
 345        s32 ret_val;
 346        struct ixgbe_hw *hw;
 347        struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
 348
 349        hw = &adapter->hw;
 350
 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);
 353
 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.
 357         */
 358        /* Set up WD pet */
 359        cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
 360
 361        /* Resync the FW time while writing to CTL1 anyway */
 362        adapter->bps.reset_tm = time(NULL);
 363        sec = 0;
 364
 365        cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
 366
 367        /* reset FW timer offset since we are resetting the clock */
 368        cmd |= BYPASS_CTL1_OFFTRST;
 369
 370        ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
 371
 372        /* Read until it matches what we wrote, or we time out */
 373        do {
 374                if (count++ > 10) {
 375                        ret_val = IXGBE_BYPASS_FW_WRITE_FAILURE;
 376                        break;
 377                }
 378
 379                if (adapter->bps.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &status)) {
 380                        ret_val = IXGBE_ERR_INVALID_ARGUMENT;
 381                        break;
 382                }
 383        } while (!adapter->bps.ops.bypass_valid_rd(cmd, status));
 384
 385        return ret_val;
 386}
 387