linux/drivers/net/ethernet/intel/igc/igc_diag.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c)  2020 Intel Corporation */
   3
   4#include "igc.h"
   5#include "igc_diag.h"
   6
   7static struct igc_reg_test reg_test[] = {
   8        { IGC_FCAL,     1,      PATTERN_TEST,   0xFFFFFFFF,     0xFFFFFFFF },
   9        { IGC_FCAH,     1,      PATTERN_TEST,   0x0000FFFF,     0xFFFFFFFF },
  10        { IGC_FCT,      1,      PATTERN_TEST,   0x0000FFFF,     0xFFFFFFFF },
  11        { IGC_RDBAH(0), 4,      PATTERN_TEST,   0xFFFFFFFF,     0xFFFFFFFF },
  12        { IGC_RDBAL(0), 4,      PATTERN_TEST,   0xFFFFFF80,     0xFFFFFF80 },
  13        { IGC_RDLEN(0), 4,      PATTERN_TEST,   0x000FFF80,     0x000FFFFF },
  14        { IGC_RDT(0),   4,      PATTERN_TEST,   0x0000FFFF,     0x0000FFFF },
  15        { IGC_FCRTH,    1,      PATTERN_TEST,   0x0003FFF0,     0x0003FFF0 },
  16        { IGC_FCTTV,    1,      PATTERN_TEST,   0x0000FFFF,     0x0000FFFF },
  17        { IGC_TIPG,     1,      PATTERN_TEST,   0x3FFFFFFF,     0x3FFFFFFF },
  18        { IGC_TDBAH(0), 4,      PATTERN_TEST,   0xFFFFFFFF,     0xFFFFFFFF },
  19        { IGC_TDBAL(0), 4,      PATTERN_TEST,   0xFFFFFF80,     0xFFFFFF80 },
  20        { IGC_TDLEN(0), 4,      PATTERN_TEST,   0x000FFF80,     0x000FFFFF },
  21        { IGC_TDT(0),   4,      PATTERN_TEST,   0x0000FFFF,     0x0000FFFF },
  22        { IGC_RCTL,     1,      SET_READ_TEST,  0xFFFFFFFF,     0x00000000 },
  23        { IGC_RCTL,     1,      SET_READ_TEST,  0x04CFB2FE,     0x003FFFFB },
  24        { IGC_RCTL,     1,      SET_READ_TEST,  0x04CFB2FE,     0xFFFFFFFF },
  25        { IGC_TCTL,     1,      SET_READ_TEST,  0xFFFFFFFF,     0x00000000 },
  26        { IGC_RA,       16,     TABLE64_TEST_LO,
  27                                                0xFFFFFFFF,     0xFFFFFFFF },
  28        { IGC_RA,       16,     TABLE64_TEST_HI,
  29                                                0x900FFFFF,     0xFFFFFFFF },
  30        { IGC_MTA,      128,    TABLE32_TEST,
  31                                                0xFFFFFFFF,     0xFFFFFFFF },
  32        { 0, 0, 0, 0}
  33};
  34
  35static bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg,
  36                             u32 mask, u32 write)
  37{
  38        struct igc_hw *hw = &adapter->hw;
  39        u32 pat, val, before;
  40        static const u32 test_pattern[] = {
  41                0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
  42        };
  43
  44        for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
  45                before = rd32(reg);
  46                wr32(reg, test_pattern[pat] & write);
  47                val = rd32(reg);
  48                if (val != (test_pattern[pat] & write & mask)) {
  49                        netdev_err(adapter->netdev,
  50                                   "pattern test reg %04X failed: got 0x%08X expected 0x%08X",
  51                                   reg, val, test_pattern[pat] & write & mask);
  52                        *data = reg;
  53                        wr32(reg, before);
  54                        return false;
  55                }
  56                wr32(reg, before);
  57        }
  58        return true;
  59}
  60
  61static bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg,
  62                              u32 mask, u32 write)
  63{
  64        struct igc_hw *hw = &adapter->hw;
  65        u32 val, before;
  66
  67        before = rd32(reg);
  68        wr32(reg, write & mask);
  69        val = rd32(reg);
  70        if ((write & mask) != (val & mask)) {
  71                netdev_err(adapter->netdev,
  72                           "set/check reg %04X test failed: got 0x%08X expected 0x%08X",
  73                           reg, (val & mask), (write & mask));
  74                *data = reg;
  75                wr32(reg, before);
  76                return false;
  77        }
  78        wr32(reg, before);
  79        return true;
  80}
  81
  82bool igc_reg_test(struct igc_adapter *adapter, u64 *data)
  83{
  84        struct igc_reg_test *test = reg_test;
  85        struct igc_hw *hw = &adapter->hw;
  86        u32 value, before, after;
  87        u32 i, toggle, b = false;
  88
  89        /* Because the status register is such a special case,
  90         * we handle it separately from the rest of the register
  91         * tests.  Some bits are read-only, some toggle, and some
  92         * are writeable.
  93         */
  94        toggle = 0x6800D3;
  95        before = rd32(IGC_STATUS);
  96        value = before & toggle;
  97        wr32(IGC_STATUS, toggle);
  98        after = rd32(IGC_STATUS) & toggle;
  99        if (value != after) {
 100                netdev_err(adapter->netdev,
 101                           "failed STATUS register test got: 0x%08X expected: 0x%08X",
 102                           after, value);
 103                *data = 1;
 104                return false;
 105        }
 106        /* restore previous status */
 107        wr32(IGC_STATUS, before);
 108
 109        /* Perform the remainder of the register test, looping through
 110         * the test table until we either fail or reach the null entry.
 111         */
 112        while (test->reg) {
 113                for (i = 0; i < test->array_len; i++) {
 114                        switch (test->test_type) {
 115                        case PATTERN_TEST:
 116                                b = reg_pattern_test(adapter, data,
 117                                                     test->reg + (i * 0x40),
 118                                                     test->mask,
 119                                                     test->write);
 120                                break;
 121                        case SET_READ_TEST:
 122                                b = reg_set_and_check(adapter, data,
 123                                                      test->reg + (i * 0x40),
 124                                                      test->mask,
 125                                                      test->write);
 126                                break;
 127                        case TABLE64_TEST_LO:
 128                                b = reg_pattern_test(adapter, data,
 129                                                     test->reg + (i * 8),
 130                                                     test->mask,
 131                                                     test->write);
 132                                break;
 133                        case TABLE64_TEST_HI:
 134                                b = reg_pattern_test(adapter, data,
 135                                                     test->reg + 4 + (i * 8),
 136                                                     test->mask,
 137                                                     test->write);
 138                                break;
 139                        case TABLE32_TEST:
 140                                b = reg_pattern_test(adapter, data,
 141                                                     test->reg + (i * 4),
 142                                                     test->mask,
 143                                                     test->write);
 144                                break;
 145                        }
 146                        if (!b)
 147                                return false;
 148                }
 149                test++;
 150        }
 151        *data = 0;
 152        return true;
 153}
 154
 155bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data)
 156{
 157        struct igc_hw *hw = &adapter->hw;
 158
 159        *data = 0;
 160
 161        if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) {
 162                *data = 1;
 163                return false;
 164        }
 165
 166        return true;
 167}
 168
 169bool igc_link_test(struct igc_adapter *adapter, u64 *data)
 170{
 171        bool link_up;
 172
 173        *data = 0;
 174
 175        /* add delay to give enough time for autonegotioation to finish */
 176        if (adapter->hw.mac.autoneg)
 177                ssleep(5);
 178
 179        link_up = igc_has_link(adapter);
 180        if (!link_up) {
 181                *data = 1;
 182                return false;
 183        }
 184
 185        return true;
 186}
 187