cc621970c0cd361599d8d3054413da63471016b4
[releases.git] / igc_diag.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c)  2020 Intel Corporation */
3
4 #include "igc.h"
5 #include "igc_diag.h"
6
7 static 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
35 static 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
61 static 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
82 bool 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
155 bool 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
169 bool 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 }