xref: /linux/drivers/net/ethernet/intel/igc/igc_diag.c (revision 702648721db590b3425c31ade294000e18808345)
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 }
187