162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c)  2020 Intel Corporation */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "igc.h"
562306a36Sopenharmony_ci#include "igc_diag.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_cistatic struct igc_reg_test reg_test[] = {
862306a36Sopenharmony_ci	{ IGC_FCAL,	1,	PATTERN_TEST,	0xFFFFFFFF,	0xFFFFFFFF },
962306a36Sopenharmony_ci	{ IGC_FCAH,	1,	PATTERN_TEST,	0x0000FFFF,	0xFFFFFFFF },
1062306a36Sopenharmony_ci	{ IGC_FCT,	1,	PATTERN_TEST,	0x0000FFFF,	0xFFFFFFFF },
1162306a36Sopenharmony_ci	{ IGC_RDBAH(0), 4,	PATTERN_TEST,	0xFFFFFFFF,	0xFFFFFFFF },
1262306a36Sopenharmony_ci	{ IGC_RDBAL(0),	4,	PATTERN_TEST,	0xFFFFFF80,	0xFFFFFF80 },
1362306a36Sopenharmony_ci	{ IGC_RDLEN(0),	4,	PATTERN_TEST,	0x000FFF80,	0x000FFFFF },
1462306a36Sopenharmony_ci	{ IGC_RDT(0),	4,	PATTERN_TEST,	0x0000FFFF,	0x0000FFFF },
1562306a36Sopenharmony_ci	{ IGC_FCRTH,	1,	PATTERN_TEST,	0x0003FFF0,	0x0003FFF0 },
1662306a36Sopenharmony_ci	{ IGC_FCTTV,	1,	PATTERN_TEST,	0x0000FFFF,	0x0000FFFF },
1762306a36Sopenharmony_ci	{ IGC_TIPG,	1,	PATTERN_TEST,	0x3FFFFFFF,	0x3FFFFFFF },
1862306a36Sopenharmony_ci	{ IGC_TDBAH(0),	4,	PATTERN_TEST,	0xFFFFFFFF,	0xFFFFFFFF },
1962306a36Sopenharmony_ci	{ IGC_TDBAL(0),	4,	PATTERN_TEST,	0xFFFFFF80,	0xFFFFFF80 },
2062306a36Sopenharmony_ci	{ IGC_TDLEN(0),	4,	PATTERN_TEST,	0x000FFF80,	0x000FFFFF },
2162306a36Sopenharmony_ci	{ IGC_TDT(0),	4,	PATTERN_TEST,	0x0000FFFF,	0x0000FFFF },
2262306a36Sopenharmony_ci	{ IGC_RCTL,	1,	SET_READ_TEST,	0xFFFFFFFF,	0x00000000 },
2362306a36Sopenharmony_ci	{ IGC_RCTL,	1,	SET_READ_TEST,	0x04CFB2FE,	0x003FFFFB },
2462306a36Sopenharmony_ci	{ IGC_RCTL,	1,	SET_READ_TEST,	0x04CFB2FE,	0xFFFFFFFF },
2562306a36Sopenharmony_ci	{ IGC_TCTL,	1,	SET_READ_TEST,	0xFFFFFFFF,	0x00000000 },
2662306a36Sopenharmony_ci	{ IGC_RA,	16,	TABLE64_TEST_LO,
2762306a36Sopenharmony_ci						0xFFFFFFFF,	0xFFFFFFFF },
2862306a36Sopenharmony_ci	{ IGC_RA,	16,	TABLE64_TEST_HI,
2962306a36Sopenharmony_ci						0x900FFFFF,	0xFFFFFFFF },
3062306a36Sopenharmony_ci	{ IGC_MTA,	128,	TABLE32_TEST,
3162306a36Sopenharmony_ci						0xFFFFFFFF,	0xFFFFFFFF },
3262306a36Sopenharmony_ci	{ 0, 0, 0, 0}
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg,
3662306a36Sopenharmony_ci			     u32 mask, u32 write)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
3962306a36Sopenharmony_ci	u32 pat, val, before;
4062306a36Sopenharmony_ci	static const u32 test_pattern[] = {
4162306a36Sopenharmony_ci		0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
4262306a36Sopenharmony_ci	};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
4562306a36Sopenharmony_ci		before = rd32(reg);
4662306a36Sopenharmony_ci		wr32(reg, test_pattern[pat] & write);
4762306a36Sopenharmony_ci		val = rd32(reg);
4862306a36Sopenharmony_ci		if (val != (test_pattern[pat] & write & mask)) {
4962306a36Sopenharmony_ci			netdev_err(adapter->netdev,
5062306a36Sopenharmony_ci				   "pattern test reg %04X failed: got 0x%08X expected 0x%08X",
5162306a36Sopenharmony_ci				   reg, val, test_pattern[pat] & write & mask);
5262306a36Sopenharmony_ci			*data = reg;
5362306a36Sopenharmony_ci			wr32(reg, before);
5462306a36Sopenharmony_ci			return false;
5562306a36Sopenharmony_ci		}
5662306a36Sopenharmony_ci		wr32(reg, before);
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci	return true;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg,
6262306a36Sopenharmony_ci			      u32 mask, u32 write)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
6562306a36Sopenharmony_ci	u32 val, before;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	before = rd32(reg);
6862306a36Sopenharmony_ci	wr32(reg, write & mask);
6962306a36Sopenharmony_ci	val = rd32(reg);
7062306a36Sopenharmony_ci	if ((write & mask) != (val & mask)) {
7162306a36Sopenharmony_ci		netdev_err(adapter->netdev,
7262306a36Sopenharmony_ci			   "set/check reg %04X test failed: got 0x%08X expected 0x%08X",
7362306a36Sopenharmony_ci			   reg, (val & mask), (write & mask));
7462306a36Sopenharmony_ci		*data = reg;
7562306a36Sopenharmony_ci		wr32(reg, before);
7662306a36Sopenharmony_ci		return false;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	wr32(reg, before);
7962306a36Sopenharmony_ci	return true;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cibool igc_reg_test(struct igc_adapter *adapter, u64 *data)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct igc_reg_test *test = reg_test;
8562306a36Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
8662306a36Sopenharmony_ci	u32 value, before, after;
8762306a36Sopenharmony_ci	u32 i, toggle, b = false;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Because the status register is such a special case,
9062306a36Sopenharmony_ci	 * we handle it separately from the rest of the register
9162306a36Sopenharmony_ci	 * tests.  Some bits are read-only, some toggle, and some
9262306a36Sopenharmony_ci	 * are writeable.
9362306a36Sopenharmony_ci	 */
9462306a36Sopenharmony_ci	toggle = 0x6800D3;
9562306a36Sopenharmony_ci	before = rd32(IGC_STATUS);
9662306a36Sopenharmony_ci	value = before & toggle;
9762306a36Sopenharmony_ci	wr32(IGC_STATUS, toggle);
9862306a36Sopenharmony_ci	after = rd32(IGC_STATUS) & toggle;
9962306a36Sopenharmony_ci	if (value != after) {
10062306a36Sopenharmony_ci		netdev_err(adapter->netdev,
10162306a36Sopenharmony_ci			   "failed STATUS register test got: 0x%08X expected: 0x%08X",
10262306a36Sopenharmony_ci			   after, value);
10362306a36Sopenharmony_ci		*data = 1;
10462306a36Sopenharmony_ci		return false;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci	/* restore previous status */
10762306a36Sopenharmony_ci	wr32(IGC_STATUS, before);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Perform the remainder of the register test, looping through
11062306a36Sopenharmony_ci	 * the test table until we either fail or reach the null entry.
11162306a36Sopenharmony_ci	 */
11262306a36Sopenharmony_ci	while (test->reg) {
11362306a36Sopenharmony_ci		for (i = 0; i < test->array_len; i++) {
11462306a36Sopenharmony_ci			switch (test->test_type) {
11562306a36Sopenharmony_ci			case PATTERN_TEST:
11662306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
11762306a36Sopenharmony_ci						     test->reg + (i * 0x40),
11862306a36Sopenharmony_ci						     test->mask,
11962306a36Sopenharmony_ci						     test->write);
12062306a36Sopenharmony_ci				break;
12162306a36Sopenharmony_ci			case SET_READ_TEST:
12262306a36Sopenharmony_ci				b = reg_set_and_check(adapter, data,
12362306a36Sopenharmony_ci						      test->reg + (i * 0x40),
12462306a36Sopenharmony_ci						      test->mask,
12562306a36Sopenharmony_ci						      test->write);
12662306a36Sopenharmony_ci				break;
12762306a36Sopenharmony_ci			case TABLE64_TEST_LO:
12862306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
12962306a36Sopenharmony_ci						     test->reg + (i * 8),
13062306a36Sopenharmony_ci						     test->mask,
13162306a36Sopenharmony_ci						     test->write);
13262306a36Sopenharmony_ci				break;
13362306a36Sopenharmony_ci			case TABLE64_TEST_HI:
13462306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
13562306a36Sopenharmony_ci						     test->reg + 4 + (i * 8),
13662306a36Sopenharmony_ci						     test->mask,
13762306a36Sopenharmony_ci						     test->write);
13862306a36Sopenharmony_ci				break;
13962306a36Sopenharmony_ci			case TABLE32_TEST:
14062306a36Sopenharmony_ci				b = reg_pattern_test(adapter, data,
14162306a36Sopenharmony_ci						     test->reg + (i * 4),
14262306a36Sopenharmony_ci						     test->mask,
14362306a36Sopenharmony_ci						     test->write);
14462306a36Sopenharmony_ci				break;
14562306a36Sopenharmony_ci			}
14662306a36Sopenharmony_ci			if (!b)
14762306a36Sopenharmony_ci				return false;
14862306a36Sopenharmony_ci		}
14962306a36Sopenharmony_ci		test++;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	*data = 0;
15262306a36Sopenharmony_ci	return true;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cibool igc_eeprom_test(struct igc_adapter *adapter, u64 *data)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct igc_hw *hw = &adapter->hw;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	*data = 0;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) {
16262306a36Sopenharmony_ci		*data = 1;
16362306a36Sopenharmony_ci		return false;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return true;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cibool igc_link_test(struct igc_adapter *adapter, u64 *data)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	bool link_up;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	*data = 0;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* add delay to give enough time for autonegotioation to finish */
17662306a36Sopenharmony_ci	if (adapter->hw.mac.autoneg)
17762306a36Sopenharmony_ci		ssleep(5);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	link_up = igc_has_link(adapter);
18062306a36Sopenharmony_ci	if (!link_up) {
18162306a36Sopenharmony_ci		*data = 1;
18262306a36Sopenharmony_ci		return false;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return true;
18662306a36Sopenharmony_ci}
187