Commit fa14b9b0 authored by David S. Miller's avatar David S. Miller
Browse files


Jeff Kirsher says:

====================
1GbE Intel Wired LAN Driver Updates 2020-05-18

This series contains updates to igc driver only.

Sasha adds ECN support for TSO by adding the NETIF_F_TSO_ECN flag, which
aligns with other Intel drivers.  Also cleaned up defines that are not
supported or used in the igc driver.

Andre does most of the changes with updating the log messages for igc
driver.

Vitaly adds support for EEPROM, register and link ethtool
self-tests.

v2: Fixed up the added ethtool self-tests based on feedback from the
    community.  Dropped the four patches that removed '\n' from log
    messages.
v3: Reverted the debug message changes in patch 2 for messages in
    igc_probe, also made reg_test[] static in patch 3 based on community
    feedback
v4: Updated the patch description for patch 2, which referred to changes
    that no longer existed in the patch
v5: Scrubbed patches 4-7 patch description, which also referred to
    changes that no longer existed in the patch
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5cdfe830 5ddb2747
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8,4 +8,4 @@
obj-$(CONFIG_IGC) += igc.o

igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o \
igc_ethtool.o igc_ptp.o igc_dump.o igc_tsn.o
igc_diag.o igc_ethtool.o igc_ptp.o igc_dump.o igc_tsn.o
+4 −0
Original line number Diff line number Diff line
@@ -198,6 +198,8 @@ struct igc_adapter {
	unsigned long link_check_timeout;
	struct igc_info ei;

	u32 test_icr;

	struct ptp_clock *ptp_clock;
	struct ptp_clock_info ptp_caps;
	struct work_struct ptp_tx_work;
@@ -215,6 +217,8 @@ struct igc_adapter {

void igc_up(struct igc_adapter *adapter);
void igc_down(struct igc_adapter *adapter);
int igc_open(struct net_device *netdev);
int igc_close(struct net_device *netdev);
int igc_setup_tx_resources(struct igc_ring *ring);
int igc_setup_rx_resources(struct igc_ring *ring);
void igc_free_tx_resources(struct igc_ring *ring);
+3 −3
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ static s32 igc_reset_hw_base(struct igc_hw *hw)
	 */
	ret_val = igc_disable_pcie_master(hw);
	if (ret_val)
		hw_dbg("PCI-E Master disable polling has failed.\n");
		hw_dbg("PCI-E Master disable polling has failed\n");

	hw_dbg("Masking off all interrupts\n");
	wr32(IGC_IMC, 0xffffffff);
@@ -177,7 +177,7 @@ static s32 igc_init_phy_params_base(struct igc_hw *hw)
	 */
	ret_val = hw->phy.ops.reset(hw);
	if (ret_val) {
		hw_dbg("Error resetting the PHY.\n");
		hw_dbg("Error resetting the PHY\n");
		goto out;
	}

@@ -367,7 +367,7 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw)
	}

	if (ms_wait == 10)
		pr_debug("Queue disable timed out after 10ms\n");
		hw_dbg("Queue disable timed out after 10ms\n");

	/* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
	 * incoming packets are rejected.  Set enable and wait 2ms so that
+0 −1
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@
/* Loop limit on how long we wait for auto-negotiation to complete */
#define COPPER_LINK_UP_LIMIT		10
#define PHY_AUTO_NEG_LIMIT		45
#define PHY_FORCE_LIMIT			20

/* Number of 100 microseconds we wait for PCI Express master disable */
#define MASTER_DISABLE_TIMEOUT		800
+186 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c)  2020 Intel Corporation */

#include "igc.h"
#include "igc_diag.h"

static struct igc_reg_test reg_test[] = {
	{ IGC_FCAL,	1,	PATTERN_TEST,	0xFFFFFFFF,	0xFFFFFFFF },
	{ IGC_FCAH,	1,	PATTERN_TEST,	0x0000FFFF,	0xFFFFFFFF },
	{ IGC_FCT,	1,	PATTERN_TEST,	0x0000FFFF,	0xFFFFFFFF },
	{ IGC_RDBAH(0), 4,	PATTERN_TEST,	0xFFFFFFFF,	0xFFFFFFFF },
	{ IGC_RDBAL(0),	4,	PATTERN_TEST,	0xFFFFFF80,	0xFFFFFF80 },
	{ IGC_RDLEN(0),	4,	PATTERN_TEST,	0x000FFF80,	0x000FFFFF },
	{ IGC_RDT(0),	4,	PATTERN_TEST,	0x0000FFFF,	0x0000FFFF },
	{ IGC_FCRTH,	1,	PATTERN_TEST,	0x0003FFF0,	0x0003FFF0 },
	{ IGC_FCTTV,	1,	PATTERN_TEST,	0x0000FFFF,	0x0000FFFF },
	{ IGC_TIPG,	1,	PATTERN_TEST,	0x3FFFFFFF,	0x3FFFFFFF },
	{ IGC_TDBAH(0),	4,	PATTERN_TEST,	0xFFFFFFFF,	0xFFFFFFFF },
	{ IGC_TDBAL(0),	4,	PATTERN_TEST,	0xFFFFFF80,	0xFFFFFF80 },
	{ IGC_TDLEN(0),	4,	PATTERN_TEST,	0x000FFF80,	0x000FFFFF },
	{ IGC_TDT(0),	4,	PATTERN_TEST,	0x0000FFFF,	0x0000FFFF },
	{ IGC_RCTL,	1,	SET_READ_TEST,	0xFFFFFFFF,	0x00000000 },
	{ IGC_RCTL,	1,	SET_READ_TEST,	0x04CFB2FE,	0x003FFFFB },
	{ IGC_RCTL,	1,	SET_READ_TEST,	0x04CFB2FE,	0xFFFFFFFF },
	{ IGC_TCTL,	1,	SET_READ_TEST,	0xFFFFFFFF,	0x00000000 },
	{ IGC_RA,	16,	TABLE64_TEST_LO,
						0xFFFFFFFF,	0xFFFFFFFF },
	{ IGC_RA,	16,	TABLE64_TEST_HI,
						0x900FFFFF,	0xFFFFFFFF },
	{ IGC_MTA,	128,	TABLE32_TEST,
						0xFFFFFFFF,	0xFFFFFFFF },
	{ 0, 0, 0, 0}
};

static bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg,
			     u32 mask, u32 write)
{
	struct igc_hw *hw = &adapter->hw;
	u32 pat, val, before;
	static const u32 test_pattern[] = {
		0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
	};

	for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
		before = rd32(reg);
		wr32(reg, test_pattern[pat] & write);
		val = rd32(reg);
		if (val != (test_pattern[pat] & write & mask)) {
			netdev_err(adapter->netdev,
				   "pattern test reg %04X failed: got 0x%08X expected 0x%08X",
				   reg, val, test_pattern[pat] & write & mask);
			*data = reg;
			wr32(reg, before);
			return false;
		}
		wr32(reg, before);
	}
	return true;
}

static bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg,
			      u32 mask, u32 write)
{
	struct igc_hw *hw = &adapter->hw;
	u32 val, before;

	before = rd32(reg);
	wr32(reg, write & mask);
	val = rd32(reg);
	if ((write & mask) != (val & mask)) {
		netdev_err(adapter->netdev,
			   "set/check reg %04X test failed: got 0x%08X expected 0x%08X",
			   reg, (val & mask), (write & mask));
		*data = reg;
		wr32(reg, before);
		return false;
	}
	wr32(reg, before);
	return true;
}

bool igc_reg_test(struct igc_adapter *adapter, u64 *data)
{
	struct igc_reg_test *test = reg_test;
	struct igc_hw *hw = &adapter->hw;
	u32 value, before, after;
	u32 i, toggle, b = false;

	/* Because the status register is such a special case,
	 * we handle it separately from the rest of the register
	 * tests.  Some bits are read-only, some toggle, and some
	 * are writeable.
	 */
	toggle = 0x6800D3;
	before = rd32(IGC_STATUS);
	value = before & toggle;
	wr32(IGC_STATUS, toggle);
	after = rd32(IGC_STATUS) & toggle;
	if (value != after) {
		netdev_err(adapter->netdev,
			   "failed STATUS register test got: 0x%08X expected: 0x%08X",
			   after, value);
		*data = 1;
		return false;
	}
	/* restore previous status */
	wr32(IGC_STATUS, before);

	/* Perform the remainder of the register test, looping through
	 * the test table until we either fail or reach the null entry.
	 */
	while (test->reg) {
		for (i = 0; i < test->array_len; i++) {
			switch (test->test_type) {
			case PATTERN_TEST:
				b = reg_pattern_test(adapter, data,
						     test->reg + (i * 0x40),
						     test->mask,
						     test->write);
				break;
			case SET_READ_TEST:
				b = reg_set_and_check(adapter, data,
						      test->reg + (i * 0x40),
						      test->mask,
						      test->write);
				break;
			case TABLE64_TEST_LO:
				b = reg_pattern_test(adapter, data,
						     test->reg + (i * 8),
						     test->mask,
						     test->write);
				break;
			case TABLE64_TEST_HI:
				b = reg_pattern_test(adapter, data,
						     test->reg + 4 + (i * 8),
						     test->mask,
						     test->write);
				break;
			case TABLE32_TEST:
				b = reg_pattern_test(adapter, data,
						     test->reg + (i * 4),
						     test->mask,
						     test->write);
				break;
			}
			if (!b)
				return false;
		}
		test++;
	}
	*data = 0;
	return true;
}

bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data)
{
	struct igc_hw *hw = &adapter->hw;

	*data = 0;

	if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) {
		*data = 1;
		return false;
	}

	return true;
}

bool igc_link_test(struct igc_adapter *adapter, u64 *data)
{
	bool link_up;

	*data = 0;

	/* add delay to give enough time for autonegotioation to finish */
	if (adapter->hw.mac.autoneg)
		ssleep(5);

	link_up = igc_has_link(adapter);
	if (!link_up) {
		*data = 1;
		return false;
	}

	return true;
}
Loading