git: 2b8df536a681 - main - axgbe: Various stability improvements

From: Warner Losh <imp_at_FreeBSD.org>
Date: Mon, 29 Apr 2024 02:41:38 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=2b8df536a68169953a9fa470b78a021156d997aa

commit 2b8df536a68169953a9fa470b78a021156d997aa
Author:     Stephan de Wit <stephan.de.wit@deciso.com>
AuthorDate: 2024-04-29 01:57:26 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-04-29 01:57:51 +0000

    axgbe: Various stability improvements
    
    Hook in RSS glue.
    
    Default to "off" for the split header feature to ensure netmap
    compatibility.
    
    Change the PCS indirection register values based on hardware type
    (ported from Linux).
    
    Move tunable settings to sysctl_init() and set the defaults there.
    Ensure it's called at the right time by moving it back.
    
    Reset PHY RX data path when mailbox command times out (Ported from
    Linux).
    
    Check if VLAN HW tagging is enabled before assuming a VLAN tag
    is present in a descriptor.
    
    Disable the hardware filter since multicast traffic is dropped
    in promisc mode.
    
    Remove unnecessary return statement.
    
    Missing sfp_get_mux, causing a race between ports to read
    SFP(+) sideband signals.
    
    Validate and fix incorrectly initialized polarity/configuration
    registers.
    
    Remove unnecessary SFP reset.
    
    axgbe_isc_rxd_pkt_get has no error state, remove unnecessary
    big packet check.
    
    Enable RSF to prevent zero-length packets while in Netmap mode.
    
    DMA cache coherency update (ported from Linux).
    
    Reviewed by: imp
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1103
---
 sys/dev/axgbe/if_axgbe_pci.c |  98 +++++++++++++++++------
 sys/dev/axgbe/xgbe-common.h  |  16 ++++
 sys/dev/axgbe/xgbe-dev.c     |   9 ++-
 sys/dev/axgbe/xgbe-i2c.c     |   2 -
 sys/dev/axgbe/xgbe-phy-v2.c  | 186 +++++++++++++++++++++++++++++++++++++++++--
 sys/dev/axgbe/xgbe-sysctl.c  |  16 ++++
 sys/dev/axgbe/xgbe-txrx.c    |   7 +-
 sys/dev/axgbe/xgbe.h         |   6 +-
 8 files changed, 298 insertions(+), 42 deletions(-)

diff --git a/sys/dev/axgbe/if_axgbe_pci.c b/sys/dev/axgbe/if_axgbe_pci.c
index beb4ff338dc7..3e68525067fb 100644
--- a/sys/dev/axgbe/if_axgbe_pci.c
+++ b/sys/dev/axgbe/if_axgbe_pci.c
@@ -56,6 +56,12 @@
 #include "ifdi_if.h"
 #include "opt_inet.h"
 #include "opt_inet6.h"
+#include "opt_rss.h"
+
+#ifdef RSS
+#include <net/rss_config.h>
+#include <netinet/in_rss.h>
+#endif
 
 MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data");
 
@@ -103,6 +109,7 @@ static bool axgbe_if_needs_restart(if_ctx_t, enum iflib_restart_event);
 #endif
 static void axgbe_set_counts(if_ctx_t);
 static void axgbe_init_iflib_softc_ctx(struct axgbe_if_softc *);
+static void axgbe_initialize_rss_mapping(struct xgbe_prv_data *);
 
 /* MII interface registered functions */
 static int axgbe_miibus_readreg(device_t, int, int);
@@ -277,11 +284,11 @@ axgbe_register(device_t dev)
 		 * No tunable found, generate one with default values
 		 * Note: only a reboot will reveal the new kenv
 		 */
-		error = kern_setenv("dev.ax.sph_enable", "1");
+		error = kern_setenv("dev.ax.sph_enable", "0");
 		if (error) {
 			printf("Error setting tunable, using default driver values\n");
 		}
-		axgbe_sph_enable = 1;
+		axgbe_sph_enable = 0;
 	}
 
 	if (!axgbe_sph_enable) {
@@ -389,6 +396,7 @@ axgbe_if_attach_pre(if_ctx_t ctx)
 	if_softc_ctx_t		scctx;
 	if_shared_ctx_t		sctx;
 	device_t		dev;
+	device_t		rdev;
 	unsigned int		ma_lo, ma_hi;
 	unsigned int		reg;
 	int			ret;
@@ -430,9 +438,23 @@ axgbe_if_attach_pre(if_ctx_t ctx)
         sc->pdata.xgmac_res = mac_res[0];
         sc->pdata.xpcs_res = mac_res[1];
 
-        /* Set the PCS indirect addressing definition registers*/
-	pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF;
-	pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT;
+	/*
+	 * Set the PCS indirect addressing definition registers.
+	 * A newer version of the hardware is using the same PCI ids
+	 * for the network device but has altered register definitions
+	 * for determining the window settings for the indirect PCS access.
+	 * This code checks hardware usage and uses the register values
+	 * accordingly.
+	 */
+	rdev = pci_find_dbsf(0, 0, 0, 0);
+	if (rdev && pci_get_device(rdev) == 0x15d0
+		&& pci_get_vendor(rdev) == 0x1022) {
+		pdata->xpcs_window_def_reg = PCS_V2_RV_WINDOW_DEF;
+		pdata->xpcs_window_sel_reg = PCS_V2_RV_WINDOW_SELECT;
+	} else {
+		pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF;
+		pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT;
+	}
 
         /* Configure the PCS indirect addressing support */
 	reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg);
@@ -714,6 +736,47 @@ axgbe_init_iflib_softc_ctx(struct axgbe_if_softc *sc)
 	scctx->isc_txrx = &axgbe_txrx;
 }
 
+static void
+axgbe_initialize_rss_mapping(struct xgbe_prv_data *pdata)
+{
+	int i;
+
+	/* Get RSS key */
+#ifdef	RSS
+	int	qid;
+	uint32_t	rss_hash_config = 0;
+
+	rss_getkey((uint8_t *)&pdata->rss_key);
+
+	rss_hash_config = rss_gethashconfig();
+
+	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
+		XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, IP2TE, 1);
+	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
+		XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
+	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
+		XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
+#else
+	arc4rand(&pdata->rss_key, ARRAY_SIZE(pdata->rss_key), 0);
+
+	XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, IP2TE, 1);
+	XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
+	XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
+#endif
+
+	/* Setup RSS lookup table */
+	for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++) {
+#ifdef	RSS
+		qid = rss_get_indirection_to_bucket(i) % pdata->rx_ring_count;
+		XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH, qid);
+#else
+		XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH,
+				i % pdata->rx_ring_count);
+#endif
+	}
+
+}
+
 static int
 axgbe_alloc_channels(if_ctx_t ctx)
 {
@@ -1336,11 +1399,9 @@ xgbe_default_config(struct xgbe_prv_data *pdata)
         pdata->tx_sf_mode = MTL_TSF_ENABLE;
         pdata->tx_threshold = MTL_TX_THRESHOLD_64;
         pdata->tx_osp_mode = DMA_OSP_ENABLE;
-        pdata->rx_sf_mode = MTL_RSF_DISABLE;
+        pdata->rx_sf_mode = MTL_RSF_ENABLE;
         pdata->rx_threshold = MTL_RX_THRESHOLD_64;
         pdata->pause_autoneg = 1;
-        pdata->tx_pause = 1;
-        pdata->rx_pause = 1;
         pdata->phy_speed = SPEED_UNKNOWN;
         pdata->power_down = 0;
         pdata->enable_rss = 1;
@@ -1355,7 +1416,7 @@ axgbe_if_attach_post(if_ctx_t ctx)
         struct xgbe_phy_if	*phy_if = &pdata->phy_if;
 	struct xgbe_hw_if 	*hw_if = &pdata->hw_if;
 	if_softc_ctx_t		scctx = sc->scctx;
-	int i, ret;
+	int ret;
 
 	/* set split header support based on tunable */
 	pdata->sph_enable = axgbe_sph_enable;
@@ -1373,6 +1434,8 @@ axgbe_if_attach_post(if_ctx_t ctx)
 	if (ret)
 		axgbe_error("%s: exit error %d\n", __func__, ret);
 
+	axgbe_sysctl_init(pdata);
+
 	/* Configure the defaults */
 	xgbe_default_config(pdata);
 
@@ -1408,15 +1471,7 @@ axgbe_if_attach_post(if_ctx_t ctx)
 	    scctx->isc_nrxqsets);
 	DBGPR("Channel count set to: %u\n", pdata->channel_count);
 
-	/* Get RSS key */
-#ifdef	RSS
-	rss_getkey((uint8_t *)pdata->rss_key);
-#else
-	arc4rand(&pdata->rss_key, ARRAY_SIZE(pdata->rss_key), 0);
-#endif
-	XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, IP2TE, 1);
-	XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
-	XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
+	axgbe_initialize_rss_mapping(pdata);
 
 	/* Initialize the PHY device */
 	pdata->sysctl_an_cdr_workaround = pdata->vdata->an_cdr_workaround;
@@ -1452,11 +1507,6 @@ axgbe_if_attach_post(if_ctx_t ctx)
 	pdata->rx_buf_size = ret;
 	DBGPR("%s: rx_buf_size %d\n", __func__, ret);
 
-	/* Setup RSS lookup table */
-	for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++)
-		XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH,
-				i % pdata->rx_ring_count);
-
 	/* 
 	 * Mark the device down until it is initialized, which happens
 	 * when the device is accessed first (for configuring the iface,
@@ -1468,8 +1518,6 @@ axgbe_if_attach_post(if_ctx_t ctx)
 	scctx->isc_max_frame_size = if_getmtu(ifp) + 18;
 	scctx->isc_min_frame_size = XGMAC_MIN_PACKET;
 
-	axgbe_sysctl_init(pdata);
-
 	axgbe_pci_init(pdata);
 
 	return (0);
diff --git a/sys/dev/axgbe/xgbe-common.h b/sys/dev/axgbe/xgbe-common.h
index 4d504682d1af..e2096463703b 100644
--- a/sys/dev/axgbe/xgbe-common.h
+++ b/sys/dev/axgbe/xgbe-common.h
@@ -479,6 +479,8 @@
 #define MAC_PFR_VTFE_WIDTH		1
 #define MAC_PFR_VUCC_INDEX		22
 #define MAC_PFR_VUCC_WIDTH		1
+#define MAC_PFR_RA_INDEX		31
+#define MAC_PFR_RA_WIDTH		1
 #define MAC_PMTCSR_MGKPKTEN_INDEX	1
 #define MAC_PMTCSR_MGKPKTEN_WIDTH	1
 #define MAC_PMTCSR_PWRDWN_INDEX		0
@@ -1319,10 +1321,18 @@
 #define MDIO_PMA_10GBR_FECCTRL		0x00ab
 #endif
 
+#ifndef MDIO_PMA_RX_CTRL1
+#define MDIO_PMA_RX_CTRL1		0x8051
+#endif
+
 #ifndef MDIO_PCS_DIG_CTRL
 #define MDIO_PCS_DIG_CTRL		0x8000
 #endif
 
+#ifndef MDIO_PCS_DIGITAL_STAT
+#define MDIO_PCS_DIGITAL_STAT		0x8010
+#endif
+
 #ifndef MDIO_AN_XNP
 #define MDIO_AN_XNP			0x0016
 #endif
@@ -1402,6 +1412,8 @@
 #define XGBE_KR_TRAINING_ENABLE		BIT(1)
 
 #define XGBE_PCS_CL37_BP		BIT(12)
+#define XGBE_PCS_PSEQ_STATE_MASK	0x1c
+#define XGBE_PCS_PSEQ_STATE_POWER_GOOD	0x10
 
 #define XGBE_AN_CL37_INT_CMPLT		BIT(0)
 #define XGBE_AN_CL37_INT_MASK		0x01
@@ -1423,6 +1435,10 @@
 #define XGBE_PMA_PLL_CTRL_ENABLE	BIT(15)
 #define XGBE_PMA_PLL_CTRL_DISABLE	0x0000
 
+#define XGBE_PMA_RX_RST_0_MASK		BIT(4)
+#define XGBE_PMA_RX_RST_0_RESET_ON	0x10
+#define XGBE_PMA_RX_RST_0_RESET_OFF	0x00
+
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
diff --git a/sys/dev/axgbe/xgbe-dev.c b/sys/dev/axgbe/xgbe-dev.c
index 786e04930780..39d0dab144a2 100644
--- a/sys/dev/axgbe/xgbe-dev.c
+++ b/sys/dev/axgbe/xgbe-dev.c
@@ -1451,7 +1451,8 @@ xgbe_dev_read(struct xgbe_channel *channel)
 
 	if (!err || !etlt) {
 		/* No error if err is 0 or etlt is 0 */
-		if (etlt == 0x09) {
+		if (etlt == 0x09 &&
+		    (if_getcapenable(pdata->netdev) & IFCAP_VLAN_HWTAGGING)) {
 			XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
 			    VLAN_CTAG, 1);
 			packet->vlan_ctag = XGMAC_GET_BITS_LE(rdesc->desc0,
@@ -2029,6 +2030,12 @@ xgbe_config_mac_address(struct xgbe_prv_data *pdata)
 {
 	xgbe_set_mac_address(pdata, if_getlladdr(pdata->netdev));
 
+	/*
+	 * Promisc mode does not work as intended. Multicast traffic
+	 * is triggering the filter, so enable Receive All.
+	 */
+	XGMAC_IOWRITE_BITS(pdata, MAC_PFR, RA, 1);
+
 	/* Filtering is done using perfect filtering and hash filtering */
 	if (pdata->hw_feat.hash_table_size) {
 		XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1);
diff --git a/sys/dev/axgbe/xgbe-i2c.c b/sys/dev/axgbe/xgbe-i2c.c
index 5883e96ed37e..fe9184aa1dd5 100644
--- a/sys/dev/axgbe/xgbe-i2c.c
+++ b/sys/dev/axgbe/xgbe-i2c.c
@@ -327,8 +327,6 @@ out:
 	if (state->ret || XI2C_GET_BITS(isr, IC_RAW_INTR_STAT, STOP_DET))
 		pdata->i2c_complete = true;
 
-	return;
-
 reissue_check:
 	/* Reissue interrupt if status is not clear */
 	if (pdata->vdata->irq_reissue_support)
diff --git a/sys/dev/axgbe/xgbe-phy-v2.c b/sys/dev/axgbe/xgbe-phy-v2.c
index d8c372cac642..d08ed118a8a8 100644
--- a/sys/dev/axgbe/xgbe-phy-v2.c
+++ b/sys/dev/axgbe/xgbe-phy-v2.c
@@ -376,6 +376,9 @@ struct xgbe_phy_data {
 	unsigned int sfp_gpio_address;
 	unsigned int sfp_gpio_mask;
 	unsigned int sfp_gpio_inputs;
+	unsigned int sfp_gpio_outputs;
+	unsigned int sfp_gpio_polarity;
+	unsigned int sfp_gpio_configuration;
 	unsigned int sfp_gpio_rx_los;
 	unsigned int sfp_gpio_tx_fault;
 	unsigned int sfp_gpio_mod_absent;
@@ -1461,13 +1464,19 @@ xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
 	axgbe_printf(3, "%s: befor sfp_mod:%d sfp_gpio_address:0x%x\n",
 	    __func__, phy_data->sfp_mod_absent, phy_data->sfp_gpio_address);
 
+	ret = xgbe_phy_sfp_get_mux(pdata);
+	if (ret) {
+		axgbe_error("I2C error setting SFP MUX\n");
+		return;
+	}
+
 	gpio_reg = 0;
 	ret = xgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address, &gpio_reg,
 	    sizeof(gpio_reg), gpio_ports, sizeof(gpio_ports));
 	if (ret) {
 		axgbe_error("%s: I2C error reading SFP GPIO addr:0x%x\n",
 		    __func__, phy_data->sfp_gpio_address);
-		return;
+		goto put_mux;
 	}
 
 	phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0];
@@ -1481,6 +1490,136 @@ xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata)
 
 	axgbe_printf(3, "%s: after sfp_mod:%d sfp_gpio_inputs:0x%x\n",
 	    __func__, phy_data->sfp_mod_absent, phy_data->sfp_gpio_inputs);
+
+put_mux:
+	xgbe_phy_sfp_put_mux(pdata);
+}
+
+static int
+xgbe_read_gpio_expander(struct xgbe_prv_data *pdata)
+{
+	struct xgbe_phy_data *phy_data = pdata->phy_data;
+	uint8_t gpio_reg, gpio_ports[2];
+	int ret = 0;
+
+	ret = xgbe_phy_sfp_get_mux(pdata);
+	if (ret) {
+		axgbe_error("I2C error setting SFP MUX\n");
+		return (ret);
+	}
+
+	gpio_reg = 2;
+	for (int i = 0; i < 3; i++) {
+		ret = xgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address,
+			&gpio_reg, sizeof(gpio_reg), gpio_ports, sizeof(gpio_ports));
+
+		if (ret) {
+			axgbe_error("%s: I2C error reading GPIO expander register: %d\n",
+			    __func__, gpio_reg);
+			goto put_mux;
+		}
+
+		if (gpio_reg == 2)
+			phy_data->sfp_gpio_outputs = (gpio_ports[1] << 8) | gpio_ports[0];
+		else if (gpio_reg == 4)
+			phy_data->sfp_gpio_polarity = (gpio_ports[1] << 8) | gpio_ports[0];
+		else if (gpio_reg == 6)
+			phy_data->sfp_gpio_configuration = (gpio_ports[1] << 8) | gpio_ports[0];
+
+		memset(gpio_ports, 0, sizeof(gpio_ports));
+		gpio_reg += 2;
+	}
+
+put_mux:
+	xgbe_phy_sfp_put_mux(pdata);
+
+	return (ret);
+}
+
+static void
+xgbe_log_gpio_expander(struct xgbe_prv_data *pdata)
+{
+	struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+	axgbe_printf(1, "Input port registers: 0x%x\n", phy_data->sfp_gpio_inputs);
+	axgbe_printf(1, "Output port registers: 0x%x\n", phy_data->sfp_gpio_outputs);
+	axgbe_printf(1, "Polarity port registers: 0x%x\n", phy_data->sfp_gpio_polarity);
+	axgbe_printf(1, "Configuration port registers: 0x%x\n", phy_data->sfp_gpio_configuration);
+}
+
+static int
+xgbe_phy_validate_gpio_expander(struct xgbe_prv_data *pdata)
+{
+	struct xgbe_phy_data *phy_data = pdata->phy_data;
+	uint8_t gpio_data[3] = {0};
+	int shift = GPIO_MASK_WIDTH * (3 - phy_data->port_id);
+	int rx_los_pos = (1 << phy_data->sfp_gpio_rx_los);
+	int tx_fault_pos = (1 << phy_data->sfp_gpio_tx_fault);
+	int mod_abs_pos = (1 << phy_data->sfp_gpio_mod_absent);
+	int port_sfp_pins = (mod_abs_pos | rx_los_pos | tx_fault_pos);
+	uint16_t config = 0;
+	int ret = 0;
+
+	ret = xgbe_phy_get_comm_ownership(pdata);
+	if (ret)
+		return (ret);
+
+	ret = xgbe_read_gpio_expander(pdata);
+	if (ret)
+		goto put;
+
+	ret = xgbe_phy_sfp_get_mux(pdata);
+	if (ret) {
+		axgbe_error("I2C error setting SFP MUX\n");
+		goto put;
+	}
+
+	if (phy_data->sfp_gpio_polarity) {
+		axgbe_printf(0, "GPIO polarity inverted, resetting\n");
+
+		xgbe_log_gpio_expander(pdata);
+		gpio_data[0] = 4; /* polarity register */
+
+		ret = xgbe_phy_i2c_write(pdata, phy_data->sfp_gpio_address,
+			gpio_data, sizeof(gpio_data));
+
+		if (ret) {
+			axgbe_error("%s: I2C error writing to GPIO polarity register\n",
+				__func__);
+			goto put_mux;
+		}
+	}
+
+	config = phy_data->sfp_gpio_configuration;
+	if ((config & port_sfp_pins) != port_sfp_pins) {
+		xgbe_log_gpio_expander(pdata);
+
+		/* Write the I/O states to the configuration register */
+		axgbe_error("Invalid GPIO configuration, resetting\n");
+		gpio_data[0] = 6; /* configuration register */
+		config = config & ~(0xF << shift); /* clear port id bits */
+		config |= port_sfp_pins;
+		gpio_data[1] = config & 0xff;
+		gpio_data[2] = (config >> 8);
+
+		ret = xgbe_phy_i2c_write(pdata, phy_data->sfp_gpio_address,
+			gpio_data, sizeof(gpio_data));
+		if (ret) {
+			axgbe_error("%s: I2C error writing to GPIO configuration register\n",
+				__func__);
+			goto put_mux;
+		}
+	} else {
+		axgbe_printf(0, "GPIO configuration valid\n");
+	}
+
+put_mux:
+	xgbe_phy_sfp_put_mux(pdata);
+
+put:
+	xgbe_phy_put_comm_ownership(pdata);
+
+	return (ret);
 }
 
 static void
@@ -1512,9 +1651,6 @@ xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata)
 	struct xgbe_phy_data *phy_data = pdata->phy_data;
 	int ret, prev_sfp_state = phy_data->sfp_mod_absent;
 
-	/* Reset the SFP signals and info */
-	xgbe_phy_sfp_reset(phy_data);
-
 	ret = xgbe_phy_get_comm_ownership(pdata);
 	if (ret)
 		return;
@@ -1532,6 +1668,11 @@ xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata)
 	if (ret) {
 		/* Treat any error as if there isn't an SFP plugged in */
 		axgbe_error("%s: eeprom read failed\n", __func__);
+		ret = xgbe_read_gpio_expander(pdata);
+
+		if (!ret)
+			xgbe_log_gpio_expander(pdata);
+
 		xgbe_phy_sfp_reset(phy_data);
 		xgbe_phy_sfp_mod_absent(pdata);
 		goto put;
@@ -2102,6 +2243,30 @@ xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable)
 	DELAY(200);
 }
 
+static void
+xgbe_phy_rx_reset(struct xgbe_prv_data *pdata)
+{
+	int reg;
+
+	reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT,
+			     XGBE_PCS_PSEQ_STATE_MASK);
+
+	if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) {
+		/*
+	         * Mailbox command timed out, reset of RX block is required.
+		 * This can be done by asserting the reset bit and waiting
+		 * for its completion.
+		 */
+		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
+				XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON);
+		DELAY(20);
+		XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
+				XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF);
+		DELAY(50);
+		axgbe_printf(0, "%s: firmware mailbox reset performed\n", __func__);
+	}
+}
+
 static void
 xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd,
     unsigned int sub_cmd)
@@ -2112,8 +2277,10 @@ xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd,
 	xgbe_phy_pll_ctrl(pdata, false);
 
 	/* Log if a previous command did not complete */
-	if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
+	if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) {
 		axgbe_error("firmware mailbox not ready for command\n");
+		xgbe_phy_rx_reset(pdata);
+	}
 
 	/* Construct the command */
 	XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd);
@@ -3467,6 +3634,15 @@ xgbe_phy_start(struct xgbe_prv_data *pdata)
 	switch (phy_data->port_mode) {
 	case XGBE_PORT_MODE_SFP:
 		axgbe_printf(3, "%s: calling phy detect\n", __func__);
+
+		/*
+		 * Validate the configuration of the GPIO expander before
+		 * we interpret the SFP signals.
+		 */
+		axgbe_printf(1, "Checking GPIO expander validity\n");
+		xgbe_phy_validate_gpio_expander(pdata);
+
+		phy_data->sfp_phy_retries = 0;
 		xgbe_phy_sfp_detect(pdata);
 		break;
 	default:
diff --git a/sys/dev/axgbe/xgbe-sysctl.c b/sys/dev/axgbe/xgbe-sysctl.c
index d5ddfbbd0bd6..16523381e1a3 100644
--- a/sys/dev/axgbe/xgbe-sysctl.c
+++ b/sys/dev/axgbe/xgbe-sysctl.c
@@ -1607,6 +1607,10 @@ axgbe_sysctl_init(struct xgbe_prv_data *pdata)
 	pdata->sysctl_xgmac_reg = 0;
 	pdata->sysctl_xpcs_mmd = 1;
 	pdata->sysctl_xpcs_reg = 0;
+	pdata->link_workaround = 1;
+	pdata->tx_pause = 1;
+	pdata->rx_pause = 1;
+	pdata->enable_rss = 1;
 
 	SYSCTL_ADD_UINT(clist, top, OID_AUTO, "axgbe_debug_level", CTLFLAG_RWTUN,
 	    &pdata->debug_level, 0, "axgbe log level -- higher is verbose");
@@ -1619,6 +1623,18 @@ axgbe_sysctl_init(struct xgbe_prv_data *pdata)
 	    CTLFLAG_RWTUN, &pdata->link_workaround, 0,
 	    "enable the workaround for link issue in coming up");
 
+	SYSCTL_ADD_UINT(clist, top, OID_AUTO, "rss_enabled",
+		CTLFLAG_RDTUN, &pdata->enable_rss, 1,
+		"shows the RSS feature state (1 - enable, 0 - disable)");
+
+	SYSCTL_ADD_UINT(clist, top, OID_AUTO, "tx_pause",
+		CTLFLAG_RDTUN, &pdata->tx_pause, 1,
+		"shows the Flow Control TX pause feature state (1 - enable, 0 - disable)");
+
+	SYSCTL_ADD_UINT(clist, top, OID_AUTO, "rx_pause",
+		CTLFLAG_RDTUN, &pdata->rx_pause, 1,
+		"shows the Flow Control RX pause feature state (1 - enable, 0 - disable)");
+
 	SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xgmac_register",
 	    CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
 	    pdata, 0, sysctl_xgmac_reg_addr_handler, "IU",
diff --git a/sys/dev/axgbe/xgbe-txrx.c b/sys/dev/axgbe/xgbe-txrx.c
index 52274dba4352..fd3d821e2e53 100644
--- a/sys/dev/axgbe/xgbe-txrx.c
+++ b/sys/dev/axgbe/xgbe-txrx.c
@@ -702,7 +702,7 @@ axgbe_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
 	struct xgbe_packet_data *packet = &ring->packet_data;
 	struct xgbe_ring_data	*rdata;
 	unsigned int last, context_next, context;
-	unsigned int buf1_len, buf2_len, max_len, len = 0, prev_cur;
+	unsigned int buf1_len, buf2_len, len = 0, prev_cur;
 	int i = 0;
 
 	axgbe_printf(2, "%s: rxq %d cidx %d cur %d dirty %d\n", __func__,
@@ -767,11 +767,9 @@ read_again:
 		axgbe_printf(2, "%s: csum flags 0x%x\n", __func__, ri->iri_csum_flags);
 	}
 
-	max_len = if_getmtu(pdata->netdev) + ETH_HLEN;
 	if (XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, VLAN_CTAG)) {
 		ri->iri_flags |= M_VLANTAG;
 		ri->iri_vtag = packet->vlan_ctag;
-		max_len += VLAN_HLEN;
 		axgbe_printf(2, "%s: iri_flags 0x%x vtag 0x%x\n", __func__,
 		    ri->iri_flags, ri->iri_vtag);
 	}
@@ -788,9 +786,6 @@ read_again:
 	if (__predict_false(len == 0))
 		axgbe_printf(1, "%s: Discarding Zero len packet\n", __func__);
 
-	if (__predict_false(len > max_len))
-		axgbe_error("%s: Big packet %d/%d\n", __func__, len, max_len);
-
 	if (__predict_false(packet->errors))
 		axgbe_printf(1, "<-- %s: rxq: %d len: %d frags: %d cidx %d cur: %d "
 		    "dirty: %d error 0x%x\n", __func__, ri->iri_qsidx, len, i,
diff --git a/sys/dev/axgbe/xgbe.h b/sys/dev/axgbe/xgbe.h
index 4719b16f47d6..5e4cc40bb2c9 100644
--- a/sys/dev/axgbe/xgbe.h
+++ b/sys/dev/axgbe/xgbe.h
@@ -180,9 +180,9 @@
 #define XGBE_DMA_SYS_AWCR	0x30303030
 
 /* DMA cache settings - PCI device */
-#define XGBE_DMA_PCI_ARCR	0x00000003
-#define XGBE_DMA_PCI_AWCR	0x13131313
-#define XGBE_DMA_PCI_AWARCR	0x00000313
+#define XGBE_DMA_PCI_ARCR	0x000f0f0f
+#define XGBE_DMA_PCI_AWCR	0x0f0f0f0f
+#define XGBE_DMA_PCI_AWARCR	0x00000f0f
 
 /* DMA channel interrupt modes */
 #define XGBE_IRQ_MODE_EDGE	0