Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jun 2018 20:34:53 +0000 (UTC)
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org
Subject:   svn commit: r334631 - in releng/11.2/sys/dev/cxgbe: . common
Message-ID:  <201806042034.w54KYraX050833@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Mon Jun  4 20:34:53 2018
New Revision: 334631
URL: https://svnweb.freebsd.org/changeset/base/334631

Log:
  Merge r334562 from stable/11 to releng/11.2.  r334562 MFC'd the
  following revisions to stable/11: r333650, r333652, r333682, r334406,
  r334409-r334410, and r334489.
  
  r333650:
  cxgbe(4): Claim some more T5 and T6 boards.
  
  r333652:
  cxgbe(4): Add support for two more flash parts.
  
  r333682:
  cxgbe(4): Fall back to a failsafe configuration built into the firmware
  if an error is reported while pre-processing the configuration file that
  the driver attempted to use.
  
  Also, allow the user to explicitly use the built-in configuration with
  hw.cxgbe.config_file="built-in"
  
  r334406:
  cxgbe(4): Consider all supported speeds when building the ifmedia list
  for a port.  Fix other related issues while here:
  - Require port lock for access to link_config.
  - Allow 100Mbps operation by tracking the speed in Mbps.  Yes, really.
  - New port flag to indicate that the media list is immutable.  It will
    be used in future refinements.
  
  This also fixes a bug where the driver reports incorrect media with
  recent firmwares.
  
  r334409:
  cxgbe(4): Implement ifm_change callback.
  
  r334410:
  cxgbe(4): Use ifm for ifmedia just like the rest of the kernel.
  
  No functional change.
  
  r334489:
  cxgbe(4): Include full duplex mediaopt in media that can be reported as
  active.  Always report full duplex in active media.
  
  Approved by:	re@ (gjb@, kib@)
  Sponsored by:	Chelsio Communications

Modified:
  releng/11.2/sys/dev/cxgbe/adapter.h
  releng/11.2/sys/dev/cxgbe/common/common.h
  releng/11.2/sys/dev/cxgbe/common/t4_hw.c
  releng/11.2/sys/dev/cxgbe/t4_main.c
Directory Properties:
  releng/11.2/   (props changed)

Modified: releng/11.2/sys/dev/cxgbe/adapter.h
==============================================================================
--- releng/11.2/sys/dev/cxgbe/adapter.h	Mon Jun  4 20:24:31 2018	(r334630)
+++ releng/11.2/sys/dev/cxgbe/adapter.h	Mon Jun  4 20:34:53 2018	(r334631)
@@ -162,6 +162,7 @@ enum {
 
 	/* port flags */
 	HAS_TRACEQ	= (1 << 3),
+	FIXED_IFMEDIA	= (1 << 4),	/* ifmedia list doesn't change. */
 
 	/* VI flags */
 	DOOMED		= (1 << 0),

Modified: releng/11.2/sys/dev/cxgbe/common/common.h
==============================================================================
--- releng/11.2/sys/dev/cxgbe/common/common.h	Mon Jun  4 20:24:31 2018	(r334630)
+++ releng/11.2/sys/dev/cxgbe/common/common.h	Mon Jun  4 20:34:53 2018	(r334631)
@@ -413,12 +413,12 @@ struct link_config {
 	unsigned char  requested_aneg;   /* link aneg user has requested */
 	unsigned char  requested_fc;     /* flow control user has requested */
 	unsigned char  requested_fec;    /* FEC user has requested */
-	unsigned int   requested_speed;  /* speed user has requested */
+	unsigned int   requested_speed;  /* speed user has requested (Mbps) */
 
 	unsigned short supported;        /* link capabilities */
 	unsigned short advertising;      /* advertised capabilities */
 	unsigned short lp_advertising;   /* peer advertised capabilities */
-	unsigned int   speed;            /* actual link speed */
+	unsigned int   speed;            /* actual link speed (Mbps) */
 	unsigned char  fc;               /* actual link flow control */
 	unsigned char  fec;              /* actual FEC */
 	unsigned char  link_ok;          /* link up? */

Modified: releng/11.2/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- releng/11.2/sys/dev/cxgbe/common/t4_hw.c	Mon Jun  4 20:24:31 2018	(r334630)
+++ releng/11.2/sys/dev/cxgbe/common/t4_hw.c	Mon Jun  4 20:34:53 2018	(r334631)
@@ -3725,21 +3725,24 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int m
 	    lc->requested_aneg == AUTONEG_DISABLE) {
 		aneg = 0;
 		switch (lc->requested_speed) {
-		case 100:
+		case 100000:
 			speed = FW_PORT_CAP_SPEED_100G;
 			break;
-		case 40:
+		case 40000:
 			speed = FW_PORT_CAP_SPEED_40G;
 			break;
-		case 25:
+		case 25000:
 			speed = FW_PORT_CAP_SPEED_25G;
 			break;
-		case 10:
+		case 10000:
 			speed = FW_PORT_CAP_SPEED_10G;
 			break;
-		case 1:
+		case 1000:
 			speed = FW_PORT_CAP_SPEED_1G;
 			break;
+		case 100:
+			speed = FW_PORT_CAP_SPEED_100M;
+			break;
 		default:
 			return -EINVAL;
 			break;
@@ -7713,9 +7716,9 @@ static void handle_port_info(struct port_info *pi, con
 
 	fec = 0;
 	if (lc->advertising & FW_PORT_CAP_FEC_RS)
-		fec |= FEC_RS;
-	if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
-		fec |= FEC_BASER_RS;
+		fec = FEC_RS;
+	else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
+		fec = FEC_BASER_RS;
 	lc->fec = fec;
 }
 
@@ -7776,14 +7779,16 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be6
 		}
 
 		lc = &pi->link_cfg;
+		PORT_LOCK(pi);
 		old_lc = &pi->old_link_cfg;
 		old_ptype = pi->port_type;
 		old_mtype = pi->mod_type;
-
 		handle_port_info(pi, &p->u.info);
+		PORT_UNLOCK(pi);
 		if (old_ptype != pi->port_type || old_mtype != pi->mod_type) {
 			t4_os_portmod_changed(pi);
 		}
+		PORT_LOCK(pi);
 		if (old_lc->link_ok != lc->link_ok ||
 		    old_lc->speed != lc->speed ||
 		    old_lc->fec != lc->fec ||
@@ -7791,6 +7796,7 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be6
 			t4_os_link_changed(pi);
 			*old_lc = *lc;
 		}
+		PORT_UNLOCK(pi);
 	} else {
 		CH_WARN_RATELIMIT(adap, "Unknown firmware reply %d\n", opcode);
 		return -EINVAL;
@@ -7896,6 +7902,44 @@ int t4_get_flash_params(struct adapter *adapter)
 
 		default:
 			CH_ERR(adapter, "Micron Flash Part has bad size, "
+			       "ID = %#x, Density code = %#x\n",
+			       flashid, density);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	case 0x9d: { /* ISSI -- Integrated Silicon Solution, Inc. */
+		/*
+		 * This Density -> Size decoding table is taken from ISSI
+		 * Data Sheets.
+		 */
+		density = (flashid >> 16) & 0xff;
+		switch (density) {
+		case 0x16: size = 1 << 25; break; /*  32MB */
+		case 0x17: size = 1 << 26; break; /*  64MB */
+
+		default:
+			CH_ERR(adapter, "ISSI Flash Part has bad size, "
+			       "ID = %#x, Density code = %#x\n",
+			       flashid, density);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	case 0xc2: { /* Macronix */
+		/*
+		 * This Density -> Size decoding table is taken from Macronix
+		 * Data Sheets.
+		 */
+		density = (flashid >> 16) & 0xff;
+		switch (density) {
+		case 0x17: size = 1 << 23; break; /*   8MB */
+		case 0x18: size = 1 << 24; break; /*  16MB */
+
+		default:
+			CH_ERR(adapter, "Macronix Flash Part has bad size, "
 			       "ID = %#x, Density code = %#x\n",
 			       flashid, density);
 			return -EINVAL;

Modified: releng/11.2/sys/dev/cxgbe/t4_main.c
==============================================================================
--- releng/11.2/sys/dev/cxgbe/t4_main.c	Mon Jun  4 20:24:31 2018	(r334630)
+++ releng/11.2/sys/dev/cxgbe/t4_main.c	Mon Jun  4 20:34:53 2018	(r334631)
@@ -376,9 +376,10 @@ int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX;
 TUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types);
 
 /*
- * Configuration file.
+ * Configuration file.  All the _CF names here are special.
  */
 #define DEFAULT_CF	"default"
+#define BUILTIN_CF	"built-in"
 #define FLASH_CF	"flash"
 #define UWIRE_CF	"uwire"
 #define FPGA_CF		"fpga"
@@ -528,6 +529,7 @@ static int set_params__post_init(struct adapter *);
 static void t4_set_desc(struct adapter *);
 static void build_medialist(struct port_info *, struct ifmedia *);
 static void init_l1cfg(struct port_info *);
+static int apply_l1cfg(struct port_info *);
 static int cxgbe_init_synchronized(struct vi_info *);
 static int cxgbe_uninit_synchronized(struct vi_info *);
 static void quiesce_txq(struct adapter *, struct sge_txq *);
@@ -659,16 +661,10 @@ struct {
 	{0x5412,  "Chelsio T560-CR"},		/* 1 x 40G, 2 x 10G */
 	{0x5414,  "Chelsio T580-LP-SO-CR"},	/* 2 x 40G, nomem */
 	{0x5415,  "Chelsio T502-BT"},		/* 2 x 1G */
-#ifdef notyet
-	{0x5404,  "Chelsio T520-BCH"},
-	{0x5405,  "Chelsio T540-BCH"},
-	{0x5406,  "Chelsio T540-CH"},
-	{0x5408,  "Chelsio T520-CX"},
-	{0x540b,  "Chelsio B520-SR"},
-	{0x540c,  "Chelsio B504-BT"},
-	{0x540f,  "Chelsio Amsterdam"},
-	{0x5413,  "Chelsio T580-CHR"},
-#endif
+	{0x5418,  "Chelsio T540-BT"},		/* 4 x 10GBaseT */
+	{0x5419,  "Chelsio T540-LP-BT"},	/* 4 x 10GBaseT */
+	{0x541a,  "Chelsio T540-SO-BT"},	/* 4 x 10GBaseT, nomem */
+	{0x541b,  "Chelsio T540-SO-CR"},	/* 4 x 10G, nomem */
 }, t6_pciids[] = {
 	{0xc006, "Chelsio Terminator 6 FPGA"},	/* T6 PE10K6 FPGA (PF0) */
 	{0x6400, "Chelsio T6-DBG-25"},		/* 2 x 10/25G, debug */
@@ -688,9 +684,14 @@ struct {
 	{0x6415, "Chelsio T6201-BT"},		/* 2 x 1000BASE-T */
 
 	/* Custom */
-	{0x6480, "Chelsio T6225 80"},
-	{0x6481, "Chelsio T62100 81"},
-	{0x6484, "Chelsio T62100 84"},
+	{0x6480, "Custom T6225-CR"},
+	{0x6481, "Custom T62100-CR"},
+	{0x6482, "Custom T6225-CR"},
+	{0x6483, "Custom T62100-CR"},
+	{0x6484, "Custom T64100-CR"},
+	{0x6485, "Custom T6240-SO"},
+	{0x6486, "Custom T6225-SO-CR"},
+	{0x6487, "Custom T6225-CR"},
 };
 
 #ifdef TCP_OFFLOAD
@@ -2008,78 +2009,248 @@ cxgbe_get_counter(struct ifnet *ifp, ift_counter c)
 	}
 }
 
+/*
+ * The kernel picks a media from the list we had provided so we do not have to
+ * validate the request.
+ */
 static int
 cxgbe_media_change(struct ifnet *ifp)
 {
 	struct vi_info *vi = ifp->if_softc;
+	struct port_info *pi = vi->pi;
+	struct ifmedia *ifm = &pi->media;
+	struct link_config *lc = &pi->link_cfg;
+	struct adapter *sc = pi->adapter;
+	int rc;
 
-	device_printf(vi->dev, "%s unimplemented.\n", __func__);
+	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4mec");
+	if (rc != 0)
+		return (rc);
+	PORT_LOCK(pi);
+	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
+		MPASS(lc->supported & FW_PORT_CAP_ANEG);
+		lc->requested_aneg = AUTONEG_ENABLE;
+	} else {
+		lc->requested_aneg = AUTONEG_DISABLE;
+		lc->requested_speed =
+		    ifmedia_baudrate(ifm->ifm_media) / 1000000;
+		lc->requested_fc = 0;
+		if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE)
+			lc->requested_fc |= PAUSE_RX;
+		if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE)
+			lc->requested_fc |= PAUSE_TX;
+	}
+	if (pi->up_vis > 0)
+		rc = apply_l1cfg(pi);
+	PORT_UNLOCK(pi);
+	end_synchronized_op(sc, 0);
+	return (rc);
+}
 
-	return (EOPNOTSUPP);
+/*
+ * Mbps to FW_PORT_CAP_SPEED_* bit.
+ */
+static uint16_t
+speed_to_fwspeed(int speed)
+{
+
+	switch (speed) {
+	case 100000:
+		return (FW_PORT_CAP_SPEED_100G);
+	case 40000:
+		return (FW_PORT_CAP_SPEED_40G);
+	case 25000:
+		return (FW_PORT_CAP_SPEED_25G);
+	case 10000:
+		return (FW_PORT_CAP_SPEED_10G);
+	case 1000:
+		return (FW_PORT_CAP_SPEED_1G);
+	case 100:
+		return (FW_PORT_CAP_SPEED_100M);
+	}
+
+	return (0);
 }
 
+/*
+ * Base media word (without ETHER, pause, link active, etc.) for the port at the
+ * given speed.
+ */
+static int
+port_mword(struct port_info *pi, uint16_t speed)
+{
+
+	MPASS(speed & M_FW_PORT_CAP_SPEED);
+	MPASS(powerof2(speed));
+
+	switch(pi->port_type) {
+	case FW_PORT_TYPE_BT_SGMII:
+	case FW_PORT_TYPE_BT_XFI:
+	case FW_PORT_TYPE_BT_XAUI:
+		/* BaseT */
+		switch (speed) {
+		case FW_PORT_CAP_SPEED_100M:
+			return (IFM_100_T);
+		case FW_PORT_CAP_SPEED_1G:
+			return (IFM_1000_T);
+		case FW_PORT_CAP_SPEED_10G:
+			return (IFM_10G_T);
+		}
+		break;
+	case FW_PORT_TYPE_KX4:
+		if (speed == FW_PORT_CAP_SPEED_10G)
+			return (IFM_10G_KX4);
+		break;
+	case FW_PORT_TYPE_CX4:
+		if (speed == FW_PORT_CAP_SPEED_10G)
+			return (IFM_10G_CX4);
+		break;
+	case FW_PORT_TYPE_KX:
+		if (speed == FW_PORT_CAP_SPEED_1G)
+			return (IFM_1000_KX);
+		break;
+	case FW_PORT_TYPE_KR:
+	case FW_PORT_TYPE_BP_AP:
+	case FW_PORT_TYPE_BP4_AP:
+	case FW_PORT_TYPE_BP40_BA:
+	case FW_PORT_TYPE_KR4_100G:
+	case FW_PORT_TYPE_KR_SFP28:
+	case FW_PORT_TYPE_KR_XLAUI:
+		switch (speed) {
+		case FW_PORT_CAP_SPEED_1G:
+			return (IFM_1000_KX);
+		case FW_PORT_CAP_SPEED_10G:
+			return (IFM_10G_KR);
+		case FW_PORT_CAP_SPEED_25G:
+			return (IFM_25G_KR);
+		case FW_PORT_CAP_SPEED_40G:
+			return (IFM_40G_KR4);
+		case FW_PORT_CAP_SPEED_100G:
+			return (IFM_100G_KR4);
+		}
+		break;
+	case FW_PORT_TYPE_FIBER_XFI:
+	case FW_PORT_TYPE_FIBER_XAUI:
+	case FW_PORT_TYPE_SFP:
+	case FW_PORT_TYPE_QSFP_10G:
+	case FW_PORT_TYPE_QSA:
+	case FW_PORT_TYPE_QSFP:
+	case FW_PORT_TYPE_CR4_QSFP:
+	case FW_PORT_TYPE_CR_QSFP:
+	case FW_PORT_TYPE_CR2_QSFP:
+	case FW_PORT_TYPE_SFP28:
+		/* Pluggable transceiver */
+		switch (pi->mod_type) {
+		case FW_PORT_MOD_TYPE_LR:
+			switch (speed) {
+			case FW_PORT_CAP_SPEED_1G:
+				return (IFM_1000_LX);
+			case FW_PORT_CAP_SPEED_10G:
+				return (IFM_10G_LR);
+			case FW_PORT_CAP_SPEED_25G:
+				return (IFM_25G_LR);
+			case FW_PORT_CAP_SPEED_40G:
+				return (IFM_40G_LR4);
+			case FW_PORT_CAP_SPEED_100G:
+				return (IFM_100G_LR4);
+			}
+			break;
+		case FW_PORT_MOD_TYPE_SR:
+			switch (speed) {
+			case FW_PORT_CAP_SPEED_1G:
+				return (IFM_1000_SX);
+			case FW_PORT_CAP_SPEED_10G:
+				return (IFM_10G_SR);
+			case FW_PORT_CAP_SPEED_25G:
+				return (IFM_25G_SR);
+			case FW_PORT_CAP_SPEED_40G:
+				return (IFM_40G_SR4);
+			case FW_PORT_CAP_SPEED_100G:
+				return (IFM_100G_SR4);
+			}
+			break;
+		case FW_PORT_MOD_TYPE_ER:
+			if (speed == FW_PORT_CAP_SPEED_10G)
+				return (IFM_10G_ER);
+			break;
+		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
+		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
+			switch (speed) {
+			case FW_PORT_CAP_SPEED_1G:
+				return (IFM_1000_CX);
+			case FW_PORT_CAP_SPEED_10G:
+				return (IFM_10G_TWINAX);
+			case FW_PORT_CAP_SPEED_25G:
+				return (IFM_25G_CR);
+			case FW_PORT_CAP_SPEED_40G:
+				return (IFM_40G_CR4);
+			case FW_PORT_CAP_SPEED_100G:
+				return (IFM_100G_CR4);
+			}
+			break;
+		case FW_PORT_MOD_TYPE_LRM:
+			if (speed == FW_PORT_CAP_SPEED_10G)
+				return (IFM_10G_LRM);
+			break;
+		case FW_PORT_MOD_TYPE_NA:
+			MPASS(0);	/* Not pluggable? */
+			/* fall throough */
+		case FW_PORT_MOD_TYPE_ERROR:
+		case FW_PORT_MOD_TYPE_UNKNOWN:
+		case FW_PORT_MOD_TYPE_NOTSUPPORTED:
+			break;
+		case FW_PORT_MOD_TYPE_NONE:
+			return (IFM_NONE);
+		}
+		break;
+	case FW_PORT_TYPE_NONE:
+		return (IFM_NONE);
+	}
+
+	return (IFM_UNKNOWN);
+}
+
 static void
 cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
 	struct vi_info *vi = ifp->if_softc;
 	struct port_info *pi = vi->pi;
-	struct ifmedia_entry *cur;
+	struct adapter *sc = pi->adapter;
 	struct link_config *lc = &pi->link_cfg;
 
-	/*
-	 * If all the interfaces are administratively down the firmware does not
-	 * report transceiver changes.  Refresh port info here so that ifconfig
-	 * displays accurate information at all times.
-	 */
-	if (begin_synchronized_op(pi->adapter, NULL, SLEEP_OK | INTR_OK,
-	    "t4med") == 0) {
-		PORT_LOCK(pi);
-		if (pi->up_vis == 0) {
-			t4_update_port_info(pi);
-			build_medialist(pi, &pi->media);
-		}
-		PORT_UNLOCK(pi);
-		end_synchronized_op(pi->adapter, 0);
+	if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4med") != 0)
+		return;
+	PORT_LOCK(pi);
+
+	if (pi->up_vis == 0) {
+		/*
+		 * If all the interfaces are administratively down the firmware
+		 * does not report transceiver changes.  Refresh port info here
+		 * so that ifconfig displays accurate ifmedia at all times.
+		 * This is the only reason we have a synchronized op in this
+		 * function.  Just PORT_LOCK would have been enough otherwise.
+		 */
+		t4_update_port_info(pi);
+		build_medialist(pi, &pi->media);
 	}
 
+	/* ifm_status */
 	ifmr->ifm_status = IFM_AVALID;
 	if (lc->link_ok == 0)
-		return;
-
+		goto done;
 	ifmr->ifm_status |= IFM_ACTIVE;
-	ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
-	if (lc->fc & PAUSE_RX)
-		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
-	if (lc->fc & PAUSE_TX)
-		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
 
-	/* active and current will differ iff current media is autoselect. */
-	cur = pi->media.ifm_cur;
-	if (cur != NULL && IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
-		return;
-
+	/* ifm_active */
 	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
+	ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
 	if (lc->fc & PAUSE_RX)
 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
 	if (lc->fc & PAUSE_TX)
 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
-	switch (lc->speed) {
-	case 10000:
-		ifmr->ifm_active |= IFM_10G_T;
-		break;
-	case 1000:
-		ifmr->ifm_active |= IFM_1000_T;
-		break;
-	case 100:
-		ifmr->ifm_active |= IFM_100_TX;
-		break;
-	case 10:
-		ifmr->ifm_active |= IFM_10_T;
-		break;
-	default:
-		device_printf(vi->dev, "link up but speed unknown (%u)\n",
-		    lc->speed);
-	}
+	ifmr->ifm_active |= port_mword(pi, speed_to_fwspeed(lc->speed));
+done:
+	PORT_UNLOCK(pi);
+	end_synchronized_op(sc, 0);
 }
 
 static int
@@ -3247,7 +3418,8 @@ partition_resources(struct adapter *sc, const struct f
 			snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF);
 		if (is_fpga(sc))
 			snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF);
-	}
+	} else if (strncmp(t4_cfg_file, BUILTIN_CF, sizeof(t4_cfg_file)) == 0)
+		goto use_built_in_config;	/* go straight to config. */
 
 	/*
 	 * We need to load another module if the profile is anything except
@@ -3358,8 +3530,31 @@ use_config_on_flash:
 	if (rc != 0) {
 		device_printf(sc->dev,
 		    "failed to pre-process config file: %d "
-		    "(mtype %d, moff 0x%x).\n", rc, mtype, moff);
-		goto done;
+		    "(mtype %d, moff 0x%x).  Will reset the firmware and retry "
+		    "with the built-in configuration.\n", rc, mtype, moff);
+
+	    	rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST);
+		if (rc != 0) {
+			device_printf(sc->dev,
+			    "firmware reset failed: %d.\n", rc);
+			if (rc != ETIMEDOUT && rc != EIO) {
+				t4_fw_bye(sc, sc->mbox);
+				sc->flags &= ~FW_OK;
+			}
+			goto done;
+		}
+		snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", "built-in");
+use_built_in_config:
+		bzero(&caps, sizeof(caps));
+		caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+		    F_FW_CMD_REQUEST | F_FW_CMD_READ);
+		caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
+		rc = t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
+		if (rc != 0) {
+			device_printf(sc->dev,
+			    "built-in configuration failed: %d.\n", rc);
+			goto done;
+		}
 	}
 
 	finicsum = be32toh(caps.finicsum);
@@ -3759,214 +3954,114 @@ t4_set_desc(struct adapter *sc)
 	device_set_desc_copy(sc->dev, buf);
 }
 
+static inline void
+ifmedia_add4(struct ifmedia *ifm, int m)
+{
+
+	ifmedia_add(ifm, m, 0, NULL);
+	ifmedia_add(ifm, m | IFM_ETH_TXPAUSE, 0, NULL);
+	ifmedia_add(ifm, m | IFM_ETH_RXPAUSE, 0, NULL);
+	ifmedia_add(ifm, m | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE, 0, NULL);
+}
+
 static void
-build_medialist(struct port_info *pi, struct ifmedia *media)
+set_current_media(struct port_info *pi, struct ifmedia *ifm)
 {
-	int m;
+	struct link_config *lc;
+	int mword;
 
 	PORT_LOCK_ASSERT_OWNED(pi);
 
-	ifmedia_removeall(media);
+	/* Leave current media alone if it's already set to IFM_NONE. */
+	if (ifm->ifm_cur != NULL &&
+	    IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_NONE)
+		return;
 
-	/*
-	 * XXX: Would it be better to ifmedia_add all 4 combinations of pause
-	 * settings for every speed instead of just txpause|rxpause?  ifconfig
-	 * media display looks much better if autoselect is the only case where
-	 * ifm_current is different from ifm_active.  If the user picks anything
-	 * except txpause|rxpause the display is ugly.
-	 */
-	m = IFM_ETHER | IFM_FDX | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
+	lc = &pi->link_cfg;
+	if (lc->requested_aneg == AUTONEG_ENABLE &&
+	    lc->supported & FW_PORT_CAP_ANEG) {
+		ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
+		return;
+	}
+	mword = IFM_ETHER | IFM_FDX;
+	if (lc->requested_fc & PAUSE_TX)
+		mword |= IFM_ETH_TXPAUSE;
+	if (lc->requested_fc & PAUSE_RX)
+		mword |= IFM_ETH_RXPAUSE;
+	mword |= port_mword(pi, speed_to_fwspeed(lc->requested_speed));
+	ifmedia_set(ifm, mword);
+}
 
-	switch(pi->port_type) {
-	case FW_PORT_TYPE_BT_XFI:
-	case FW_PORT_TYPE_BT_XAUI:
-		ifmedia_add(media, m | IFM_10G_T, 0, NULL);
-		/* fall through */
+static void
+build_medialist(struct port_info *pi, struct ifmedia *ifm)
+{
+	uint16_t ss, speed;
+	int unknown, mword, bit;
+	struct link_config *lc;
 
-	case FW_PORT_TYPE_BT_SGMII:
-		ifmedia_add(media, m | IFM_1000_T, 0, NULL);
-		ifmedia_add(media, m | IFM_100_TX, 0, NULL);
-		ifmedia_add(media, IFM_ETHER | IFM_AUTO, 0, NULL);
-		ifmedia_set(media, IFM_ETHER | IFM_AUTO);
-		break;
+	PORT_LOCK_ASSERT_OWNED(pi);
 
-	case FW_PORT_TYPE_CX4:
-		ifmedia_add(media, m | IFM_10G_CX4, 0, NULL);
-		ifmedia_set(media, m | IFM_10G_CX4);
-		break;
+	if (pi->flags & FIXED_IFMEDIA)
+		return;
 
-	case FW_PORT_TYPE_QSFP_10G:
-	case FW_PORT_TYPE_SFP:
-	case FW_PORT_TYPE_FIBER_XFI:
-	case FW_PORT_TYPE_FIBER_XAUI:
-		switch (pi->mod_type) {
+	/*
+	 * First setup all the requested_ fields so that they comply with what's
+	 * supported by the port + transceiver.  Note that this clobbers any
+	 * user preferences set via sysctl_pause_settings or sysctl_autoneg.
+	 */
+	init_l1cfg(pi);
 
-		case FW_PORT_MOD_TYPE_LR:
-			ifmedia_add(media, m | IFM_10G_LR, 0, NULL);
-			ifmedia_set(media, m | IFM_10G_LR);
-			break;
+	/*
+	 * Now (re)build the ifmedia list.
+	 */
+	ifmedia_removeall(ifm);
+	lc = &pi->link_cfg;
+	ss = G_FW_PORT_CAP_SPEED(lc->supported); /* Supported Speeds */
+	if (__predict_false(ss == 0)) {	/* not supposed to happen. */
+		MPASS(ss != 0);
+no_media:
+		MPASS(LIST_EMPTY(&ifm->ifm_list));
+		ifmedia_add(ifm, IFM_ETHER | IFM_NONE, 0, NULL);
+		ifmedia_set(ifm, IFM_ETHER | IFM_NONE);
+		return;
+	}
 
-		case FW_PORT_MOD_TYPE_SR:
-			ifmedia_add(media, m | IFM_10G_SR, 0, NULL);
-			ifmedia_set(media, m | IFM_10G_SR);
-			break;
-
-		case FW_PORT_MOD_TYPE_LRM:
-			ifmedia_add(media, m | IFM_10G_LRM, 0, NULL);
-			ifmedia_set(media, m | IFM_10G_LRM);
-			break;
-
-		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
-		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
-			ifmedia_add(media, m | IFM_10G_TWINAX, 0, NULL);
-			ifmedia_set(media, m | IFM_10G_TWINAX);
-			break;
-
-		case FW_PORT_MOD_TYPE_NONE:
-			m &= ~IFM_FDX;
-			ifmedia_add(media, m | IFM_NONE, 0, NULL);
-			ifmedia_set(media, m | IFM_NONE);
-			break;
-
-		case FW_PORT_MOD_TYPE_NA:
-		case FW_PORT_MOD_TYPE_ER:
-		default:
-			device_printf(pi->dev,
-			    "unknown port_type (%d), mod_type (%d)\n",
-			    pi->port_type, pi->mod_type);
-			ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
-			ifmedia_set(media, m | IFM_UNKNOWN);
-			break;
+	unknown = 0;
+	for (bit = 0; bit < fls(ss); bit++) {
+		speed = 1 << bit;
+		MPASS(speed & M_FW_PORT_CAP_SPEED);
+		if (ss & speed) {
+			mword = port_mword(pi, speed);
+			if (mword == IFM_NONE) {
+				goto no_media;
+			} else if (mword == IFM_UNKNOWN)
+				unknown++;
+			else
+				ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | mword);
 		}
-		break;
-
-	case FW_PORT_TYPE_CR_QSFP:
-	case FW_PORT_TYPE_SFP28:
-	case FW_PORT_TYPE_KR_SFP28:
-		switch (pi->mod_type) {
-
-		case FW_PORT_MOD_TYPE_SR:
-			ifmedia_add(media, m | IFM_25G_SR, 0, NULL);
-			ifmedia_set(media, m | IFM_25G_SR);
-			break;
-
-		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
-		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
-			ifmedia_add(media, m | IFM_25G_CR, 0, NULL);
-			ifmedia_set(media, m | IFM_25G_CR);
-			break;
-
-		case FW_PORT_MOD_TYPE_NONE:
-			m &= ~IFM_FDX;
-			ifmedia_add(media, m | IFM_NONE, 0, NULL);
-			ifmedia_set(media, m | IFM_NONE);
-			break;
-
-		default:
-			device_printf(pi->dev,
-			    "unknown port_type (%d), mod_type (%d)\n",
-			    pi->port_type, pi->mod_type);
-			ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
-			ifmedia_set(media, m | IFM_UNKNOWN);
-			break;
-		}
-		break;
-
-	case FW_PORT_TYPE_QSFP:
-		switch (pi->mod_type) {
-
-		case FW_PORT_MOD_TYPE_LR:
-			ifmedia_add(media, m | IFM_40G_LR4, 0, NULL);
-			ifmedia_set(media, m | IFM_40G_LR4);
-			break;
-
-		case FW_PORT_MOD_TYPE_SR:
-			ifmedia_add(media, m | IFM_40G_SR4, 0, NULL);
-			ifmedia_set(media, m | IFM_40G_SR4);
-			break;
-
-		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
-		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
-			ifmedia_add(media, m | IFM_40G_CR4, 0, NULL);
-			ifmedia_set(media, m | IFM_40G_CR4);
-			break;
-
-		case FW_PORT_MOD_TYPE_NONE:
-			m &= ~IFM_FDX;
-			ifmedia_add(media, m | IFM_NONE, 0, NULL);
-			ifmedia_set(media, m | IFM_NONE);
-			break;
-
-		default:
-			device_printf(pi->dev,
-			    "unknown port_type (%d), mod_type (%d)\n",
-			    pi->port_type, pi->mod_type);
-			ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
-			ifmedia_set(media, m | IFM_UNKNOWN);
-			break;
-		}
-		break;
-
-	case FW_PORT_TYPE_KR4_100G:
-	case FW_PORT_TYPE_CR4_QSFP:
-		switch (pi->mod_type) {
-
-		case FW_PORT_MOD_TYPE_LR:
-			ifmedia_add(media, m | IFM_100G_LR4, 0, NULL);
-			ifmedia_set(media, m | IFM_100G_LR4);
-			break;
-
-		case FW_PORT_MOD_TYPE_SR:
-			ifmedia_add(media, m | IFM_100G_SR4, 0, NULL);
-			ifmedia_set(media, m | IFM_100G_SR4);
-			break;
-
-		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
-		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
-			ifmedia_add(media, m | IFM_100G_CR4, 0, NULL);
-			ifmedia_set(media, m | IFM_100G_CR4);
-			break;
-
-		case FW_PORT_MOD_TYPE_NONE:
-			m &= ~IFM_FDX;
-			ifmedia_add(media, m | IFM_NONE, 0, NULL);
-			ifmedia_set(media, m | IFM_NONE);
-			break;
-
-		default:
-			device_printf(pi->dev,
-			    "unknown port_type (%d), mod_type (%d)\n",
-			    pi->port_type, pi->mod_type);
-			ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
-			ifmedia_set(media, m | IFM_UNKNOWN);
-			break;
-		}
-		break;
-
-	default:
-		device_printf(pi->dev,
-		    "unknown port_type (%d), mod_type (%d)\n", pi->port_type,
-		    pi->mod_type);
-		ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
-		ifmedia_set(media, m | IFM_UNKNOWN);
-		break;
 	}
+	if (unknown > 0) /* Add one unknown for all unknown media types. */
+		ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | IFM_UNKNOWN);
+	if (lc->supported & FW_PORT_CAP_ANEG)
+		ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL);
+
+	set_current_media(pi, ifm);
 }
 
 /*
- * Update all the requested_* fields in the link config and then send a mailbox
- * command to apply the settings.
+ * Update all the requested_* fields in the link config to something valid (and
+ * reasonable).
  */
 static void
 init_l1cfg(struct port_info *pi)
 {
-	struct adapter *sc = pi->adapter;
 	struct link_config *lc = &pi->link_cfg;
-	int rc;
 
-	ASSERT_SYNCHRONIZED_OP(sc);
+	PORT_LOCK_ASSERT_OWNED(pi);
 
-	lc->requested_speed = port_top_speed(pi);	/* in Gbps */
+	/* Gbps -> Mbps */
+	lc->requested_speed = port_top_speed(pi) * 1000;
+
 	if (t4_autoneg != 0 && lc->supported & FW_PORT_CAP_ANEG) {
 		lc->requested_aneg = AUTONEG_ENABLE;
 	} else {
@@ -3976,18 +4071,58 @@ init_l1cfg(struct port_info *pi)
 	lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX);
 
 	if (t4_fec != -1) {
-		lc->requested_fec = t4_fec & (FEC_RS | FEC_BASER_RS |
-		    FEC_RESERVED);
+		if (t4_fec & FEC_RS && lc->supported & FW_PORT_CAP_FEC_RS) {
+			lc->requested_fec = FEC_RS;
+		} else if (t4_fec & FEC_BASER_RS &&
+		    lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
+			lc->requested_fec = FEC_BASER_RS;
+		} else {
+			lc->requested_fec = 0;
+		}
 	} else {
 		/* Use the suggested value provided by the firmware in acaps */
-		if (lc->advertising & FW_PORT_CAP_FEC_RS)
+		if (lc->advertising & FW_PORT_CAP_FEC_RS &&
+		    lc->supported & FW_PORT_CAP_FEC_RS) {
 			lc->requested_fec = FEC_RS;
-		else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
+		} else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS &&
+		    lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
 			lc->requested_fec = FEC_BASER_RS;
-		else
+		} else {
 			lc->requested_fec = 0;
+		}
 	}
+}
 
+/*
+ * Apply the settings in requested_* to the hardware.  The parameters are
+ * expected to be sane.
+ */
+static int
+apply_l1cfg(struct port_info *pi)
+{
+	struct adapter *sc = pi->adapter;
+	struct link_config *lc = &pi->link_cfg;
+	int rc;
+#ifdef INVARIANTS
+	uint16_t fwspeed;
+
+	ASSERT_SYNCHRONIZED_OP(sc);
+	PORT_LOCK_ASSERT_OWNED(pi);
+
+	if (lc->requested_aneg == AUTONEG_ENABLE)
+		MPASS(lc->supported & FW_PORT_CAP_ANEG);
+	if (lc->requested_fc & PAUSE_TX)
+		MPASS(lc->supported & FW_PORT_CAP_FC_TX);
+	if (lc->requested_fc & PAUSE_RX)
+		MPASS(lc->supported & FW_PORT_CAP_FC_RX);
+	if (lc->requested_fec == FEC_RS)
+		MPASS(lc->supported & FW_PORT_CAP_FEC_RS);
+	if (lc->requested_fec == FEC_BASER_RS)
+		MPASS(lc->supported & FW_PORT_CAP_FEC_BASER_RS);
+	fwspeed = speed_to_fwspeed(lc->requested_speed);
+	MPASS(fwspeed != 0);
+	MPASS(lc->supported & fwspeed);
+#endif
 	rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
 	if (rc != 0) {
 		device_printf(pi->dev, "l1cfg failed: %d\n", rc);
@@ -3995,6 +4130,7 @@ init_l1cfg(struct port_info *pi)
 		lc->fc = lc->requested_fc;
 		lc->fec = lc->requested_fec;
 	}
+	return (rc);
 }
 
 #define FW_MAC_EXACT_CHUNK	7
@@ -4279,7 +4415,7 @@ cxgbe_init_synchronized(struct vi_info *vi)
 	if (pi->up_vis++ == 0) {
 		t4_update_port_info(pi);
 		build_medialist(pi, &pi->media);
-		init_l1cfg(pi);
+		apply_l1cfg(pi);
 	}
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 
@@ -4354,13 +4490,13 @@ cxgbe_uninit_synchronized(struct vi_info *vi)
 		PORT_UNLOCK(pi);
 		return (0);
 	}
-	PORT_UNLOCK(pi);
 
 	pi->link_cfg.link_ok = 0;
 	pi->link_cfg.speed = 0;
 	pi->link_cfg.link_down_rc = 255;
 	t4_os_link_changed(pi);
 	pi->old_link_cfg = pi->link_cfg;
+	PORT_UNLOCK(pi);
 
 	return (0);
 }
@@ -6083,14 +6219,17 @@ sysctl_pause_settings(SYSCTL_HANDLER_ARGS)
 		    "t4PAUSE");
 		if (rc)
 			return (rc);
+		PORT_LOCK(pi);
 		if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
 			lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
 			lc->requested_fc |= n;
 			rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
 			if (rc == 0) {
 				lc->fc = lc->requested_fc;
+				set_current_media(pi, &pi->media);
 			}
 		}
+		PORT_UNLOCK(pi);
 		end_synchronized_op(sc, 0);
 	}
 
@@ -6138,11 +6277,14 @@ sysctl_fec(SYSCTL_HANDLER_ARGS)
 		n = s[0] - '0';
 		if (n & ~M_FW_PORT_CAP_FEC)
 			return (EINVAL);	/* some other bit is set too */
+		if (!powerof2(n))
+			return (EINVAL);	/* one bit can be set at most */
 
 		rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
 		    "t4fec");
 		if (rc)
 			return (rc);
+		PORT_LOCK(pi);
 		if ((lc->requested_fec & M_FW_PORT_CAP_FEC) != n) {
 			lc->requested_fec = n &
 			    G_FW_PORT_CAP_FEC(lc->supported);
@@ -6151,6 +6293,7 @@ sysctl_fec(SYSCTL_HANDLER_ARGS)
 				lc->fec = lc->requested_fec;
 			}
 		}
+		PORT_UNLOCK(pi);
 		end_synchronized_op(sc, 0);
 	}
 
@@ -6172,27 +6315,35 @@ sysctl_autoneg(SYSCTL_HANDLER_ARGS)
 	rc = sysctl_handle_int(oidp, &val, 0, req);
 	if (rc != 0 || req->newptr == NULL)
 		return (rc);
-	if ((lc->supported & FW_PORT_CAP_ANEG) == 0)
-		return (ENOTSUP);
-
 	if (val == 0)
 		val = AUTONEG_DISABLE;
 	else if (val == 1)
 		val = AUTONEG_ENABLE;
 	else
 		return (EINVAL);
-	if (lc->requested_aneg == val)
-		return (0);	/* no change */
 
 	rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
 	    "t4aneg");
 	if (rc)
 		return (rc);
+	PORT_LOCK(pi);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806042034.w54KYraX050833>