18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2020 Intel Corporation */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "igc.h" 58c2ecf20Sopenharmony_ci#include "igc_diag.h" 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_cistatic struct igc_reg_test reg_test[] = { 88c2ecf20Sopenharmony_ci { IGC_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 98c2ecf20Sopenharmony_ci { IGC_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 108c2ecf20Sopenharmony_ci { IGC_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, 118c2ecf20Sopenharmony_ci { IGC_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 128c2ecf20Sopenharmony_ci { IGC_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, 138c2ecf20Sopenharmony_ci { IGC_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 148c2ecf20Sopenharmony_ci { IGC_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 158c2ecf20Sopenharmony_ci { IGC_FCRTH, 1, PATTERN_TEST, 0x0003FFF0, 0x0003FFF0 }, 168c2ecf20Sopenharmony_ci { IGC_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 178c2ecf20Sopenharmony_ci { IGC_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, 188c2ecf20Sopenharmony_ci { IGC_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, 198c2ecf20Sopenharmony_ci { IGC_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, 208c2ecf20Sopenharmony_ci { IGC_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, 218c2ecf20Sopenharmony_ci { IGC_TDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, 228c2ecf20Sopenharmony_ci { IGC_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 238c2ecf20Sopenharmony_ci { IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0x003FFFFB }, 248c2ecf20Sopenharmony_ci { IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0xFFFFFFFF }, 258c2ecf20Sopenharmony_ci { IGC_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, 268c2ecf20Sopenharmony_ci { IGC_RA, 16, TABLE64_TEST_LO, 278c2ecf20Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 288c2ecf20Sopenharmony_ci { IGC_RA, 16, TABLE64_TEST_HI, 298c2ecf20Sopenharmony_ci 0x900FFFFF, 0xFFFFFFFF }, 308c2ecf20Sopenharmony_ci { IGC_MTA, 128, TABLE32_TEST, 318c2ecf20Sopenharmony_ci 0xFFFFFFFF, 0xFFFFFFFF }, 328c2ecf20Sopenharmony_ci { 0, 0, 0, 0} 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg, 368c2ecf20Sopenharmony_ci u32 mask, u32 write) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct igc_hw *hw = &adapter->hw; 398c2ecf20Sopenharmony_ci u32 pat, val, before; 408c2ecf20Sopenharmony_ci static const u32 test_pattern[] = { 418c2ecf20Sopenharmony_ci 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF 428c2ecf20Sopenharmony_ci }; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) { 458c2ecf20Sopenharmony_ci before = rd32(reg); 468c2ecf20Sopenharmony_ci wr32(reg, test_pattern[pat] & write); 478c2ecf20Sopenharmony_ci val = rd32(reg); 488c2ecf20Sopenharmony_ci if (val != (test_pattern[pat] & write & mask)) { 498c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 508c2ecf20Sopenharmony_ci "pattern test reg %04X failed: got 0x%08X expected 0x%08X", 518c2ecf20Sopenharmony_ci reg, val, test_pattern[pat] & write & mask); 528c2ecf20Sopenharmony_ci *data = reg; 538c2ecf20Sopenharmony_ci wr32(reg, before); 548c2ecf20Sopenharmony_ci return false; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci wr32(reg, before); 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci return true; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg, 628c2ecf20Sopenharmony_ci u32 mask, u32 write) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct igc_hw *hw = &adapter->hw; 658c2ecf20Sopenharmony_ci u32 val, before; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci before = rd32(reg); 688c2ecf20Sopenharmony_ci wr32(reg, write & mask); 698c2ecf20Sopenharmony_ci val = rd32(reg); 708c2ecf20Sopenharmony_ci if ((write & mask) != (val & mask)) { 718c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 728c2ecf20Sopenharmony_ci "set/check reg %04X test failed: got 0x%08X expected 0x%08X", 738c2ecf20Sopenharmony_ci reg, (val & mask), (write & mask)); 748c2ecf20Sopenharmony_ci *data = reg; 758c2ecf20Sopenharmony_ci wr32(reg, before); 768c2ecf20Sopenharmony_ci return false; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci wr32(reg, before); 798c2ecf20Sopenharmony_ci return true; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cibool igc_reg_test(struct igc_adapter *adapter, u64 *data) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct igc_reg_test *test = reg_test; 858c2ecf20Sopenharmony_ci struct igc_hw *hw = &adapter->hw; 868c2ecf20Sopenharmony_ci u32 value, before, after; 878c2ecf20Sopenharmony_ci u32 i, toggle, b = false; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* Because the status register is such a special case, 908c2ecf20Sopenharmony_ci * we handle it separately from the rest of the register 918c2ecf20Sopenharmony_ci * tests. Some bits are read-only, some toggle, and some 928c2ecf20Sopenharmony_ci * are writeable. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci toggle = 0x6800D3; 958c2ecf20Sopenharmony_ci before = rd32(IGC_STATUS); 968c2ecf20Sopenharmony_ci value = before & toggle; 978c2ecf20Sopenharmony_ci wr32(IGC_STATUS, toggle); 988c2ecf20Sopenharmony_ci after = rd32(IGC_STATUS) & toggle; 998c2ecf20Sopenharmony_ci if (value != after) { 1008c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 1018c2ecf20Sopenharmony_ci "failed STATUS register test got: 0x%08X expected: 0x%08X", 1028c2ecf20Sopenharmony_ci after, value); 1038c2ecf20Sopenharmony_ci *data = 1; 1048c2ecf20Sopenharmony_ci return false; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci /* restore previous status */ 1078c2ecf20Sopenharmony_ci wr32(IGC_STATUS, before); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Perform the remainder of the register test, looping through 1108c2ecf20Sopenharmony_ci * the test table until we either fail or reach the null entry. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci while (test->reg) { 1138c2ecf20Sopenharmony_ci for (i = 0; i < test->array_len; i++) { 1148c2ecf20Sopenharmony_ci switch (test->test_type) { 1158c2ecf20Sopenharmony_ci case PATTERN_TEST: 1168c2ecf20Sopenharmony_ci b = reg_pattern_test(adapter, data, 1178c2ecf20Sopenharmony_ci test->reg + (i * 0x40), 1188c2ecf20Sopenharmony_ci test->mask, 1198c2ecf20Sopenharmony_ci test->write); 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case SET_READ_TEST: 1228c2ecf20Sopenharmony_ci b = reg_set_and_check(adapter, data, 1238c2ecf20Sopenharmony_ci test->reg + (i * 0x40), 1248c2ecf20Sopenharmony_ci test->mask, 1258c2ecf20Sopenharmony_ci test->write); 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case TABLE64_TEST_LO: 1288c2ecf20Sopenharmony_ci b = reg_pattern_test(adapter, data, 1298c2ecf20Sopenharmony_ci test->reg + (i * 8), 1308c2ecf20Sopenharmony_ci test->mask, 1318c2ecf20Sopenharmony_ci test->write); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case TABLE64_TEST_HI: 1348c2ecf20Sopenharmony_ci b = reg_pattern_test(adapter, data, 1358c2ecf20Sopenharmony_ci test->reg + 4 + (i * 8), 1368c2ecf20Sopenharmony_ci test->mask, 1378c2ecf20Sopenharmony_ci test->write); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci case TABLE32_TEST: 1408c2ecf20Sopenharmony_ci b = reg_pattern_test(adapter, data, 1418c2ecf20Sopenharmony_ci test->reg + (i * 4), 1428c2ecf20Sopenharmony_ci test->mask, 1438c2ecf20Sopenharmony_ci test->write); 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci if (!b) 1478c2ecf20Sopenharmony_ci return false; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci test++; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci *data = 0; 1528c2ecf20Sopenharmony_ci return true; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cibool igc_eeprom_test(struct igc_adapter *adapter, u64 *data) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct igc_hw *hw = &adapter->hw; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci *data = 0; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) { 1628c2ecf20Sopenharmony_ci *data = 1; 1638c2ecf20Sopenharmony_ci return false; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return true; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cibool igc_link_test(struct igc_adapter *adapter, u64 *data) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci bool link_up; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci *data = 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* add delay to give enough time for autonegotioation to finish */ 1768c2ecf20Sopenharmony_ci if (adapter->hw.mac.autoneg) 1778c2ecf20Sopenharmony_ci ssleep(5); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci link_up = igc_has_link(adapter); 1808c2ecf20Sopenharmony_ci if (!link_up) { 1818c2ecf20Sopenharmony_ci *data = 1; 1828c2ecf20Sopenharmony_ci return false; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return true; 1868c2ecf20Sopenharmony_ci} 187