Thomas Bogendoerfer 3237e1
From: Ganesh Goudar <ganeshgr@chelsio.com>
Thomas Bogendoerfer 3237e1
Date: Sun, 20 Aug 2017 14:15:51 +0530
Thomas Bogendoerfer 3237e1
Subject: cxgb4/cxgbvf: Handle 32-bit fw port capabilities
Thomas Bogendoerfer 3237e1
Patch-mainline: v4.14-rc1
Thomas Bogendoerfer 3237e1
Git-commit: c3168cabe1af2683475d0e3048220c04b7fa4f51
Thomas Bogendoerfer 3237e1
References: bsc#1046540 FATE#322930 bsc#1046542 FATE#322928
Thomas Bogendoerfer 3237e1
Thomas Bogendoerfer 3237e1
Implement new 32-bit Firmware Port Capabilities in order to
Thomas Bogendoerfer 3237e1
handle new speeds which couldn't be represented in the old 16-bit
Thomas Bogendoerfer 3237e1
Firmware Port Capabilities values.
Thomas Bogendoerfer 3237e1
Thomas Bogendoerfer 3237e1
Based on the original work of Casey Leedom <leedom@chelsio.com>
Thomas Bogendoerfer 3237e1
Thomas Bogendoerfer 3237e1
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
Thomas Bogendoerfer 3237e1
Signed-off-by: David S. Miller <davem@davemloft.net>
Thomas Bogendoerfer 3237e1
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Thomas Bogendoerfer 3237e1
---
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h          |   43 +
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c  |   98 ++-
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c     |   88 +--
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c          |  578 +++++++++++++++-----
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h       |  175 ++++++
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c |   50 +
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h  |   86 +-
Thomas Bogendoerfer 3237e1
 drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c      |  458 ++++++++++++---
Thomas Bogendoerfer 3237e1
 8 files changed, 1220 insertions(+), 356 deletions(-)
Thomas Bogendoerfer 3237e1
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
Thomas Bogendoerfer 3237e1
@@ -104,13 +104,13 @@ enum dev_state {
Thomas Bogendoerfer 3237e1
 	DEV_STATE_ERR
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-enum {
Thomas Bogendoerfer 3237e1
+enum cc_pause {
Thomas Bogendoerfer 3237e1
 	PAUSE_RX      = 1 << 0,
Thomas Bogendoerfer 3237e1
 	PAUSE_TX      = 1 << 1,
Thomas Bogendoerfer 3237e1
 	PAUSE_AUTONEG = 1 << 2
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-enum {
Thomas Bogendoerfer 3237e1
+enum cc_fec {
Thomas Bogendoerfer 3237e1
 	FEC_AUTO      = 1 << 0,	 /* IEEE 802.3 "automatic" */
Thomas Bogendoerfer 3237e1
 	FEC_RS        = 1 << 1,  /* Reed-Solomon */
Thomas Bogendoerfer 3237e1
 	FEC_BASER_RS  = 1 << 2   /* BaseR/Reed-Solomon */
Thomas Bogendoerfer 3237e1
@@ -366,6 +366,7 @@ struct adapter_params {
Thomas Bogendoerfer 3237e1
 	unsigned int max_ordird_qp;       /* Max read depth per RDMA QP */
Thomas Bogendoerfer 3237e1
 	unsigned int max_ird_adapter;     /* Max read depth per adapter */
Thomas Bogendoerfer 3237e1
 	bool fr_nsmr_tpte_wr_support;	  /* FW support for FR_NSMR_TPTE_WR */
Thomas Bogendoerfer 3237e1
+	u8 fw_caps_support;		/* 32-bit Port Capabilities */
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	/* MPS Buffer Group Map[per Port].  Bit i is set if buffer group i is
Thomas Bogendoerfer 3237e1
 	 * used by the Port
Thomas Bogendoerfer 3237e1
@@ -439,18 +440,34 @@ struct trace_params {
Thomas Bogendoerfer 3237e1
 	unsigned char port;
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+/* Firmware Port Capabilities types. */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+typedef u16 fw_port_cap16_t;	/* 16-bit Port Capabilities integral value */
Thomas Bogendoerfer 3237e1
+typedef u32 fw_port_cap32_t;	/* 32-bit Port Capabilities integral value */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+enum fw_caps {
Thomas Bogendoerfer 3237e1
+	FW_CAPS_UNKNOWN	= 0,	/* 0'ed out initial state */
Thomas Bogendoerfer 3237e1
+	FW_CAPS16	= 1,	/* old Firmware: 16-bit Port Capabilities */
Thomas Bogendoerfer 3237e1
+	FW_CAPS32	= 2,	/* new Firmware: 32-bit Port Capabilities */
Thomas Bogendoerfer 3237e1
+};
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 struct link_config {
Thomas Bogendoerfer 3237e1
-	unsigned short supported;        /* link capabilities */
Thomas Bogendoerfer 3237e1
-	unsigned short advertising;      /* advertised capabilities */
Thomas Bogendoerfer 3237e1
-	unsigned short lp_advertising;   /* peer advertised capabilities */
Thomas Bogendoerfer 3237e1
-	unsigned int   requested_speed;  /* speed user has requested */
Thomas Bogendoerfer 3237e1
-	unsigned int   speed;            /* actual link speed */
Thomas Bogendoerfer 3237e1
-	unsigned char  requested_fc;     /* flow control user has requested */
Thomas Bogendoerfer 3237e1
-	unsigned char  fc;               /* actual link flow control */
Thomas Bogendoerfer 3237e1
-	unsigned char  auto_fec;	 /* Forward Error Correction: */
Thomas Bogendoerfer 3237e1
-	unsigned char  requested_fec;	 /* "automatic" (IEEE 802.3), */
Thomas Bogendoerfer 3237e1
-	unsigned char  fec;		 /* requested, and actual in use */
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t pcaps;           /* link capabilities */
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t def_acaps;       /* default advertised capabilities */
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t acaps;           /* advertised capabilities */
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t lpacaps;         /* peer advertised capabilities */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t speed_caps;      /* speed(s) user has requested */
Thomas Bogendoerfer 3237e1
+	unsigned int   speed;            /* actual link speed (Mb/s) */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	enum cc_pause  requested_fc;     /* flow control user has requested */
Thomas Bogendoerfer 3237e1
+	enum cc_pause  fc;               /* actual link flow control */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	enum cc_fec    requested_fec;	 /* Forward Error Correction: */
Thomas Bogendoerfer 3237e1
+	enum cc_fec    fec;		 /* requested and actual in use */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	unsigned char  autoneg;          /* autonegotiating? */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	unsigned char  link_ok;          /* link up? */
Thomas Bogendoerfer 3237e1
 	unsigned char  link_down_rc;     /* link down reason */
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
@@ -1580,6 +1597,8 @@ int t4_ofld_eq_free(struct adapter *adap
Thomas Bogendoerfer 3237e1
 int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
Thomas Bogendoerfer 3237e1
 void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl);
Thomas Bogendoerfer 3237e1
 int t4_update_port_info(struct port_info *pi);
Thomas Bogendoerfer 3237e1
+int t4_get_link_params(struct port_info *pi, unsigned int *link_okp,
Thomas Bogendoerfer 3237e1
+		       unsigned int *speedp, unsigned int *mtup);
Thomas Bogendoerfer 3237e1
 int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
Thomas Bogendoerfer 3237e1
 void t4_db_full(struct adapter *adapter);
Thomas Bogendoerfer 3237e1
 void t4_db_dropped(struct adapter *adapter);
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
Thomas Bogendoerfer 3237e1
@@ -533,17 +533,23 @@ static int from_fw_port_mod_type(enum fw
Thomas Bogendoerfer 3237e1
 static unsigned int speed_to_fw_caps(int speed)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
 	if (speed == 100)
Thomas Bogendoerfer 3237e1
-		return FW_PORT_CAP_SPEED_100M;
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_100M;
Thomas Bogendoerfer 3237e1
 	if (speed == 1000)
Thomas Bogendoerfer 3237e1
-		return FW_PORT_CAP_SPEED_1G;
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_1G;
Thomas Bogendoerfer 3237e1
 	if (speed == 10000)
Thomas Bogendoerfer 3237e1
-		return FW_PORT_CAP_SPEED_10G;
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_10G;
Thomas Bogendoerfer 3237e1
 	if (speed == 25000)
Thomas Bogendoerfer 3237e1
-		return FW_PORT_CAP_SPEED_25G;
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_25G;
Thomas Bogendoerfer 3237e1
 	if (speed == 40000)
Thomas Bogendoerfer 3237e1
-		return FW_PORT_CAP_SPEED_40G;
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_40G;
Thomas Bogendoerfer 3237e1
+	if (speed == 50000)
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_50G;
Thomas Bogendoerfer 3237e1
 	if (speed == 100000)
Thomas Bogendoerfer 3237e1
-		return FW_PORT_CAP_SPEED_100G;
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_100G;
Thomas Bogendoerfer 3237e1
+	if (speed == 200000)
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_200G;
Thomas Bogendoerfer 3237e1
+	if (speed == 400000)
Thomas Bogendoerfer 3237e1
+		return FW_PORT_CAP32_SPEED_400G;
Thomas Bogendoerfer 3237e1
 	return 0;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -560,12 +566,13 @@ static void fw_caps_to_lmm(enum fw_port_
Thomas Bogendoerfer 3237e1
 			   unsigned int fw_caps,
Thomas Bogendoerfer 3237e1
 			   unsigned long *link_mode_mask)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	#define SET_LMM(__lmm_name) __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name \
Thomas Bogendoerfer 3237e1
-					## _BIT, link_mode_mask)
Thomas Bogendoerfer 3237e1
+	#define SET_LMM(__lmm_name) \
Thomas Bogendoerfer 3237e1
+		__set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \
Thomas Bogendoerfer 3237e1
+			  link_mode_mask)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	#define FW_CAPS_TO_LMM(__fw_name, __lmm_name) \
Thomas Bogendoerfer 3237e1
 		do { \
Thomas Bogendoerfer 3237e1
-			if (fw_caps & FW_PORT_CAP_ ## __fw_name) \
Thomas Bogendoerfer 3237e1
+			if (fw_caps & FW_PORT_CAP32_ ## __fw_name) \
Thomas Bogendoerfer 3237e1
 				SET_LMM(__lmm_name); \
Thomas Bogendoerfer 3237e1
 		} while (0)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -645,7 +652,10 @@ static void fw_caps_to_lmm(enum fw_port_
Thomas Bogendoerfer 3237e1
 	case FW_PORT_TYPE_KR4_100G:
Thomas Bogendoerfer 3237e1
 	case FW_PORT_TYPE_CR4_QSFP:
Thomas Bogendoerfer 3237e1
 		SET_LMM(FIBRE);
Thomas Bogendoerfer 3237e1
-		SET_LMM(100000baseCR4_Full);
Thomas Bogendoerfer 3237e1
+		FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full);
Thomas Bogendoerfer 3237e1
+		FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full);
Thomas Bogendoerfer 3237e1
+		FW_CAPS_TO_LMM(SPEED_50G, 50000baseCR2_Full);
Thomas Bogendoerfer 3237e1
+		FW_CAPS_TO_LMM(SPEED_100G, 100000baseCR4_Full);
Thomas Bogendoerfer 3237e1
 		break;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	default:
Thomas Bogendoerfer 3237e1
@@ -663,8 +673,7 @@ static void fw_caps_to_lmm(enum fw_port_
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
  *	lmm_to_fw_caps - translate ethtool Link Mode Mask to Firmware
Thomas Bogendoerfer 3237e1
  *	capabilities
Thomas Bogendoerfer 3237e1
- *
Thomas Bogendoerfer 3237e1
- *	@link_mode_mask: ethtool Link Mode Mask
Thomas Bogendoerfer 3237e1
+ *	@et_lmm: ethtool Link Mode Mask
Thomas Bogendoerfer 3237e1
  *
Thomas Bogendoerfer 3237e1
  *	Translate ethtool Link Mode Mask into a Firmware Port capabilities
Thomas Bogendoerfer 3237e1
  *	value.
Thomas Bogendoerfer 3237e1
@@ -677,7 +686,7 @@ static unsigned int lmm_to_fw_caps(const
Thomas Bogendoerfer 3237e1
 		do { \
Thomas Bogendoerfer 3237e1
 			if (test_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \
Thomas Bogendoerfer 3237e1
 				     link_mode_mask)) \
Thomas Bogendoerfer 3237e1
-				fw_caps |= FW_PORT_CAP_ ## __fw_name; \
Thomas Bogendoerfer 3237e1
+				fw_caps |= FW_PORT_CAP32_ ## __fw_name; \
Thomas Bogendoerfer 3237e1
 		} while (0)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	LMM_TO_FW_CAPS(100baseT_Full, SPEED_100M);
Thomas Bogendoerfer 3237e1
@@ -685,6 +694,7 @@ static unsigned int lmm_to_fw_caps(const
Thomas Bogendoerfer 3237e1
 	LMM_TO_FW_CAPS(10000baseT_Full, SPEED_10G);
Thomas Bogendoerfer 3237e1
 	LMM_TO_FW_CAPS(40000baseSR4_Full, SPEED_40G);
Thomas Bogendoerfer 3237e1
 	LMM_TO_FW_CAPS(25000baseCR_Full, SPEED_25G);
Thomas Bogendoerfer 3237e1
+	LMM_TO_FW_CAPS(50000baseCR2_Full, SPEED_50G);
Thomas Bogendoerfer 3237e1
 	LMM_TO_FW_CAPS(100000baseCR4_Full, SPEED_100G);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	#undef LMM_TO_FW_CAPS
Thomas Bogendoerfer 3237e1
@@ -698,10 +708,6 @@ static int get_link_ksettings(struct net
Thomas Bogendoerfer 3237e1
 	struct port_info *pi = netdev_priv(dev);
Thomas Bogendoerfer 3237e1
 	struct ethtool_link_settings *base = &link_ksettings->base;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
Thomas Bogendoerfer 3237e1
-	ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
Thomas Bogendoerfer 3237e1
-	ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising);
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
 	/* For the nonce, the Firmware doesn't send up Port State changes
Thomas Bogendoerfer 3237e1
 	 * when the Virtual Interface attached to the Port is down.  So
Thomas Bogendoerfer 3237e1
 	 * if it's down, let's grab any changes.
Thomas Bogendoerfer 3237e1
@@ -709,6 +715,10 @@ static int get_link_ksettings(struct net
Thomas Bogendoerfer 3237e1
 	if (!netif_running(dev))
Thomas Bogendoerfer 3237e1
 		(void)t4_update_port_info(pi);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+	ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
Thomas Bogendoerfer 3237e1
+	ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
Thomas Bogendoerfer 3237e1
+	ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	base->port = from_fw_port_mod_type(pi->port_type, pi->mod_type);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (pi->mdio_addr >= 0) {
Thomas Bogendoerfer 3237e1
@@ -721,11 +731,11 @@ static int get_link_ksettings(struct net
Thomas Bogendoerfer 3237e1
 		base->mdio_support = 0;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	fw_caps_to_lmm(pi->port_type, pi->link_cfg.supported,
Thomas Bogendoerfer 3237e1
+	fw_caps_to_lmm(pi->port_type, pi->link_cfg.pcaps,
Thomas Bogendoerfer 3237e1
 		       link_ksettings->link_modes.supported);
Thomas Bogendoerfer 3237e1
-	fw_caps_to_lmm(pi->port_type, pi->link_cfg.advertising,
Thomas Bogendoerfer 3237e1
+	fw_caps_to_lmm(pi->port_type, pi->link_cfg.acaps,
Thomas Bogendoerfer 3237e1
 		       link_ksettings->link_modes.advertising);
Thomas Bogendoerfer 3237e1
-	fw_caps_to_lmm(pi->port_type, pi->link_cfg.lp_advertising,
Thomas Bogendoerfer 3237e1
+	fw_caps_to_lmm(pi->port_type, pi->link_cfg.lpacaps,
Thomas Bogendoerfer 3237e1
 		       link_ksettings->link_modes.lp_advertising);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (netif_carrier_ok(dev)) {
Thomas Bogendoerfer 3237e1
@@ -736,8 +746,24 @@ static int get_link_ksettings(struct net
Thomas Bogendoerfer 3237e1
 		base->duplex = DUPLEX_UNKNOWN;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.fc & PAUSE_RX) {
Thomas Bogendoerfer 3237e1
+		if (pi->link_cfg.fc & PAUSE_TX) {
Thomas Bogendoerfer 3237e1
+			ethtool_link_ksettings_add_link_mode(link_ksettings,
Thomas Bogendoerfer 3237e1
+							     advertising,
Thomas Bogendoerfer 3237e1
+							     Pause);
Thomas Bogendoerfer 3237e1
+		} else {
Thomas Bogendoerfer 3237e1
+			ethtool_link_ksettings_add_link_mode(link_ksettings,
Thomas Bogendoerfer 3237e1
+							     advertising,
Thomas Bogendoerfer 3237e1
+							     Asym_Pause);
Thomas Bogendoerfer 3237e1
+		}
Thomas Bogendoerfer 3237e1
+	} else if (pi->link_cfg.fc & PAUSE_TX) {
Thomas Bogendoerfer 3237e1
+		ethtool_link_ksettings_add_link_mode(link_ksettings,
Thomas Bogendoerfer 3237e1
+						     advertising,
Thomas Bogendoerfer 3237e1
+						     Asym_Pause);
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	base->autoneg = pi->link_cfg.autoneg;
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_ANEG)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_ANEG)
Thomas Bogendoerfer 3237e1
 		ethtool_link_ksettings_add_link_mode(link_ksettings,
Thomas Bogendoerfer 3237e1
 						     supported, Autoneg);
Thomas Bogendoerfer 3237e1
 	if (pi->link_cfg.autoneg)
Thomas Bogendoerfer 3237e1
@@ -748,8 +774,7 @@ static int get_link_ksettings(struct net
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 static int set_link_ksettings(struct net_device *dev,
Thomas Bogendoerfer 3237e1
-			      const struct ethtool_link_ksettings
Thomas Bogendoerfer 3237e1
-						*link_ksettings)
Thomas Bogendoerfer 3237e1
+			    const struct ethtool_link_ksettings *link_ksettings)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
 	struct port_info *pi = netdev_priv(dev);
Thomas Bogendoerfer 3237e1
 	struct link_config *lc = &pi->link_cfg;
Thomas Bogendoerfer 3237e1
@@ -762,12 +787,12 @@ static int set_link_ksettings(struct net
Thomas Bogendoerfer 3237e1
 	if (base->duplex != DUPLEX_FULL)
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (!(lc->supported & FW_PORT_CAP_ANEG)) {
Thomas Bogendoerfer 3237e1
+	if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
Thomas Bogendoerfer 3237e1
 		/* PHY offers a single speed.  See if that's what's
Thomas Bogendoerfer 3237e1
 		 * being requested.
Thomas Bogendoerfer 3237e1
 		 */
Thomas Bogendoerfer 3237e1
 		if (base->autoneg == AUTONEG_DISABLE &&
Thomas Bogendoerfer 3237e1
-		    (lc->supported & speed_to_fw_caps(base->speed)))
Thomas Bogendoerfer 3237e1
+		    (lc->pcaps & speed_to_fw_caps(base->speed)))
Thomas Bogendoerfer 3237e1
 			return 0;
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
@@ -776,18 +801,17 @@ static int set_link_ksettings(struct net
Thomas Bogendoerfer 3237e1
 	if (base->autoneg == AUTONEG_DISABLE) {
Thomas Bogendoerfer 3237e1
 		fw_caps = speed_to_fw_caps(base->speed);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-		if (!(lc->supported & fw_caps))
Thomas Bogendoerfer 3237e1
+		if (!(lc->pcaps & fw_caps))
Thomas Bogendoerfer 3237e1
 			return -EINVAL;
Thomas Bogendoerfer 3237e1
-		lc->requested_speed = fw_caps;
Thomas Bogendoerfer 3237e1
-		lc->advertising = 0;
Thomas Bogendoerfer 3237e1
+		lc->speed_caps = fw_caps;
Thomas Bogendoerfer 3237e1
+		lc->acaps = 0;
Thomas Bogendoerfer 3237e1
 	} else {
Thomas Bogendoerfer 3237e1
 		fw_caps =
Thomas Bogendoerfer 3237e1
-			lmm_to_fw_caps(link_ksettings->link_modes.advertising);
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-		if (!(lc->supported & fw_caps))
Thomas Bogendoerfer 3237e1
+			 lmm_to_fw_caps(link_ksettings->link_modes.advertising);
Thomas Bogendoerfer 3237e1
+		if (!(lc->pcaps & fw_caps))
Thomas Bogendoerfer 3237e1
 			return -EINVAL;
Thomas Bogendoerfer 3237e1
-		lc->requested_speed = 0;
Thomas Bogendoerfer 3237e1
-		lc->advertising = fw_caps | FW_PORT_CAP_ANEG;
Thomas Bogendoerfer 3237e1
+		lc->speed_caps = 0;
Thomas Bogendoerfer 3237e1
+		lc->acaps = fw_caps | FW_PORT_CAP32_ANEG;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 	lc->autoneg = base->autoneg;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -806,9 +830,9 @@ static inline unsigned int fwcap_to_eth_
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
 	unsigned int eth_fec = 0;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (fw_fec & FW_PORT_CAP_FEC_RS)
Thomas Bogendoerfer 3237e1
+	if (fw_fec & FW_PORT_CAP32_FEC_RS)
Thomas Bogendoerfer 3237e1
 		eth_fec |= ETHTOOL_FEC_RS;
Thomas Bogendoerfer 3237e1
-	if (fw_fec & FW_PORT_CAP_FEC_BASER_RS)
Thomas Bogendoerfer 3237e1
+	if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
Thomas Bogendoerfer 3237e1
 		eth_fec |= ETHTOOL_FEC_BASER;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	/* if nothing is set, then FEC is off */
Thomas Bogendoerfer 3237e1
@@ -864,7 +888,7 @@ static int get_fecparam(struct net_devic
Thomas Bogendoerfer 3237e1
 	 * always support IEEE 802.3 "automatic" selection of Link FEC type if
Thomas Bogendoerfer 3237e1
 	 * any FEC is supported.
Thomas Bogendoerfer 3237e1
 	 */
Thomas Bogendoerfer 3237e1
-	fec->fec = fwcap_to_eth_fec(lc->supported);
Thomas Bogendoerfer 3237e1
+	fec->fec = fwcap_to_eth_fec(lc->pcaps);
Thomas Bogendoerfer 3237e1
 	if (fec->fec != ETHTOOL_FEC_OFF)
Thomas Bogendoerfer 3237e1
 		fec->fec |= ETHTOOL_FEC_AUTO;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -917,7 +941,7 @@ static int set_pauseparam(struct net_dev
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (epause->autoneg == AUTONEG_DISABLE)
Thomas Bogendoerfer 3237e1
 		lc->requested_fc = 0;
Thomas Bogendoerfer 3237e1
-	else if (lc->supported & FW_PORT_CAP_ANEG)
Thomas Bogendoerfer 3237e1
+	else if (lc->pcaps & FW_PORT_CAP32_ANEG)
Thomas Bogendoerfer 3237e1
 		lc->requested_fc = PAUSE_AUTONEG;
Thomas Bogendoerfer 3237e1
 	else
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
Thomas Bogendoerfer 3237e1
@@ -530,15 +530,22 @@ static int fwevtq_handler(struct sge_rsp
Thomas Bogendoerfer 3237e1
 			FW_PORT_CMD_ACTION_G(ntohl(pcmd->action_to_len16));
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 		if (cmd == FW_PORT_CMD &&
Thomas Bogendoerfer 3237e1
-		    action == FW_PORT_ACTION_GET_PORT_INFO) {
Thomas Bogendoerfer 3237e1
+		    (action == FW_PORT_ACTION_GET_PORT_INFO ||
Thomas Bogendoerfer 3237e1
+		     action == FW_PORT_ACTION_GET_PORT_INFO32)) {
Thomas Bogendoerfer 3237e1
 			int port = FW_PORT_CMD_PORTID_G(
Thomas Bogendoerfer 3237e1
 					be32_to_cpu(pcmd->op_to_portid));
Thomas Bogendoerfer 3237e1
-			struct net_device *dev =
Thomas Bogendoerfer 3237e1
-				q->adap->port[q->adap->chan_map[port]];
Thomas Bogendoerfer 3237e1
-			int state_input = ((pcmd->u.info.dcbxdis_pkd &
Thomas Bogendoerfer 3237e1
-					    FW_PORT_CMD_DCBXDIS_F)
Thomas Bogendoerfer 3237e1
-					   ? CXGB4_DCB_INPUT_FW_DISABLED
Thomas Bogendoerfer 3237e1
-					   : CXGB4_DCB_INPUT_FW_ENABLED);
Thomas Bogendoerfer 3237e1
+			struct net_device *dev;
Thomas Bogendoerfer 3237e1
+			int dcbxdis, state_input;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+			dev = q->adap->port[q->adap->chan_map[port]];
Thomas Bogendoerfer 3237e1
+			dcbxdis = (action == FW_PORT_ACTION_GET_PORT_INFO
Thomas Bogendoerfer 3237e1
+				   ? !!(pcmd->u.info.dcbxdis_pkd &
Thomas Bogendoerfer 3237e1
+					FW_PORT_CMD_DCBXDIS_F)
Thomas Bogendoerfer 3237e1
+				   : !!(pcmd->u.info32.lstatus32_to_cbllen32 &
Thomas Bogendoerfer 3237e1
+					FW_PORT_CMD_DCBXDIS32_F));
Thomas Bogendoerfer 3237e1
+			state_input = (dcbxdis
Thomas Bogendoerfer 3237e1
+				       ? CXGB4_DCB_INPUT_FW_DISABLED
Thomas Bogendoerfer 3237e1
+				       : CXGB4_DCB_INPUT_FW_ENABLED);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 			cxgb4_dcb_state_fsm(dev, state_input);
Thomas Bogendoerfer 3237e1
 		}
Thomas Bogendoerfer 3237e1
@@ -2672,11 +2679,10 @@ static int cxgb_set_vf_rate(struct net_d
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
 	struct port_info *pi = netdev_priv(dev);
Thomas Bogendoerfer 3237e1
 	struct adapter *adap = pi->adapter;
Thomas Bogendoerfer 3237e1
-	struct fw_port_cmd port_cmd, port_rpl;
Thomas Bogendoerfer 3237e1
-	u32 link_status, speed = 0;
Thomas Bogendoerfer 3237e1
+	unsigned int link_ok, speed, mtu;
Thomas Bogendoerfer 3237e1
 	u32 fw_pfvf, fw_class;
Thomas Bogendoerfer 3237e1
 	int class_id = vf;
Thomas Bogendoerfer 3237e1
-	int link_ok, ret;
Thomas Bogendoerfer 3237e1
+	int ret;
Thomas Bogendoerfer 3237e1
 	u16 pktsize;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (vf >= adap->num_vfs)
Thomas Bogendoerfer 3237e1
@@ -2688,41 +2694,18 @@ static int cxgb_set_vf_rate(struct net_d
Thomas Bogendoerfer 3237e1
 			min_tx_rate, vf);
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
-	/* Retrieve link details for VF port */
Thomas Bogendoerfer 3237e1
-	memset(&port_cmd, 0, sizeof(port_cmd));
Thomas Bogendoerfer 3237e1
-	port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
-					    FW_CMD_REQUEST_F |
Thomas Bogendoerfer 3237e1
-					    FW_CMD_READ_F |
Thomas Bogendoerfer 3237e1
-					    FW_PORT_CMD_PORTID_V(pi->port_id));
Thomas Bogendoerfer 3237e1
-	port_cmd.action_to_len16 =
Thomas Bogendoerfer 3237e1
-		cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
Thomas Bogendoerfer 3237e1
-			    FW_LEN16(port_cmd));
Thomas Bogendoerfer 3237e1
-	ret = t4_wr_mbox(adap, adap->mbox, &port_cmd, sizeof(port_cmd),
Thomas Bogendoerfer 3237e1
-			 &port_rpl);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	ret = t4_get_link_params(pi, &link_ok, &speed, &mtu);
Thomas Bogendoerfer 3237e1
 	if (ret != FW_SUCCESS) {
Thomas Bogendoerfer 3237e1
 		dev_err(adap->pdev_dev,
Thomas Bogendoerfer 3237e1
-			"Failed to get link status for VF %d\n", vf);
Thomas Bogendoerfer 3237e1
+			"Failed to get link information for VF %d\n", vf);
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
-	link_status = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
-	link_ok = (link_status & FW_PORT_CMD_LSTATUS_F) != 0;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	if (!link_ok) {
Thomas Bogendoerfer 3237e1
 		dev_err(adap->pdev_dev, "Link down for VF %d\n", vf);
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
-	/* Determine link speed */
Thomas Bogendoerfer 3237e1
-	if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
Thomas Bogendoerfer 3237e1
-		speed = 100;
Thomas Bogendoerfer 3237e1
-	else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
Thomas Bogendoerfer 3237e1
-		speed = 1000;
Thomas Bogendoerfer 3237e1
-	else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
Thomas Bogendoerfer 3237e1
-		speed = 10000;
Thomas Bogendoerfer 3237e1
-	else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
Thomas Bogendoerfer 3237e1
-		speed = 25000;
Thomas Bogendoerfer 3237e1
-	else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
Thomas Bogendoerfer 3237e1
-		speed = 40000;
Thomas Bogendoerfer 3237e1
-	else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
Thomas Bogendoerfer 3237e1
-		speed = 100000;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (max_tx_rate > speed) {
Thomas Bogendoerfer 3237e1
 		dev_err(adap->pdev_dev,
Thomas Bogendoerfer 3237e1
@@ -2730,7 +2713,8 @@ static int cxgb_set_vf_rate(struct net_d
Thomas Bogendoerfer 3237e1
 			max_tx_rate, vf, speed);
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
-	pktsize = be16_to_cpu(port_rpl.u.info.mtu);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	pktsize = mtu;
Thomas Bogendoerfer 3237e1
 	/* subtract ethhdr size and 4 bytes crc since, f/w appends it */
Thomas Bogendoerfer 3237e1
 	pktsize = pktsize - sizeof(struct ethhdr) - 4;
Thomas Bogendoerfer 3237e1
 	/* subtract ipv4 hdr size, tcp hdr size to get typical IPv4 MSS size */
Thomas Bogendoerfer 3237e1
@@ -2741,7 +2725,7 @@ static int cxgb_set_vf_rate(struct net_d
Thomas Bogendoerfer 3237e1
 			      SCHED_CLASS_MODE_CLASS,
Thomas Bogendoerfer 3237e1
 			      SCHED_CLASS_RATEUNIT_BITS,
Thomas Bogendoerfer 3237e1
 			      SCHED_CLASS_RATEMODE_ABS,
Thomas Bogendoerfer 3237e1
-			      pi->port_id, class_id, 0,
Thomas Bogendoerfer 3237e1
+			      pi->tx_chan, class_id, 0,
Thomas Bogendoerfer 3237e1
 			      max_tx_rate * 1000, 0, pktsize);
Thomas Bogendoerfer 3237e1
 	if (ret) {
Thomas Bogendoerfer 3237e1
 		dev_err(adap->pdev_dev, "Err %d for Traffic Class config\n",
Thomas Bogendoerfer 3237e1
@@ -4208,8 +4192,9 @@ static inline bool is_x_10g_port(const s
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
 	unsigned int speeds, high_speeds;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	speeds = FW_PORT_CAP_SPEED_V(FW_PORT_CAP_SPEED_G(lc->supported));
Thomas Bogendoerfer 3237e1
-	high_speeds = speeds & ~(FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G);
Thomas Bogendoerfer 3237e1
+	speeds = FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_G(lc->pcaps));
Thomas Bogendoerfer 3237e1
+	high_speeds = speeds &
Thomas Bogendoerfer 3237e1
+			~(FW_PORT_CAP32_SPEED_100M | FW_PORT_CAP32_SPEED_1G);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	return high_speeds != 0;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
@@ -4590,18 +4575,24 @@ static void print_port_info(const struct
Thomas Bogendoerfer 3237e1
 	else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_8_0GB)
Thomas Bogendoerfer 3237e1
 		spd = " 8 GT/s";
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100M)
Thomas Bogendoerfer 3237e1
 		bufp += sprintf(bufp, "100M/");
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_1G)
Thomas Bogendoerfer 3237e1
 		bufp += sprintf(bufp, "1G/");
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_10G)
Thomas Bogendoerfer 3237e1
 		bufp += sprintf(bufp, "10G/");
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_25G)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_25G)
Thomas Bogendoerfer 3237e1
 		bufp += sprintf(bufp, "25G/");
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_40G)
Thomas Bogendoerfer 3237e1
 		bufp += sprintf(bufp, "40G/");
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100G)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_50G)
Thomas Bogendoerfer 3237e1
+		bufp += sprintf(bufp, "50G/");
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100G)
Thomas Bogendoerfer 3237e1
 		bufp += sprintf(bufp, "100G/");
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_200G)
Thomas Bogendoerfer 3237e1
+		bufp += sprintf(bufp, "200G/");
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_400G)
Thomas Bogendoerfer 3237e1
+		bufp += sprintf(bufp, "400G/");
Thomas Bogendoerfer 3237e1
 	if (bufp != buf)
Thomas Bogendoerfer 3237e1
 		--bufp;
Thomas Bogendoerfer 3237e1
 	sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type));
Thomas Bogendoerfer 3237e1
@@ -4707,10 +4698,11 @@ static int config_mgmt_dev(struct pci_de
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	pi = netdev_priv(netdev);
Thomas Bogendoerfer 3237e1
 	pi->adapter = adap;
Thomas Bogendoerfer 3237e1
-	pi->port_id = adap->pf % adap->params.nports;
Thomas Bogendoerfer 3237e1
+	pi->tx_chan = adap->pf % adap->params.nports;
Thomas Bogendoerfer 3237e1
 	SET_NETDEV_DEV(netdev, &pdev->dev);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	adap->port[0] = netdev;
Thomas Bogendoerfer 3237e1
+	pi->port_id = 0;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	err = register_netdev(adap->port[0]);
Thomas Bogendoerfer 3237e1
 	if (err) {
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
Thomas Bogendoerfer 3237e1
@@ -3835,59 +3835,133 @@ void t4_ulprx_read_la(struct adapter *ad
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
Thomas Bogendoerfer 3237e1
-		     FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_25G | \
Thomas Bogendoerfer 3237e1
-		     FW_PORT_CAP_SPEED_40G | FW_PORT_CAP_SPEED_100G | \
Thomas Bogendoerfer 3237e1
-		     FW_PORT_CAP_ANEG)
Thomas Bogendoerfer 3237e1
+#define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \
Thomas Bogendoerfer 3237e1
+		     FW_PORT_CAP32_ANEG)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
+ *	fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits
Thomas Bogendoerfer 3237e1
+ *	@caps16: a 16-bit Port Capabilities value
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Returns the equivalent 32-bit Port Capabilities value.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t caps32 = 0;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#define CAP16_TO_CAP32(__cap) \
Thomas Bogendoerfer 3237e1
+		do { \
Thomas Bogendoerfer 3237e1
+			if (caps16 & FW_PORT_CAP_##__cap) \
Thomas Bogendoerfer 3237e1
+				caps32 |= FW_PORT_CAP32_##__cap; \
Thomas Bogendoerfer 3237e1
+		} while (0)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_100M);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_1G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_25G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_10G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_40G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_100G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FC_RX);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FC_TX);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(ANEG);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(MDIX);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(MDIAUTO);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FEC_RS);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FEC_BASER_RS);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(802_3_PAUSE);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(802_3_ASM_DIR);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#undef CAP16_TO_CAP32
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return caps32;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
+ *	fwcaps32_to_caps16 - convert 32-bit Port Capabilities to 16-bits
Thomas Bogendoerfer 3237e1
+ *	@caps32: a 32-bit Port Capabilities value
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Returns the equivalent 16-bit Port Capabilities value.  Note that
Thomas Bogendoerfer 3237e1
+ *	not all 32-bit Port Capabilities can be represented in the 16-bit
Thomas Bogendoerfer 3237e1
+ *	Port Capabilities and some fields/values may not make it.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static fw_port_cap16_t fwcaps32_to_caps16(fw_port_cap32_t caps32)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	fw_port_cap16_t caps16 = 0;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#define CAP32_TO_CAP16(__cap) \
Thomas Bogendoerfer 3237e1
+		do { \
Thomas Bogendoerfer 3237e1
+			if (caps32 & FW_PORT_CAP32_##__cap) \
Thomas Bogendoerfer 3237e1
+				caps16 |= FW_PORT_CAP_##__cap; \
Thomas Bogendoerfer 3237e1
+		} while (0)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(SPEED_100M);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(SPEED_1G);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(SPEED_10G);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(SPEED_25G);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(SPEED_40G);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(SPEED_100G);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(FC_RX);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(FC_TX);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(802_3_PAUSE);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(802_3_ASM_DIR);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(ANEG);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(MDIX);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(MDIAUTO);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(FEC_RS);
Thomas Bogendoerfer 3237e1
+	CAP32_TO_CAP16(FEC_BASER_RS);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#undef CAP32_TO_CAP16
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return caps16;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /* Translate Firmware Port Capabilities Pause specification to Common Code */
Thomas Bogendoerfer 3237e1
-static inline unsigned int fwcap_to_cc_pause(unsigned int fw_pause)
Thomas Bogendoerfer 3237e1
+static inline enum cc_pause fwcap_to_cc_pause(fw_port_cap32_t fw_pause)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	unsigned int cc_pause = 0;
Thomas Bogendoerfer 3237e1
+	enum cc_pause cc_pause = 0;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (fw_pause & FW_PORT_CAP_FC_RX)
Thomas Bogendoerfer 3237e1
+	if (fw_pause & FW_PORT_CAP32_FC_RX)
Thomas Bogendoerfer 3237e1
 		cc_pause |= PAUSE_RX;
Thomas Bogendoerfer 3237e1
-	if (fw_pause & FW_PORT_CAP_FC_TX)
Thomas Bogendoerfer 3237e1
+	if (fw_pause & FW_PORT_CAP32_FC_TX)
Thomas Bogendoerfer 3237e1
 		cc_pause |= PAUSE_TX;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	return cc_pause;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /* Translate Common Code Pause specification into Firmware Port Capabilities */
Thomas Bogendoerfer 3237e1
-static inline unsigned int cc_to_fwcap_pause(unsigned int cc_pause)
Thomas Bogendoerfer 3237e1
+static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	unsigned int fw_pause = 0;
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t fw_pause = 0;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (cc_pause & PAUSE_RX)
Thomas Bogendoerfer 3237e1
-		fw_pause |= FW_PORT_CAP_FC_RX;
Thomas Bogendoerfer 3237e1
+		fw_pause |= FW_PORT_CAP32_FC_RX;
Thomas Bogendoerfer 3237e1
 	if (cc_pause & PAUSE_TX)
Thomas Bogendoerfer 3237e1
-		fw_pause |= FW_PORT_CAP_FC_TX;
Thomas Bogendoerfer 3237e1
+		fw_pause |= FW_PORT_CAP32_FC_TX;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	return fw_pause;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /* Translate Firmware Forward Error Correction specification to Common Code */
Thomas Bogendoerfer 3237e1
-static inline unsigned int fwcap_to_cc_fec(unsigned int fw_fec)
Thomas Bogendoerfer 3237e1
+static inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	unsigned int cc_fec = 0;
Thomas Bogendoerfer 3237e1
+	enum cc_fec cc_fec = 0;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (fw_fec & FW_PORT_CAP_FEC_RS)
Thomas Bogendoerfer 3237e1
+	if (fw_fec & FW_PORT_CAP32_FEC_RS)
Thomas Bogendoerfer 3237e1
 		cc_fec |= FEC_RS;
Thomas Bogendoerfer 3237e1
-	if (fw_fec & FW_PORT_CAP_FEC_BASER_RS)
Thomas Bogendoerfer 3237e1
+	if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
Thomas Bogendoerfer 3237e1
 		cc_fec |= FEC_BASER_RS;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	return cc_fec;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /* Translate Common Code Forward Error Correction specification to Firmware */
Thomas Bogendoerfer 3237e1
-static inline unsigned int cc_to_fwcap_fec(unsigned int cc_fec)
Thomas Bogendoerfer 3237e1
+static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	unsigned int fw_fec = 0;
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t fw_fec = 0;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (cc_fec & FEC_RS)
Thomas Bogendoerfer 3237e1
-		fw_fec |= FW_PORT_CAP_FEC_RS;
Thomas Bogendoerfer 3237e1
+		fw_fec |= FW_PORT_CAP32_FEC_RS;
Thomas Bogendoerfer 3237e1
 	if (cc_fec & FEC_BASER_RS)
Thomas Bogendoerfer 3237e1
-		fw_fec |= FW_PORT_CAP_FEC_BASER_RS;
Thomas Bogendoerfer 3237e1
+		fw_fec |= FW_PORT_CAP32_FEC_BASER_RS;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	return fw_fec;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
@@ -3906,13 +3980,13 @@ static inline unsigned int cc_to_fwcap_f
Thomas Bogendoerfer 3237e1
  *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
Thomas Bogendoerfer 3237e1
  *	  otherwise do it later based on the outcome of auto-negotiation.
Thomas Bogendoerfer 3237e1
  */
Thomas Bogendoerfer 3237e1
-int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
Thomas Bogendoerfer 3237e1
-		  struct link_config *lc)
Thomas Bogendoerfer 3237e1
+int t4_link_l1cfg(struct adapter *adapter, unsigned int mbox,
Thomas Bogendoerfer 3237e1
+		  unsigned int port, struct link_config *lc)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	struct fw_port_cmd c;
Thomas Bogendoerfer 3237e1
-	unsigned int fw_mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO);
Thomas Bogendoerfer 3237e1
-	unsigned int fw_fc, cc_fec, fw_fec;
Thomas Bogendoerfer 3237e1
-	unsigned int rcap;
Thomas Bogendoerfer 3237e1
+	unsigned int fw_caps = adapter->params.fw_caps_support;
Thomas Bogendoerfer 3237e1
+	struct fw_port_cmd cmd;
Thomas Bogendoerfer 3237e1
+	unsigned int fw_mdi = FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO);
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t fw_fc, cc_fec, fw_fec, rcap;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	lc->link_ok = 0;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -3929,36 +4003,41 @@ int t4_link_l1cfg(struct adapter *adap,
Thomas Bogendoerfer 3237e1
 	 * use whatever is in the current Requested FEC settings.
Thomas Bogendoerfer 3237e1
 	 */
Thomas Bogendoerfer 3237e1
 	if (lc->requested_fec & FEC_AUTO)
Thomas Bogendoerfer 3237e1
-		cc_fec = lc->auto_fec;
Thomas Bogendoerfer 3237e1
+		cc_fec = fwcap_to_cc_fec(lc->def_acaps);
Thomas Bogendoerfer 3237e1
 	else
Thomas Bogendoerfer 3237e1
 		cc_fec = lc->requested_fec;
Thomas Bogendoerfer 3237e1
 	fw_fec = cc_to_fwcap_fec(cc_fec);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	/* Figure out what our Requested Port Capabilities are going to be.
Thomas Bogendoerfer 3237e1
 	 */
Thomas Bogendoerfer 3237e1
-	if (!(lc->supported & FW_PORT_CAP_ANEG)) {
Thomas Bogendoerfer 3237e1
-		rcap = (lc->supported & ADVERT_MASK) | fw_fc | fw_fec;
Thomas Bogendoerfer 3237e1
-		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
Thomas Bogendoerfer 3237e1
+	if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
Thomas Bogendoerfer 3237e1
+		rcap = (lc->pcaps & ADVERT_MASK) | fw_fc | fw_fec;
Thomas Bogendoerfer 3237e1
+		lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
Thomas Bogendoerfer 3237e1
 		lc->fec = cc_fec;
Thomas Bogendoerfer 3237e1
 	} else if (lc->autoneg == AUTONEG_DISABLE) {
Thomas Bogendoerfer 3237e1
-		rcap = lc->requested_speed | fw_fc | fw_fec | fw_mdi;
Thomas Bogendoerfer 3237e1
-		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
Thomas Bogendoerfer 3237e1
+		rcap = lc->speed_caps | fw_fc | fw_fec | fw_mdi;
Thomas Bogendoerfer 3237e1
+		lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
Thomas Bogendoerfer 3237e1
 		lc->fec = cc_fec;
Thomas Bogendoerfer 3237e1
 	} else {
Thomas Bogendoerfer 3237e1
-		rcap = lc->advertising | fw_fc | fw_fec | fw_mdi;
Thomas Bogendoerfer 3237e1
+		rcap = lc->acaps | fw_fc | fw_fec | fw_mdi;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	/* And send that on to the Firmware ...
Thomas Bogendoerfer 3237e1
 	 */
Thomas Bogendoerfer 3237e1
-	memset(&c, 0, sizeof(c));
Thomas Bogendoerfer 3237e1
-	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
-				     FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
Thomas Bogendoerfer 3237e1
-				     FW_PORT_CMD_PORTID_V(port));
Thomas Bogendoerfer 3237e1
-	c.action_to_len16 =
Thomas Bogendoerfer 3237e1
-		cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
Thomas Bogendoerfer 3237e1
-			    FW_LEN16(c));
Thomas Bogendoerfer 3237e1
-	c.u.l1cfg.rcap = cpu_to_be32(rcap);
Thomas Bogendoerfer 3237e1
-	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
Thomas Bogendoerfer 3237e1
+	memset(&cmd, 0, sizeof(cmd));
Thomas Bogendoerfer 3237e1
+	cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
+				       FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
Thomas Bogendoerfer 3237e1
+				       FW_PORT_CMD_PORTID_V(port));
Thomas Bogendoerfer 3237e1
+	cmd.action_to_len16 =
Thomas Bogendoerfer 3237e1
+		cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
Thomas Bogendoerfer 3237e1
+						 ? FW_PORT_ACTION_L1_CFG
Thomas Bogendoerfer 3237e1
+						 : FW_PORT_ACTION_L1_CFG32) |
Thomas Bogendoerfer 3237e1
+			    FW_LEN16(cmd));
Thomas Bogendoerfer 3237e1
+	if (fw_caps == FW_CAPS16)
Thomas Bogendoerfer 3237e1
+		cmd.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap));
Thomas Bogendoerfer 3237e1
+	else
Thomas Bogendoerfer 3237e1
+		cmd.u.l1cfg32.rcap32 = cpu_to_be32(rcap);
Thomas Bogendoerfer 3237e1
+	return t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL);
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
@@ -3980,7 +4059,7 @@ int t4_restart_aneg(struct adapter *adap
Thomas Bogendoerfer 3237e1
 	c.action_to_len16 =
Thomas Bogendoerfer 3237e1
 		cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
Thomas Bogendoerfer 3237e1
 			    FW_LEN16(c));
Thomas Bogendoerfer 3237e1
-	c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP_ANEG);
Thomas Bogendoerfer 3237e1
+	c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP32_ANEG);
Thomas Bogendoerfer 3237e1
 	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -7697,6 +7776,98 @@ static const char *t4_link_down_rc_str(u
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
+ * Return the highest speed set in the port capabilities, in Mb/s.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static unsigned int fwcap_to_speed(fw_port_cap32_t caps)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	#define TEST_SPEED_RETURN(__caps_speed, __speed) \
Thomas Bogendoerfer 3237e1
+		do { \
Thomas Bogendoerfer 3237e1
+			if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \
Thomas Bogendoerfer 3237e1
+				return __speed; \
Thomas Bogendoerfer 3237e1
+		} while (0)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(400G, 400000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(200G, 200000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(100G, 100000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(50G,   50000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(40G,   40000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(25G,   25000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(10G,   10000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(1G,     1000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(100M,    100);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#undef TEST_SPEED_RETURN
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return 0;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
+ *	fwcap_to_fwspeed - return highest speed in Port Capabilities
Thomas Bogendoerfer 3237e1
+ *	@acaps: advertised Port Capabilities
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Get the highest speed for the port from the advertised Port
Thomas Bogendoerfer 3237e1
+ *	Capabilities.  It will be either the highest speed from the list of
Thomas Bogendoerfer 3237e1
+ *	speeds or whatever user has set using ethtool.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	#define TEST_SPEED_RETURN(__caps_speed) \
Thomas Bogendoerfer 3237e1
+		do { \
Thomas Bogendoerfer 3237e1
+			if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \
Thomas Bogendoerfer 3237e1
+				return FW_PORT_CAP32_SPEED_##__caps_speed; \
Thomas Bogendoerfer 3237e1
+		} while (0)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(400G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(200G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(100G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(50G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(40G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(25G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(10G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(1G);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(100M);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#undef TEST_SPEED_RETURN
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return 0;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
+ *	lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities
Thomas Bogendoerfer 3237e1
+ *	@lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new
Thomas Bogendoerfer 3237e1
+ *	32-bit Port Capabilities value.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static fw_port_cap32_t lstatus_to_fwcap(u32 lstatus)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t linkattr = 0;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	/* Unfortunately the format of the Link Status in the old
Thomas Bogendoerfer 3237e1
+	 * 16-bit Port Information message isn't the same as the
Thomas Bogendoerfer 3237e1
+	 * 16-bit Port Capabilities bitfield used everywhere else ...
Thomas Bogendoerfer 3237e1
+	 */
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_RXPAUSE_F)
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_FC_RX;
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_TXPAUSE_F)
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_FC_TX;
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_SPEED_100M;
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_SPEED_1G;
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_SPEED_10G;
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_SPEED_25G;
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_SPEED_40G;
Thomas Bogendoerfer 3237e1
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
Thomas Bogendoerfer 3237e1
+		linkattr |= FW_PORT_CAP32_SPEED_100G;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return linkattr;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
  *	t4_handle_get_port_info - process a FW reply message
Thomas Bogendoerfer 3237e1
  *	@pi: the port info
Thomas Bogendoerfer 3237e1
  *	@rpl: start of the FW message
Thomas Bogendoerfer 3237e1
@@ -7705,76 +7876,123 @@ static const char *t4_link_down_rc_str(u
Thomas Bogendoerfer 3237e1
  */
Thomas Bogendoerfer 3237e1
 void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	const struct fw_port_cmd *p = (const void *)rpl;
Thomas Bogendoerfer 3237e1
-	unsigned int acaps = be16_to_cpu(p->u.info.acap);
Thomas Bogendoerfer 3237e1
-	struct adapter *adap = pi->adapter;
Thomas Bogendoerfer 3237e1
+	const struct fw_port_cmd *cmd = (const void *)rpl;
Thomas Bogendoerfer 3237e1
+	int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
Thomas Bogendoerfer 3237e1
+	struct adapter *adapter = pi->adapter;
Thomas Bogendoerfer 3237e1
+	struct link_config *lc = &pi->link_cfg;
Thomas Bogendoerfer 3237e1
+	int link_ok, linkdnrc;
Thomas Bogendoerfer 3237e1
+	enum fw_port_type port_type;
Thomas Bogendoerfer 3237e1
+	enum fw_port_module_type mod_type;
Thomas Bogendoerfer 3237e1
+	unsigned int speed, fc, fec;
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	/* Extract the various fields from the Port Information message.
Thomas Bogendoerfer 3237e1
+	 */
Thomas Bogendoerfer 3237e1
+	switch (action) {
Thomas Bogendoerfer 3237e1
+	case FW_PORT_ACTION_GET_PORT_INFO: {
Thomas Bogendoerfer 3237e1
+		u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		link_ok = (lstatus & FW_PORT_CMD_LSTATUS_F) != 0;
Thomas Bogendoerfer 3237e1
+		linkdnrc = FW_PORT_CMD_LINKDNRC_G(lstatus);
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PTYPE_G(lstatus);
Thomas Bogendoerfer 3237e1
+		mod_type = FW_PORT_CMD_MODTYPE_G(lstatus);
Thomas Bogendoerfer 3237e1
+		pcaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.pcap));
Thomas Bogendoerfer 3237e1
+		acaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.acap));
Thomas Bogendoerfer 3237e1
+		lpacaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.lpacap));
Thomas Bogendoerfer 3237e1
+		linkattr = lstatus_to_fwcap(lstatus);
Thomas Bogendoerfer 3237e1
+		break;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	/* link/module state change message */
Thomas Bogendoerfer 3237e1
-	int speed = 0, fc, fec;
Thomas Bogendoerfer 3237e1
-	struct link_config *lc;
Thomas Bogendoerfer 3237e1
-	u32 stat = be32_to_cpu(p->u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
-	int link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;
Thomas Bogendoerfer 3237e1
-	u32 mod = FW_PORT_CMD_MODTYPE_G(stat);
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-	/* Unfortunately the format of the Link Status returned by the
Thomas Bogendoerfer 3237e1
-	 * Firmware isn't the same as the Firmware Port Capabilities bitfield
Thomas Bogendoerfer 3237e1
-	 * used everywhere else ...
Thomas Bogendoerfer 3237e1
-	 */
Thomas Bogendoerfer 3237e1
-	fc = 0;
Thomas Bogendoerfer 3237e1
-	if (stat & FW_PORT_CMD_RXPAUSE_F)
Thomas Bogendoerfer 3237e1
-		fc |= PAUSE_RX;
Thomas Bogendoerfer 3237e1
-	if (stat & FW_PORT_CMD_TXPAUSE_F)
Thomas Bogendoerfer 3237e1
-		fc |= PAUSE_TX;
Thomas Bogendoerfer 3237e1
+	case FW_PORT_ACTION_GET_PORT_INFO32: {
Thomas Bogendoerfer 3237e1
+		u32 lstatus32;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	fec = fwcap_to_cc_fec(acaps);
Thomas Bogendoerfer 3237e1
+		lstatus32 = be32_to_cpu(cmd->u.info32.lstatus32_to_cbllen32);
Thomas Bogendoerfer 3237e1
+		link_ok = (lstatus32 & FW_PORT_CMD_LSTATUS32_F) != 0;
Thomas Bogendoerfer 3237e1
+		linkdnrc = FW_PORT_CMD_LINKDNRC32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		mod_type = FW_PORT_CMD_MODTYPE32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		pcaps = be32_to_cpu(cmd->u.info32.pcaps32);
Thomas Bogendoerfer 3237e1
+		acaps = be32_to_cpu(cmd->u.info32.acaps32);
Thomas Bogendoerfer 3237e1
+		lpacaps = be32_to_cpu(cmd->u.info32.lpacaps32);
Thomas Bogendoerfer 3237e1
+		linkattr = be32_to_cpu(cmd->u.info32.linkattr32);
Thomas Bogendoerfer 3237e1
+		break;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
Thomas Bogendoerfer 3237e1
-		speed = 100;
Thomas Bogendoerfer 3237e1
-	else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
Thomas Bogendoerfer 3237e1
-		speed = 1000;
Thomas Bogendoerfer 3237e1
-	else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
Thomas Bogendoerfer 3237e1
-		speed = 10000;
Thomas Bogendoerfer 3237e1
-	else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
Thomas Bogendoerfer 3237e1
-		speed = 25000;
Thomas Bogendoerfer 3237e1
-	else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
Thomas Bogendoerfer 3237e1
-		speed = 40000;
Thomas Bogendoerfer 3237e1
-	else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
Thomas Bogendoerfer 3237e1
-		speed = 100000;
Thomas Bogendoerfer 3237e1
+	default:
Thomas Bogendoerfer 3237e1
+		dev_err(adapter->pdev_dev, "Handle Port Information: Bad Command/Action %#x\n",
Thomas Bogendoerfer 3237e1
+			be32_to_cpu(cmd->action_to_len16));
Thomas Bogendoerfer 3237e1
+		return;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	lc = &pi->link_cfg;
Thomas Bogendoerfer 3237e1
+	fec = fwcap_to_cc_fec(acaps);
Thomas Bogendoerfer 3237e1
+	fc = fwcap_to_cc_pause(linkattr);
Thomas Bogendoerfer 3237e1
+	speed = fwcap_to_speed(linkattr);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (mod_type != pi->mod_type) {
Thomas Bogendoerfer 3237e1
+		/* With the newer SFP28 and QSFP28 Transceiver Module Types,
Thomas Bogendoerfer 3237e1
+		 * various fundamental Port Capabilities which used to be
Thomas Bogendoerfer 3237e1
+		 * immutable can now change radically.  We can now have
Thomas Bogendoerfer 3237e1
+		 * Speeds, Auto-Negotiation, Forward Error Correction, etc.
Thomas Bogendoerfer 3237e1
+		 * all change based on what Transceiver Module is inserted.
Thomas Bogendoerfer 3237e1
+		 * So we need to record the Physical "Port" Capabilities on
Thomas Bogendoerfer 3237e1
+		 * every Transceiver Module change.
Thomas Bogendoerfer 3237e1
+		 */
Thomas Bogendoerfer 3237e1
+		lc->pcaps = pcaps;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (mod != pi->mod_type) {
Thomas Bogendoerfer 3237e1
 		/* When a new Transceiver Module is inserted, the Firmware
Thomas Bogendoerfer 3237e1
-		 * will examine any Forward Error Correction parameters
Thomas Bogendoerfer 3237e1
-		 * present in the Transceiver Module i2c EPROM and determine
Thomas Bogendoerfer 3237e1
-		 * the supported and recommended FEC settings from those
Thomas Bogendoerfer 3237e1
-		 * based on IEEE 802.3 standards.  We always record the
Thomas Bogendoerfer 3237e1
-		 * IEEE 802.3 recommended "automatic" settings.
Thomas Bogendoerfer 3237e1
+		 * will examine its i2c EPROM to determine its type and
Thomas Bogendoerfer 3237e1
+		 * general operating parameters including things like Forward
Thomas Bogendoerfer 3237e1
+		 * Error Control, etc.  Various IEEE 802.3 standards dictate
Thomas Bogendoerfer 3237e1
+		 * how to interpret these i2c values to determine default
Thomas Bogendoerfer 3237e1
+		 * "sutomatic" settings.  We record these for future use when
Thomas Bogendoerfer 3237e1
+		 * the user explicitly requests these standards-based values.
Thomas Bogendoerfer 3237e1
+		 */
Thomas Bogendoerfer 3237e1
+		lc->def_acaps = acaps;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		/* Some versions of the early T6 Firmware "cheated" when
Thomas Bogendoerfer 3237e1
+		 * handling different Transceiver Modules by changing the
Thomas Bogendoerfer 3237e1
+		 * underlaying Port Type reported to the Host Drivers.  As
Thomas Bogendoerfer 3237e1
+		 * such we need to capture whatever Port Type the Firmware
Thomas Bogendoerfer 3237e1
+		 * sends us and record it in case it's different from what we
Thomas Bogendoerfer 3237e1
+		 * were told earlier.  Unfortunately, since Firmware is
Thomas Bogendoerfer 3237e1
+		 * forever, we'll need to keep this code here forever, but in
Thomas Bogendoerfer 3237e1
+		 * later T6 Firmware it should just be an assignment of the
Thomas Bogendoerfer 3237e1
+		 * same value already recorded.
Thomas Bogendoerfer 3237e1
 		 */
Thomas Bogendoerfer 3237e1
-		lc->auto_fec = fec;
Thomas Bogendoerfer 3237e1
+		pi->port_type = port_type;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-		pi->mod_type = mod;
Thomas Bogendoerfer 3237e1
-		t4_os_portmod_changed(adap, pi->port_id);
Thomas Bogendoerfer 3237e1
+		pi->mod_type = mod_type;
Thomas Bogendoerfer 3237e1
+		t4_os_portmod_changed(adapter, pi->port_id);
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	if (link_ok != lc->link_ok || speed != lc->speed ||
Thomas Bogendoerfer 3237e1
 	    fc != lc->fc || fec != lc->fec) {	/* something changed */
Thomas Bogendoerfer 3237e1
 		if (!link_ok && lc->link_ok) {
Thomas Bogendoerfer 3237e1
-			unsigned char rc = FW_PORT_CMD_LINKDNRC_G(stat);
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-			lc->link_down_rc = rc;
Thomas Bogendoerfer 3237e1
-			dev_warn(adap->pdev_dev,
Thomas Bogendoerfer 3237e1
-				 "Port %d link down, reason: %s\n",
Thomas Bogendoerfer 3237e1
-				 pi->port_id, t4_link_down_rc_str(rc));
Thomas Bogendoerfer 3237e1
+			lc->link_down_rc = linkdnrc;
Thomas Bogendoerfer 3237e1
+			dev_warn(adapter->pdev_dev, "Port %d link down, reason: %s\n",
Thomas Bogendoerfer 3237e1
+				 pi->tx_chan, t4_link_down_rc_str(linkdnrc));
Thomas Bogendoerfer 3237e1
 		}
Thomas Bogendoerfer 3237e1
 		lc->link_ok = link_ok;
Thomas Bogendoerfer 3237e1
 		lc->speed = speed;
Thomas Bogendoerfer 3237e1
 		lc->fc = fc;
Thomas Bogendoerfer 3237e1
 		lc->fec = fec;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-		lc->supported = be16_to_cpu(p->u.info.pcap);
Thomas Bogendoerfer 3237e1
-		lc->lp_advertising = be16_to_cpu(p->u.info.lpacap);
Thomas Bogendoerfer 3237e1
+		lc->lpacaps = lpacaps;
Thomas Bogendoerfer 3237e1
+		lc->acaps = acaps & ADVERT_MASK;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-		t4_os_link_changed(adap, pi->port_id, link_ok);
Thomas Bogendoerfer 3237e1
+		if (lc->acaps & FW_PORT_CAP32_ANEG) {
Thomas Bogendoerfer 3237e1
+			lc->autoneg = AUTONEG_ENABLE;
Thomas Bogendoerfer 3237e1
+		} else {
Thomas Bogendoerfer 3237e1
+			/* When Autoneg is disabled, user needs to set
Thomas Bogendoerfer 3237e1
+			 * single speed.
Thomas Bogendoerfer 3237e1
+			 * Similar to cxgb4_ethtool.c: set_link_ksettings
Thomas Bogendoerfer 3237e1
+			 */
Thomas Bogendoerfer 3237e1
+			lc->acaps = 0;
Thomas Bogendoerfer 3237e1
+			lc->speed_caps = fwcap_to_fwspeed(acaps);
Thomas Bogendoerfer 3237e1
+			lc->autoneg = AUTONEG_DISABLE;
Thomas Bogendoerfer 3237e1
+		}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		t4_os_link_changed(adapter, pi->port_id, link_ok);
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -7788,15 +8006,18 @@ void t4_handle_get_port_info(struct port
Thomas Bogendoerfer 3237e1
  */
Thomas Bogendoerfer 3237e1
 int t4_update_port_info(struct port_info *pi)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
+	unsigned int fw_caps = pi->adapter->params.fw_caps_support;
Thomas Bogendoerfer 3237e1
 	struct fw_port_cmd port_cmd;
Thomas Bogendoerfer 3237e1
 	int ret;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	memset(&port_cmd, 0, sizeof(port_cmd));
Thomas Bogendoerfer 3237e1
 	port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
 					    FW_CMD_REQUEST_F | FW_CMD_READ_F |
Thomas Bogendoerfer 3237e1
-					    FW_PORT_CMD_PORTID_V(pi->port_id));
Thomas Bogendoerfer 3237e1
+					    FW_PORT_CMD_PORTID_V(pi->tx_chan));
Thomas Bogendoerfer 3237e1
 	port_cmd.action_to_len16 = cpu_to_be32(
Thomas Bogendoerfer 3237e1
-		FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
Thomas Bogendoerfer 3237e1
+		FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
Thomas Bogendoerfer 3237e1
+				     ? FW_PORT_ACTION_GET_PORT_INFO
Thomas Bogendoerfer 3237e1
+				     : FW_PORT_ACTION_GET_PORT_INFO32) |
Thomas Bogendoerfer 3237e1
 		FW_LEN16(port_cmd));
Thomas Bogendoerfer 3237e1
 	ret = t4_wr_mbox(pi->adapter, pi->adapter->mbox,
Thomas Bogendoerfer 3237e1
 			 &port_cmd, sizeof(port_cmd), &port_cmd);
Thomas Bogendoerfer 3237e1
@@ -7808,6 +8029,65 @@ int t4_update_port_info(struct port_info
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
+ *	t4_get_link_params - retrieve basic link parameters for given port
Thomas Bogendoerfer 3237e1
+ *	@pi: the port
Thomas Bogendoerfer 3237e1
+ *	@link_okp: value return pointer for link up/down
Thomas Bogendoerfer 3237e1
+ *	@speedp: value return pointer for speed (Mb/s)
Thomas Bogendoerfer 3237e1
+ *	@mtup: value return pointer for mtu
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Retrieves basic link parameters for a port: link up/down, speed (Mb/s),
Thomas Bogendoerfer 3237e1
+ *	and MTU for a specified port.  A negative error is returned on
Thomas Bogendoerfer 3237e1
+ *	failure; 0 on success.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+int t4_get_link_params(struct port_info *pi, unsigned int *link_okp,
Thomas Bogendoerfer 3237e1
+		       unsigned int *speedp, unsigned int *mtup)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	unsigned int fw_caps = pi->adapter->params.fw_caps_support;
Thomas Bogendoerfer 3237e1
+	struct fw_port_cmd port_cmd;
Thomas Bogendoerfer 3237e1
+	unsigned int action, link_ok, speed, mtu;
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t linkattr;
Thomas Bogendoerfer 3237e1
+	int ret;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	memset(&port_cmd, 0, sizeof(port_cmd));
Thomas Bogendoerfer 3237e1
+	port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
+					    FW_CMD_REQUEST_F | FW_CMD_READ_F |
Thomas Bogendoerfer 3237e1
+					    FW_PORT_CMD_PORTID_V(pi->tx_chan));
Thomas Bogendoerfer 3237e1
+	action = (fw_caps == FW_CAPS16
Thomas Bogendoerfer 3237e1
+		  ? FW_PORT_ACTION_GET_PORT_INFO
Thomas Bogendoerfer 3237e1
+		  : FW_PORT_ACTION_GET_PORT_INFO32);
Thomas Bogendoerfer 3237e1
+	port_cmd.action_to_len16 = cpu_to_be32(
Thomas Bogendoerfer 3237e1
+		FW_PORT_CMD_ACTION_V(action) |
Thomas Bogendoerfer 3237e1
+		FW_LEN16(port_cmd));
Thomas Bogendoerfer 3237e1
+	ret = t4_wr_mbox(pi->adapter, pi->adapter->mbox,
Thomas Bogendoerfer 3237e1
+			 &port_cmd, sizeof(port_cmd), &port_cmd);
Thomas Bogendoerfer 3237e1
+	if (ret)
Thomas Bogendoerfer 3237e1
+		return ret;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (action == FW_PORT_ACTION_GET_PORT_INFO) {
Thomas Bogendoerfer 3237e1
+		u32 lstatus = be32_to_cpu(port_cmd.u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		link_ok = !!(lstatus & FW_PORT_CMD_LSTATUS_F);
Thomas Bogendoerfer 3237e1
+		linkattr = lstatus_to_fwcap(lstatus);
Thomas Bogendoerfer 3237e1
+		mtu = be16_to_cpu(port_cmd.u.info.mtu);
Thomas Bogendoerfer 3237e1
+	} else {
Thomas Bogendoerfer 3237e1
+		u32 lstatus32 =
Thomas Bogendoerfer 3237e1
+			   be32_to_cpu(port_cmd.u.info32.lstatus32_to_cbllen32);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		link_ok = !!(lstatus32 & FW_PORT_CMD_LSTATUS32_F);
Thomas Bogendoerfer 3237e1
+		linkattr = be32_to_cpu(port_cmd.u.info32.linkattr32);
Thomas Bogendoerfer 3237e1
+		mtu = FW_PORT_CMD_MTU32_G(
Thomas Bogendoerfer 3237e1
+			be32_to_cpu(port_cmd.u.info32.auxlinfo32_mtu32));
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+	speed = fwcap_to_speed(linkattr);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	*link_okp = link_ok;
Thomas Bogendoerfer 3237e1
+	*speedp = fwcap_to_speed(linkattr);
Thomas Bogendoerfer 3237e1
+	*mtup = mtu;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return 0;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
  *      t4_handle_fw_rpl - process a FW reply message
Thomas Bogendoerfer 3237e1
  *      @adap: the adapter
Thomas Bogendoerfer 3237e1
  *      @rpl: start of the FW message
Thomas Bogendoerfer 3237e1
@@ -7827,7 +8107,9 @@ int t4_handle_fw_rpl(struct adapter *ada
Thomas Bogendoerfer 3237e1
 	unsigned int action =
Thomas Bogendoerfer 3237e1
 		FW_PORT_CMD_ACTION_G(be32_to_cpu(p->action_to_len16));
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) {
Thomas Bogendoerfer 3237e1
+	if (opcode == FW_PORT_CMD &&
Thomas Bogendoerfer 3237e1
+	    (action == FW_PORT_ACTION_GET_PORT_INFO ||
Thomas Bogendoerfer 3237e1
+	     action == FW_PORT_ACTION_GET_PORT_INFO32)) {
Thomas Bogendoerfer 3237e1
 		int i;
Thomas Bogendoerfer 3237e1
 		int chan = FW_PORT_CMD_PORTID_G(be32_to_cpu(p->op_to_portid));
Thomas Bogendoerfer 3237e1
 		struct port_info *pi = NULL;
Thomas Bogendoerfer 3237e1
@@ -7840,7 +8122,8 @@ int t4_handle_fw_rpl(struct adapter *ada
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 		t4_handle_get_port_info(pi, rpl);
Thomas Bogendoerfer 3237e1
 	} else {
Thomas Bogendoerfer 3237e1
-		dev_warn(adap->pdev_dev, "Unknown firmware reply %d\n", opcode);
Thomas Bogendoerfer 3237e1
+		dev_warn(adap->pdev_dev, "Unknown firmware reply %d\n",
Thomas Bogendoerfer 3237e1
+			 opcode);
Thomas Bogendoerfer 3237e1
 		return -EINVAL;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 	return 0;
Thomas Bogendoerfer 3237e1
@@ -7859,35 +8142,35 @@ static void get_pci_mode(struct adapter
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
  *	init_link_config - initialize a link's SW state
Thomas Bogendoerfer 3237e1
- *	@lc: structure holding the link state
Thomas Bogendoerfer 3237e1
+ *	@lc: pointer to structure holding the link state
Thomas Bogendoerfer 3237e1
  *	@pcaps: link Port Capabilities
Thomas Bogendoerfer 3237e1
  *	@acaps: link current Advertised Port Capabilities
Thomas Bogendoerfer 3237e1
  *
Thomas Bogendoerfer 3237e1
  *	Initializes the SW state maintained for each link, including the link's
Thomas Bogendoerfer 3237e1
  *	capabilities and default speed/flow-control/autonegotiation settings.
Thomas Bogendoerfer 3237e1
  */
Thomas Bogendoerfer 3237e1
-static void init_link_config(struct link_config *lc, unsigned int pcaps,
Thomas Bogendoerfer 3237e1
-			     unsigned int acaps)
Thomas Bogendoerfer 3237e1
+static void init_link_config(struct link_config *lc, fw_port_cap32_t pcaps,
Thomas Bogendoerfer 3237e1
+			     fw_port_cap32_t acaps)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	lc->supported = pcaps;
Thomas Bogendoerfer 3237e1
-	lc->lp_advertising = 0;
Thomas Bogendoerfer 3237e1
-	lc->requested_speed = 0;
Thomas Bogendoerfer 3237e1
+	lc->pcaps = pcaps;
Thomas Bogendoerfer 3237e1
+	lc->def_acaps = acaps;
Thomas Bogendoerfer 3237e1
+	lc->lpacaps = 0;
Thomas Bogendoerfer 3237e1
+	lc->speed_caps = 0;
Thomas Bogendoerfer 3237e1
 	lc->speed = 0;
Thomas Bogendoerfer 3237e1
 	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	/* For Forward Error Control, we default to whatever the Firmware
Thomas Bogendoerfer 3237e1
 	 * tells us the Link is currently advertising.
Thomas Bogendoerfer 3237e1
 	 */
Thomas Bogendoerfer 3237e1
-	lc->auto_fec = fwcap_to_cc_fec(acaps);
Thomas Bogendoerfer 3237e1
 	lc->requested_fec = FEC_AUTO;
Thomas Bogendoerfer 3237e1
-	lc->fec = lc->auto_fec;
Thomas Bogendoerfer 3237e1
+	lc->fec = fwcap_to_cc_fec(lc->def_acaps);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	if (lc->supported & FW_PORT_CAP_ANEG) {
Thomas Bogendoerfer 3237e1
-		lc->advertising = lc->supported & ADVERT_MASK;
Thomas Bogendoerfer 3237e1
+	if (lc->pcaps & FW_PORT_CAP32_ANEG) {
Thomas Bogendoerfer 3237e1
+		lc->acaps = lc->pcaps & ADVERT_MASK;
Thomas Bogendoerfer 3237e1
 		lc->autoneg = AUTONEG_ENABLE;
Thomas Bogendoerfer 3237e1
 		lc->requested_fc |= PAUSE_AUTONEG;
Thomas Bogendoerfer 3237e1
 	} else {
Thomas Bogendoerfer 3237e1
-		lc->advertising = 0;
Thomas Bogendoerfer 3237e1
+		lc->acaps = 0;
Thomas Bogendoerfer 3237e1
 		lc->autoneg = AUTONEG_DISABLE;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
@@ -8412,7 +8695,7 @@ int t4_init_rss_mode(struct adapter *ada
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
- *	t4_init_portinfo - allocate a virtual interface amd initialize port_info
Thomas Bogendoerfer 3237e1
+ *	t4_init_portinfo - allocate a virtual interface and initialize port_info
Thomas Bogendoerfer 3237e1
  *	@pi: the port_info
Thomas Bogendoerfer 3237e1
  *	@mbox: mailbox to use for the FW command
Thomas Bogendoerfer 3237e1
  *	@port: physical port associated with the VI
Thomas Bogendoerfer 3237e1
@@ -8428,21 +8711,67 @@ int t4_init_rss_mode(struct adapter *ada
Thomas Bogendoerfer 3237e1
 int t4_init_portinfo(struct port_info *pi, int mbox,
Thomas Bogendoerfer 3237e1
 		     int port, int pf, int vf, u8 mac[])
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	int ret;
Thomas Bogendoerfer 3237e1
-	struct fw_port_cmd c;
Thomas Bogendoerfer 3237e1
+	struct adapter *adapter = pi->adapter;
Thomas Bogendoerfer 3237e1
+	unsigned int fw_caps = adapter->params.fw_caps_support;
Thomas Bogendoerfer 3237e1
+	struct fw_port_cmd cmd;
Thomas Bogendoerfer 3237e1
 	unsigned int rss_size;
Thomas Bogendoerfer 3237e1
+	enum fw_port_type port_type;
Thomas Bogendoerfer 3237e1
+	int mdio_addr;
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t pcaps, acaps;
Thomas Bogendoerfer 3237e1
+	int ret;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	memset(&c, 0, sizeof(c));
Thomas Bogendoerfer 3237e1
-	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
-				     FW_CMD_REQUEST_F | FW_CMD_READ_F |
Thomas Bogendoerfer 3237e1
-				     FW_PORT_CMD_PORTID_V(port));
Thomas Bogendoerfer 3237e1
-	c.action_to_len16 = cpu_to_be32(
Thomas Bogendoerfer 3237e1
-		FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
Thomas Bogendoerfer 3237e1
-		FW_LEN16(c));
Thomas Bogendoerfer 3237e1
-	ret = t4_wr_mbox(pi->adapter, mbox, &c, sizeof(c), &c);
Thomas Bogendoerfer 3237e1
+	/* If we haven't yet determined whether we're talking to Firmware
Thomas Bogendoerfer 3237e1
+	 * which knows the new 32-bit Port Capabilities, it's time to find
Thomas Bogendoerfer 3237e1
+	 * out now.  This will also tell new Firmware to send us Port Status
Thomas Bogendoerfer 3237e1
+	 * Updates using the new 32-bit Port Capabilities version of the
Thomas Bogendoerfer 3237e1
+	 * Port Information message.
Thomas Bogendoerfer 3237e1
+	 */
Thomas Bogendoerfer 3237e1
+	if (fw_caps == FW_CAPS_UNKNOWN) {
Thomas Bogendoerfer 3237e1
+		u32 param, val;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
Thomas Bogendoerfer 3237e1
+			 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32));
Thomas Bogendoerfer 3237e1
+		val = 1;
Thomas Bogendoerfer 3237e1
+		ret = t4_set_params(adapter, mbox, pf, vf, 1, &param, &val;;
Thomas Bogendoerfer 3237e1
+		fw_caps = (ret == 0 ? FW_CAPS32 : FW_CAPS16);
Thomas Bogendoerfer 3237e1
+		adapter->params.fw_caps_support = fw_caps;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	memset(&cmd, 0, sizeof(cmd));
Thomas Bogendoerfer 3237e1
+	cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
+				       FW_CMD_REQUEST_F | FW_CMD_READ_F |
Thomas Bogendoerfer 3237e1
+				       FW_PORT_CMD_PORTID_V(port));
Thomas Bogendoerfer 3237e1
+	cmd.action_to_len16 = cpu_to_be32(
Thomas Bogendoerfer 3237e1
+		FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
Thomas Bogendoerfer 3237e1
+				     ? FW_PORT_ACTION_GET_PORT_INFO
Thomas Bogendoerfer 3237e1
+				     : FW_PORT_ACTION_GET_PORT_INFO32) |
Thomas Bogendoerfer 3237e1
+		FW_LEN16(cmd));
Thomas Bogendoerfer 3237e1
+	ret = t4_wr_mbox(pi->adapter, mbox, &cmd, sizeof(cmd), &cmd);
Thomas Bogendoerfer 3237e1
 	if (ret)
Thomas Bogendoerfer 3237e1
 		return ret;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+	/* Extract the various fields from the Port Information message.
Thomas Bogendoerfer 3237e1
+	 */
Thomas Bogendoerfer 3237e1
+	if (fw_caps == FW_CAPS16) {
Thomas Bogendoerfer 3237e1
+		u32 lstatus = be32_to_cpu(cmd.u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PTYPE_G(lstatus);
Thomas Bogendoerfer 3237e1
+		mdio_addr = ((lstatus & FW_PORT_CMD_MDIOCAP_F)
Thomas Bogendoerfer 3237e1
+			     ? FW_PORT_CMD_MDIOADDR_G(lstatus)
Thomas Bogendoerfer 3237e1
+			     : -1);
Thomas Bogendoerfer 3237e1
+		pcaps = fwcaps16_to_caps32(be16_to_cpu(cmd.u.info.pcap));
Thomas Bogendoerfer 3237e1
+		acaps = fwcaps16_to_caps32(be16_to_cpu(cmd.u.info.acap));
Thomas Bogendoerfer 3237e1
+	} else {
Thomas Bogendoerfer 3237e1
+		u32 lstatus32 = be32_to_cpu(cmd.u.info32.lstatus32_to_cbllen32);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		mdio_addr = ((lstatus32 & FW_PORT_CMD_MDIOCAP32_F)
Thomas Bogendoerfer 3237e1
+			     ? FW_PORT_CMD_MDIOADDR32_G(lstatus32)
Thomas Bogendoerfer 3237e1
+			     : -1);
Thomas Bogendoerfer 3237e1
+		pcaps = be32_to_cpu(cmd.u.info32.pcaps32);
Thomas Bogendoerfer 3237e1
+		acaps = be32_to_cpu(cmd.u.info32.acaps32);
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	ret = t4_alloc_vi(pi->adapter, mbox, port, pf, vf, 1, mac, &rss_size);
Thomas Bogendoerfer 3237e1
 	if (ret < 0)
Thomas Bogendoerfer 3237e1
 		return ret;
Thomas Bogendoerfer 3237e1
@@ -8452,14 +8781,11 @@ int t4_init_portinfo(struct port_info *p
Thomas Bogendoerfer 3237e1
 	pi->lport = port;
Thomas Bogendoerfer 3237e1
 	pi->rss_size = rss_size;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	ret = be32_to_cpu(c.u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
-	pi->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP_F) ?
Thomas Bogendoerfer 3237e1
-		FW_PORT_CMD_MDIOADDR_G(ret) : -1;
Thomas Bogendoerfer 3237e1
-	pi->port_type = FW_PORT_CMD_PTYPE_G(ret);
Thomas Bogendoerfer 3237e1
+	pi->port_type = port_type;
Thomas Bogendoerfer 3237e1
+	pi->mdio_addr = mdio_addr;
Thomas Bogendoerfer 3237e1
 	pi->mod_type = FW_PORT_MOD_TYPE_NA;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	init_link_config(&pi->link_cfg, be16_to_cpu(c.u.info.pcap),
Thomas Bogendoerfer 3237e1
-			 be16_to_cpu(c.u.info.acap));
Thomas Bogendoerfer 3237e1
+	init_link_config(&pi->link_cfg, pcaps, acaps);
Thomas Bogendoerfer 3237e1
 	return 0;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
Thomas Bogendoerfer 3237e1
@@ -1173,7 +1173,8 @@ enum fw_params_param_pfvf {
Thomas Bogendoerfer 3237e1
 	FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_END = 0x2E,
Thomas Bogendoerfer 3237e1
 	FW_PARAMS_PARAM_PFVF_ETHOFLD_END = 0x30,
Thomas Bogendoerfer 3237e1
 	FW_PARAMS_PARAM_PFVF_CPLFW4MSG_ENCAP = 0x31,
Thomas Bogendoerfer 3237e1
-	FW_PARAMS_PARAM_PFVF_NCRYPTO_LOOKASIDE = 0x32
Thomas Bogendoerfer 3237e1
+	FW_PARAMS_PARAM_PFVF_NCRYPTO_LOOKASIDE = 0x32,
Thomas Bogendoerfer 3237e1
+	FW_PARAMS_PARAM_PFVF_PORT_CAPS32 = 0x3A,
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /*
Thomas Bogendoerfer 3237e1
@@ -2256,6 +2257,7 @@ struct fw_acl_vlan_cmd {
Thomas Bogendoerfer 3237e1
 #define FW_ACL_VLAN_CMD_FM_S	6
Thomas Bogendoerfer 3237e1
 #define FW_ACL_VLAN_CMD_FM_V(x)	((x) << FW_ACL_VLAN_CMD_FM_S)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+/* old 16-bit port capabilities bitmap (fw_port_cap16_t) */
Thomas Bogendoerfer 3237e1
 enum fw_port_cap {
Thomas Bogendoerfer 3237e1
 	FW_PORT_CAP_SPEED_100M		= 0x0001,
Thomas Bogendoerfer 3237e1
 	FW_PORT_CAP_SPEED_1G		= 0x0002,
Thomas Bogendoerfer 3237e1
@@ -2291,6 +2293,84 @@ enum fw_port_mdi {
Thomas Bogendoerfer 3237e1
 #define FW_PORT_CAP_MDI_S 9
Thomas Bogendoerfer 3237e1
 #define FW_PORT_CAP_MDI_V(x) ((x) << FW_PORT_CAP_MDI_S)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+/* new 32-bit port capabilities bitmap (fw_port_cap32_t) */
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_100M	0x00000001UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_1G		0x00000002UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_10G		0x00000004UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_25G		0x00000008UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_40G		0x00000010UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_50G		0x00000020UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_100G	0x00000040UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_200G	0x00000080UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_400G	0x00000100UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_RESERVED1	0x00000200UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_RESERVED2	0x00000400UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_SPEED_RESERVED3	0x00000800UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_RESERVED1		0x0000f000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_FC_RX		0x00010000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_FC_TX		0x00020000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_802_3_PAUSE	0x00040000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_802_3_ASM_DIR	0x00080000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_ANEG		0x00100000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_MDIX		0x00200000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_MDIAUTO		0x00400000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_FEC_RS		0x00800000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_FEC_BASER_RS	0x01000000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_FEC_RESERVED1	0x02000000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_FEC_RESERVED2	0x04000000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_FEC_RESERVED3	0x08000000UL
Thomas Bogendoerfer 3237e1
+#define	FW_PORT_CAP32_RESERVED2		0xf0000000UL
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_SPEED_S	0
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_SPEED_M	0xfff
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_SPEED_V(x)	((x) << FW_PORT_CAP32_SPEED_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_SPEED_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CAP32_SPEED_S) & FW_PORT_CAP32_SPEED_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FC_S	16
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FC_M	0x3
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FC_V(x)	((x) << FW_PORT_CAP32_FC_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FC_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CAP32_FC_S) & FW_PORT_CAP32_FC_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_802_3_S	18
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_802_3_M	0x3
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_802_3_V(x)	((x) << FW_PORT_CAP32_802_3_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_802_3_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CAP32_802_3_S) & FW_PORT_CAP32_802_3_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_ANEG_S	20
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_ANEG_M	0x1
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_ANEG_V(x)	((x) << FW_PORT_CAP32_ANEG_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_ANEG_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CAP32_ANEG_S) & FW_PORT_CAP32_ANEG_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+enum fw_port_mdi32 {
Thomas Bogendoerfer 3237e1
+	FW_PORT_CAP32_MDI_UNCHANGED,
Thomas Bogendoerfer 3237e1
+	FW_PORT_CAP32_MDI_AUTO,
Thomas Bogendoerfer 3237e1
+	FW_PORT_CAP32_MDI_F_STRAIGHT,
Thomas Bogendoerfer 3237e1
+	FW_PORT_CAP32_MDI_F_CROSSOVER
Thomas Bogendoerfer 3237e1
+};
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_MDI_S 21
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_MDI_M 3
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_MDI_V(x) ((x) << FW_PORT_CAP32_MDI_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_MDI_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CAP32_MDI_S) & FW_PORT_CAP32_MDI_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FEC_S	23
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FEC_M	0x1f
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FEC_V(x)	((x) << FW_PORT_CAP32_FEC_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CAP32_FEC_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CAP32_FEC_S) & FW_PORT_CAP32_FEC_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/* macros to isolate various 32-bit Port Capabilities sub-fields */
Thomas Bogendoerfer 3237e1
+#define CAP32_SPEED(__cap32) \
Thomas Bogendoerfer 3237e1
+	(FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) & __cap32)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define CAP32_FEC(__cap32) \
Thomas Bogendoerfer 3237e1
+	(FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M) & __cap32)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 enum fw_port_action {
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_L1_CFG		= 0x0001,
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_L2_CFG		= 0x0002,
Thomas Bogendoerfer 3237e1
@@ -2300,6 +2380,8 @@ enum fw_port_action {
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_DCB_READ_TRANS	= 0x0006,
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_DCB_READ_RECV	= 0x0007,
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_DCB_READ_DET	= 0x0008,
Thomas Bogendoerfer 3237e1
+	FW_PORT_ACTION_L1_CFG32		= 0x0009,
Thomas Bogendoerfer 3237e1
+	FW_PORT_ACTION_GET_PORT_INFO32	= 0x000a,
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_LOW_PWR_TO_NORMAL = 0x0010,
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_L1_LOW_PWR_EN	= 0x0011,
Thomas Bogendoerfer 3237e1
 	FW_PORT_ACTION_L2_WOL_MODE_EN	= 0x0012,
Thomas Bogendoerfer 3237e1
@@ -2447,6 +2529,18 @@ struct fw_port_cmd {
Thomas Bogendoerfer 3237e1
 				__be64 r12;
Thomas Bogendoerfer 3237e1
 			} control;
Thomas Bogendoerfer 3237e1
 		} dcb;
Thomas Bogendoerfer 3237e1
+		struct fw_port_l1cfg32 {
Thomas Bogendoerfer 3237e1
+			__be32 rcap32;
Thomas Bogendoerfer 3237e1
+			__be32 r;
Thomas Bogendoerfer 3237e1
+		} l1cfg32;
Thomas Bogendoerfer 3237e1
+		struct fw_port_info32 {
Thomas Bogendoerfer 3237e1
+			__be32 lstatus32_to_cbllen32;
Thomas Bogendoerfer 3237e1
+			__be32 auxlinfo32_mtu32;
Thomas Bogendoerfer 3237e1
+			__be32 linkattr32;
Thomas Bogendoerfer 3237e1
+			__be32 pcaps32;
Thomas Bogendoerfer 3237e1
+			__be32 acaps32;
Thomas Bogendoerfer 3237e1
+			__be32 lpacaps32;
Thomas Bogendoerfer 3237e1
+		} info32;
Thomas Bogendoerfer 3237e1
 	} u;
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -2555,6 +2649,85 @@ struct fw_port_cmd {
Thomas Bogendoerfer 3237e1
 #define FW_PORT_CMD_DCB_VERSION_G(x)	\
Thomas Bogendoerfer 3237e1
 	(((x) >> FW_PORT_CMD_DCB_VERSION_S) & FW_PORT_CMD_DCB_VERSION_M)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LSTATUS32_S		31
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LSTATUS32_M		0x1
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LSTATUS32_V(x)	((x) << FW_PORT_CMD_LSTATUS32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LSTATUS32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_LSTATUS32_S) & FW_PORT_CMD_LSTATUS32_M)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LSTATUS32_F	FW_PORT_CMD_LSTATUS32_V(1U)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LINKDNRC32_S	28
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LINKDNRC32_M	0x7
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LINKDNRC32_V(x)	((x) << FW_PORT_CMD_LINKDNRC32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_LINKDNRC32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_LINKDNRC32_S) & FW_PORT_CMD_LINKDNRC32_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_DCBXDIS32_S		27
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_DCBXDIS32_M		0x1
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_DCBXDIS32_V(x)	((x) << FW_PORT_CMD_DCBXDIS32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_DCBXDIS32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_DCBXDIS32_S) & FW_PORT_CMD_DCBXDIS32_M)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_DCBXDIS32_F	FW_PORT_CMD_DCBXDIS32_V(1U)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOCAP32_S		26
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOCAP32_M		0x1
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOCAP32_V(x)	((x) << FW_PORT_CMD_MDIOCAP32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOCAP32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_MDIOCAP32_S) & FW_PORT_CMD_MDIOCAP32_M)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOCAP32_F	FW_PORT_CMD_MDIOCAP32_V(1U)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOADDR32_S	21
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOADDR32_M	0x1f
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOADDR32_V(x)	((x) << FW_PORT_CMD_MDIOADDR32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MDIOADDR32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_MDIOADDR32_S) & FW_PORT_CMD_MDIOADDR32_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_PORTTYPE32_S	13
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_PORTTYPE32_M	0xff
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_PORTTYPE32_V(x)	((x) << FW_PORT_CMD_PORTTYPE32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_PORTTYPE32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_PORTTYPE32_S) & FW_PORT_CMD_PORTTYPE32_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MODTYPE32_S		8
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MODTYPE32_M		0x1f
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MODTYPE32_V(x)	((x) << FW_PORT_CMD_MODTYPE32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MODTYPE32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_MODTYPE32_S) & FW_PORT_CMD_MODTYPE32_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_CBLLEN32_S		0
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_CBLLEN32_M		0xff
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_CBLLEN32_V(x)	((x) << FW_PORT_CMD_CBLLEN32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_CBLLEN32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_CBLLEN32_S) & FW_PORT_CMD_CBLLEN32_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_AUXLINFO32_S	24
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_AUXLINFO32_M	0xff
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_AUXLINFO32_V(x)	((x) << FW_PORT_CMD_AUXLINFO32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_AUXLINFO32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_AUXLINFO32_S) & FW_PORT_CMD_AUXLINFO32_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KX4_S	2
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KX4_M	0x1
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KX4_V(x) \
Thomas Bogendoerfer 3237e1
+	((x) << FW_PORT_AUXLINFO32_KX4_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KX4_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_AUXLINFO32_KX4_S) & FW_PORT_AUXLINFO32_KX4_M)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KX4_F	FW_PORT_AUXLINFO32_KX4_V(1U)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KR_S	1
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KR_M	0x1
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KR_V(x) \
Thomas Bogendoerfer 3237e1
+	((x) << FW_PORT_AUXLINFO32_KR_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KR_G(x) \
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_AUXLINFO32_KR_S) & FW_PORT_AUXLINFO32_KR_M)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_AUXLINFO32_KR_F	FW_PORT_AUXLINFO32_KR_V(1U)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MTU32_S	0
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MTU32_M	0xffff
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MTU32_V(x)	((x) << FW_PORT_CMD_MTU32_S)
Thomas Bogendoerfer 3237e1
+#define FW_PORT_CMD_MTU32_G(x)	\
Thomas Bogendoerfer 3237e1
+	(((x) >> FW_PORT_CMD_MTU32_S) & FW_PORT_CMD_MTU32_M)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 enum fw_port_type {
Thomas Bogendoerfer 3237e1
 	FW_PORT_TYPE_FIBER_XFI,
Thomas Bogendoerfer 3237e1
 	FW_PORT_TYPE_FIBER_XAUI,
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
Thomas Bogendoerfer 3237e1
@@ -182,7 +182,7 @@ void t4vf_os_link_changed(struct adapter
Thomas Bogendoerfer 3237e1
 			break;
Thomas Bogendoerfer 3237e1
 		}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-		switch (pi->link_cfg.fc) {
Thomas Bogendoerfer 3237e1
+		switch ((int)pi->link_cfg.fc) {
Thomas Bogendoerfer 3237e1
 		case PAUSE_RX:
Thomas Bogendoerfer 3237e1
 			fc = "RX";
Thomas Bogendoerfer 3237e1
 			break;
Thomas Bogendoerfer 3237e1
@@ -191,7 +191,7 @@ void t4vf_os_link_changed(struct adapter
Thomas Bogendoerfer 3237e1
 			fc = "TX";
Thomas Bogendoerfer 3237e1
 			break;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-		case PAUSE_RX|PAUSE_TX:
Thomas Bogendoerfer 3237e1
+		case PAUSE_RX | PAUSE_TX:
Thomas Bogendoerfer 3237e1
 			fc = "RX/TX";
Thomas Bogendoerfer 3237e1
 			break;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -1213,7 +1213,11 @@ static int from_fw_port_mod_type(enum fw
Thomas Bogendoerfer 3237e1
 	} else if (port_type == FW_PORT_TYPE_SFP ||
Thomas Bogendoerfer 3237e1
 		   port_type == FW_PORT_TYPE_QSFP_10G ||
Thomas Bogendoerfer 3237e1
 		   port_type == FW_PORT_TYPE_QSA ||
Thomas Bogendoerfer 3237e1
-		   port_type == FW_PORT_TYPE_QSFP) {
Thomas Bogendoerfer 3237e1
+		   port_type == FW_PORT_TYPE_QSFP ||
Thomas Bogendoerfer 3237e1
+		   port_type == FW_PORT_TYPE_CR4_QSFP ||
Thomas Bogendoerfer 3237e1
+		   port_type == FW_PORT_TYPE_CR_QSFP ||
Thomas Bogendoerfer 3237e1
+		   port_type == FW_PORT_TYPE_CR2_QSFP ||
Thomas Bogendoerfer 3237e1
+		   port_type == FW_PORT_TYPE_SFP28) {
Thomas Bogendoerfer 3237e1
 		if (mod_type == FW_PORT_MOD_TYPE_LR ||
Thomas Bogendoerfer 3237e1
 		    mod_type == FW_PORT_MOD_TYPE_SR ||
Thomas Bogendoerfer 3237e1
 		    mod_type == FW_PORT_MOD_TYPE_ER ||
Thomas Bogendoerfer 3237e1
@@ -1224,6 +1228,9 @@ static int from_fw_port_mod_type(enum fw
Thomas Bogendoerfer 3237e1
 			return PORT_DA;
Thomas Bogendoerfer 3237e1
 		else
Thomas Bogendoerfer 3237e1
 			return PORT_OTHER;
Thomas Bogendoerfer 3237e1
+	} else if (port_type == FW_PORT_TYPE_KR4_100G ||
Thomas Bogendoerfer 3237e1
+		   port_type == FW_PORT_TYPE_KR_SFP28) {
Thomas Bogendoerfer 3237e1
+		return PORT_NONE;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	return PORT_OTHER;
Thomas Bogendoerfer 3237e1
@@ -1242,12 +1249,13 @@ static void fw_caps_to_lmm(enum fw_port_
Thomas Bogendoerfer 3237e1
 			   unsigned int fw_caps,
Thomas Bogendoerfer 3237e1
 			   unsigned long *link_mode_mask)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	#define SET_LMM(__lmm_name) __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name\
Thomas Bogendoerfer 3237e1
-			 ## _BIT, link_mode_mask)
Thomas Bogendoerfer 3237e1
+	#define SET_LMM(__lmm_name) \
Thomas Bogendoerfer 3237e1
+		__set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \
Thomas Bogendoerfer 3237e1
+			  link_mode_mask)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	#define FW_CAPS_TO_LMM(__fw_name, __lmm_name) \
Thomas Bogendoerfer 3237e1
 		do { \
Thomas Bogendoerfer 3237e1
-			if (fw_caps & FW_PORT_CAP_ ## __fw_name) \
Thomas Bogendoerfer 3237e1
+			if (fw_caps & FW_PORT_CAP32_ ## __fw_name) \
Thomas Bogendoerfer 3237e1
 				SET_LMM(__lmm_name); \
Thomas Bogendoerfer 3237e1
 		} while (0)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -1310,6 +1318,16 @@ static void fw_caps_to_lmm(enum fw_port_
Thomas Bogendoerfer 3237e1
 		SET_LMM(25000baseCR_Full);
Thomas Bogendoerfer 3237e1
 		break;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+	case FW_PORT_TYPE_KR_SFP28:
Thomas Bogendoerfer 3237e1
+		SET_LMM(Backplane);
Thomas Bogendoerfer 3237e1
+		SET_LMM(25000baseKR_Full);
Thomas Bogendoerfer 3237e1
+		break;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	case FW_PORT_TYPE_CR2_QSFP:
Thomas Bogendoerfer 3237e1
+		SET_LMM(FIBRE);
Thomas Bogendoerfer 3237e1
+		SET_LMM(50000baseSR2_Full);
Thomas Bogendoerfer 3237e1
+		break;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	case FW_PORT_TYPE_KR4_100G:
Thomas Bogendoerfer 3237e1
 	case FW_PORT_TYPE_CR4_QSFP:
Thomas Bogendoerfer 3237e1
 		SET_LMM(FIBRE);
Thomas Bogendoerfer 3237e1
@@ -1329,12 +1347,18 @@ static void fw_caps_to_lmm(enum fw_port_
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 static int cxgb4vf_get_link_ksettings(struct net_device *dev,
Thomas Bogendoerfer 3237e1
-				      struct ethtool_link_ksettings
Thomas Bogendoerfer 3237e1
-							*link_ksettings)
Thomas Bogendoerfer 3237e1
+				  struct ethtool_link_ksettings *link_ksettings)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
-	const struct port_info *pi = netdev_priv(dev);
Thomas Bogendoerfer 3237e1
+	struct port_info *pi = netdev_priv(dev);
Thomas Bogendoerfer 3237e1
 	struct ethtool_link_settings *base = &link_ksettings->base;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+	/* For the nonce, the Firmware doesn't send up Port State changes
Thomas Bogendoerfer 3237e1
+	 * when the Virtual Interface attached to the Port is down.  So
Thomas Bogendoerfer 3237e1
+	 * if it's down, let's grab any changes.
Thomas Bogendoerfer 3237e1
+	 */
Thomas Bogendoerfer 3237e1
+	if (!netif_running(dev))
Thomas Bogendoerfer 3237e1
+		(void)t4vf_update_port_info(pi);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 	ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
Thomas Bogendoerfer 3237e1
 	ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
Thomas Bogendoerfer 3237e1
 	ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising);
Thomas Bogendoerfer 3237e1
@@ -1351,11 +1375,11 @@ static int cxgb4vf_get_link_ksettings(st
Thomas Bogendoerfer 3237e1
 		base->mdio_support = 0;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	fw_caps_to_lmm(pi->port_type, pi->link_cfg.supported,
Thomas Bogendoerfer 3237e1
+	fw_caps_to_lmm(pi->port_type, pi->link_cfg.pcaps,
Thomas Bogendoerfer 3237e1
 		       link_ksettings->link_modes.supported);
Thomas Bogendoerfer 3237e1
-	fw_caps_to_lmm(pi->port_type, pi->link_cfg.advertising,
Thomas Bogendoerfer 3237e1
+	fw_caps_to_lmm(pi->port_type, pi->link_cfg.acaps,
Thomas Bogendoerfer 3237e1
 		       link_ksettings->link_modes.advertising);
Thomas Bogendoerfer 3237e1
-	fw_caps_to_lmm(pi->port_type, pi->link_cfg.lp_advertising,
Thomas Bogendoerfer 3237e1
+	fw_caps_to_lmm(pi->port_type, pi->link_cfg.lpacaps,
Thomas Bogendoerfer 3237e1
 		       link_ksettings->link_modes.lp_advertising);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	if (netif_carrier_ok(dev)) {
Thomas Bogendoerfer 3237e1
@@ -1367,7 +1391,7 @@ static int cxgb4vf_get_link_ksettings(st
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	base->autoneg = pi->link_cfg.autoneg;
Thomas Bogendoerfer 3237e1
-	if (pi->link_cfg.supported & FW_PORT_CAP_ANEG)
Thomas Bogendoerfer 3237e1
+	if (pi->link_cfg.pcaps & FW_PORT_CAP32_ANEG)
Thomas Bogendoerfer 3237e1
 		ethtool_link_ksettings_add_link_mode(link_ksettings,
Thomas Bogendoerfer 3237e1
 						     supported, Autoneg);
Thomas Bogendoerfer 3237e1
 	if (pi->link_cfg.autoneg)
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
Thomas Bogendoerfer 3237e1
@@ -104,24 +104,62 @@ struct t4vf_port_stats {
Thomas Bogendoerfer 3237e1
 /*
Thomas Bogendoerfer 3237e1
  * Per-"port" (Virtual Interface) link configuration ...
Thomas Bogendoerfer 3237e1
  */
Thomas Bogendoerfer 3237e1
-struct link_config {
Thomas Bogendoerfer 3237e1
-	unsigned int   supported;        /* link capabilities */
Thomas Bogendoerfer 3237e1
-	unsigned int   advertising;      /* advertised capabilities */
Thomas Bogendoerfer 3237e1
-	unsigned short lp_advertising;   /* peer advertised capabilities */
Thomas Bogendoerfer 3237e1
-	unsigned int   requested_speed;  /* speed user has requested */
Thomas Bogendoerfer 3237e1
-	unsigned int   speed;            /* actual link speed */
Thomas Bogendoerfer 3237e1
-	unsigned char  requested_fc;     /* flow control user has requested */
Thomas Bogendoerfer 3237e1
-	unsigned char  fc;               /* actual link flow control */
Thomas Bogendoerfer 3237e1
-	unsigned char  autoneg;          /* autonegotiating? */
Thomas Bogendoerfer 3237e1
-	unsigned char  link_ok;          /* link up? */
Thomas Bogendoerfer 3237e1
+typedef u16 fw_port_cap16_t;    /* 16-bit Port Capabilities integral value */
Thomas Bogendoerfer 3237e1
+typedef u32 fw_port_cap32_t;    /* 32-bit Port Capabilities integral value */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+enum fw_caps {
Thomas Bogendoerfer 3237e1
+	FW_CAPS_UNKNOWN	= 0,	/* 0'ed out initial state */
Thomas Bogendoerfer 3237e1
+	FW_CAPS16	= 1,	/* old Firmware: 16-bit Port Capabilities */
Thomas Bogendoerfer 3237e1
+	FW_CAPS32	= 2,	/* new Firmware: 32-bit Port Capabilities */
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-enum {
Thomas Bogendoerfer 3237e1
-	PAUSE_RX      = 1 << 0,
Thomas Bogendoerfer 3237e1
-	PAUSE_TX      = 1 << 1,
Thomas Bogendoerfer 3237e1
-	PAUSE_AUTONEG = 1 << 2
Thomas Bogendoerfer 3237e1
+enum cc_pause {
Thomas Bogendoerfer 3237e1
+	PAUSE_RX	= 1 << 0,
Thomas Bogendoerfer 3237e1
+	PAUSE_TX	= 1 << 1,
Thomas Bogendoerfer 3237e1
+	PAUSE_AUTONEG	= 1 << 2
Thomas Bogendoerfer 3237e1
+};
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+enum cc_fec {
Thomas Bogendoerfer 3237e1
+	FEC_AUTO	= 1 << 0,	/* IEEE 802.3 "automatic" */
Thomas Bogendoerfer 3237e1
+	FEC_RS		= 1 << 1,	/* Reed-Solomon */
Thomas Bogendoerfer 3237e1
+	FEC_BASER_RS	= 1 << 2,	/* BaseR/Reed-Solomon */
Thomas Bogendoerfer 3237e1
+};
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+struct link_config {
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t pcaps;		/* link capabilities */
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t	acaps;		/* advertised capabilities */
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t	lpacaps;	/* peer advertised capabilities */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t	speed_caps;	/* speed(s) user has requested */
Thomas Bogendoerfer 3237e1
+	u32		speed;		/* actual link speed */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	enum cc_pause	requested_fc;	/* flow control user has requested */
Thomas Bogendoerfer 3237e1
+	enum cc_pause	fc;		/* actual link flow control */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	enum cc_fec	auto_fec;	/* Forward Error Correction: */
Thomas Bogendoerfer 3237e1
+	enum cc_fec	requested_fec;	/*   "automatic" (IEEE 802.3), */
Thomas Bogendoerfer 3237e1
+	enum cc_fec	fec;		/*   requested, and actual in use */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	unsigned char	autoneg;	/* autonegotiating? */
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	unsigned char	link_ok;	/* link up? */
Thomas Bogendoerfer 3237e1
+	unsigned char	link_down_rc;	/* link down reason */
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+/* Return true if the Link Configuration supports "High Speeds" (those greater
Thomas Bogendoerfer 3237e1
+ * than 1Gb/s).
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static inline bool is_x_10g_port(const struct link_config *lc)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t speeds, high_speeds;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	speeds = FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_G(lc->pcaps));
Thomas Bogendoerfer 3237e1
+	high_speeds =
Thomas Bogendoerfer 3237e1
+		speeds & ~(FW_PORT_CAP32_SPEED_100M | FW_PORT_CAP32_SPEED_1G);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return high_speeds != 0;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
 /*
Thomas Bogendoerfer 3237e1
  * General device parameters ...
Thomas Bogendoerfer 3237e1
  */
Thomas Bogendoerfer 3237e1
@@ -227,6 +265,7 @@ struct adapter_params {
Thomas Bogendoerfer 3237e1
 	struct arch_specific_params arch; /* chip specific params */
Thomas Bogendoerfer 3237e1
 	enum chip_type chip;		/* chip code */
Thomas Bogendoerfer 3237e1
 	u8 nports;			/* # of Ethernet "ports" */
Thomas Bogendoerfer 3237e1
+	u8 fw_caps_support;		/* 32-bit Port Capabilities */
Thomas Bogendoerfer 3237e1
 };
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /* Firmware Mailbox Command/Reply log.  All values are in Host-Endian format.
Thomas Bogendoerfer 3237e1
@@ -266,24 +305,6 @@ static inline struct mbox_cmd *mbox_cmd_
Thomas Bogendoerfer 3237e1
 #define for_each_port(adapter, iter) \
Thomas Bogendoerfer 3237e1
 	for (iter = 0; iter < (adapter)->params.nports; iter++)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-static inline bool is_10g_port(const struct link_config *lc)
Thomas Bogendoerfer 3237e1
-{
Thomas Bogendoerfer 3237e1
-	return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;
Thomas Bogendoerfer 3237e1
-}
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-/* Return true if the Link Configuration supports "High Speeds" (those greater
Thomas Bogendoerfer 3237e1
- * than 1Gb/s).
Thomas Bogendoerfer 3237e1
- */
Thomas Bogendoerfer 3237e1
-static inline bool is_x_10g_port(const struct link_config *lc)
Thomas Bogendoerfer 3237e1
-{
Thomas Bogendoerfer 3237e1
-	unsigned int speeds, high_speeds;
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-	speeds = FW_PORT_CAP_SPEED_V(FW_PORT_CAP_SPEED_G(lc->supported));
Thomas Bogendoerfer 3237e1
-	high_speeds = speeds & ~(FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G);
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-	return high_speeds != 0;
Thomas Bogendoerfer 3237e1
-}
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
 static inline unsigned int core_ticks_per_usec(const struct adapter *adapter)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
 	return adapter->params.vpd.cclk / 1000;
Thomas Bogendoerfer 3237e1
@@ -387,6 +408,7 @@ int t4vf_iq_free(struct adapter *, unsig
Thomas Bogendoerfer 3237e1
 		 unsigned int);
Thomas Bogendoerfer 3237e1
 int t4vf_eth_eq_free(struct adapter *, unsigned int);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+int t4vf_update_port_info(struct port_info *pi);
Thomas Bogendoerfer 3237e1
 int t4vf_handle_fw_rpl(struct adapter *, const __be64 *);
Thomas Bogendoerfer 3237e1
 int t4vf_prep_adapter(struct adapter *);
Thomas Bogendoerfer 3237e1
 int t4vf_get_vf_mac_acl(struct adapter *adapter, unsigned int pf,
Thomas Bogendoerfer 3237e1
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
Thomas Bogendoerfer 3237e1
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
Thomas Bogendoerfer 3237e1
@@ -313,32 +313,130 @@ int t4vf_wr_mbox_core(struct adapter *ad
Thomas Bogendoerfer 3237e1
 	return ret;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
Thomas Bogendoerfer 3237e1
-		     FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_25G | \
Thomas Bogendoerfer 3237e1
-		     FW_PORT_CAP_SPEED_40G | FW_PORT_CAP_SPEED_100G | \
Thomas Bogendoerfer 3237e1
-		     FW_PORT_CAP_ANEG)
Thomas Bogendoerfer 3237e1
+#define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \
Thomas Bogendoerfer 3237e1
+		     FW_PORT_CAP32_ANEG)
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
+ *	fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits
Thomas Bogendoerfer 3237e1
+ *	@caps16: a 16-bit Port Capabilities value
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Returns the equivalent 32-bit Port Capabilities value.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t caps32 = 0;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#define CAP16_TO_CAP32(__cap) \
Thomas Bogendoerfer 3237e1
+		do { \
Thomas Bogendoerfer 3237e1
+			if (caps16 & FW_PORT_CAP_##__cap) \
Thomas Bogendoerfer 3237e1
+				caps32 |= FW_PORT_CAP32_##__cap; \
Thomas Bogendoerfer 3237e1
+		} while (0)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_100M);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_1G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_25G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_10G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_40G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(SPEED_100G);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FC_RX);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FC_TX);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(ANEG);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(MDIX);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(MDIAUTO);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FEC_RS);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(FEC_BASER_RS);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(802_3_PAUSE);
Thomas Bogendoerfer 3237e1
+	CAP16_TO_CAP32(802_3_ASM_DIR);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#undef CAP16_TO_CAP32
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return caps32;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/* Translate Firmware Pause specification to Common Code */
Thomas Bogendoerfer 3237e1
+static inline enum cc_pause fwcap_to_cc_pause(fw_port_cap32_t fw_pause)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	enum cc_pause cc_pause = 0;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (fw_pause & FW_PORT_CAP32_FC_RX)
Thomas Bogendoerfer 3237e1
+		cc_pause |= PAUSE_RX;
Thomas Bogendoerfer 3237e1
+	if (fw_pause & FW_PORT_CAP32_FC_TX)
Thomas Bogendoerfer 3237e1
+		cc_pause |= PAUSE_TX;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return cc_pause;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/* Translate Firmware Forward Error Correction specification to Common Code */
Thomas Bogendoerfer 3237e1
+static inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	enum cc_fec cc_fec = 0;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (fw_fec & FW_PORT_CAP32_FEC_RS)
Thomas Bogendoerfer 3237e1
+		cc_fec |= FEC_RS;
Thomas Bogendoerfer 3237e1
+	if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
Thomas Bogendoerfer 3237e1
+		cc_fec |= FEC_BASER_RS;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return cc_fec;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
+ * Return the highest speed set in the port capabilities, in Mb/s.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+static unsigned int fwcap_to_speed(fw_port_cap32_t caps)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	#define TEST_SPEED_RETURN(__caps_speed, __speed) \
Thomas Bogendoerfer 3237e1
+		do { \
Thomas Bogendoerfer 3237e1
+			if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \
Thomas Bogendoerfer 3237e1
+				return __speed; \
Thomas Bogendoerfer 3237e1
+		} while (0)
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(400G, 400000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(200G, 200000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(100G, 100000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(50G,   50000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(40G,   40000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(25G,   25000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(10G,   10000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(1G,     1000);
Thomas Bogendoerfer 3237e1
+	TEST_SPEED_RETURN(100M,    100);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	#undef TEST_SPEED_RETURN
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return 0;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/*
Thomas Bogendoerfer 3237e1
  *	init_link_config - initialize a link's SW state
Thomas Bogendoerfer 3237e1
  *	@lc: structure holding the link state
Thomas Bogendoerfer 3237e1
- *	@caps: link capabilities
Thomas Bogendoerfer 3237e1
+ *	@pcaps: link Port Capabilities
Thomas Bogendoerfer 3237e1
+ *	@acaps: link current Advertised Port Capabilities
Thomas Bogendoerfer 3237e1
  *
Thomas Bogendoerfer 3237e1
  *	Initializes the SW state maintained for each link, including the link's
Thomas Bogendoerfer 3237e1
  *	capabilities and default speed/flow-control/autonegotiation settings.
Thomas Bogendoerfer 3237e1
  */
Thomas Bogendoerfer 3237e1
-static void init_link_config(struct link_config *lc, unsigned int caps)
Thomas Bogendoerfer 3237e1
-{
Thomas Bogendoerfer 3237e1
-	lc->supported = caps;
Thomas Bogendoerfer 3237e1
-	lc->lp_advertising = 0;
Thomas Bogendoerfer 3237e1
-	lc->requested_speed = 0;
Thomas Bogendoerfer 3237e1
+static void init_link_config(struct link_config *lc,
Thomas Bogendoerfer 3237e1
+			     fw_port_cap32_t pcaps,
Thomas Bogendoerfer 3237e1
+			     fw_port_cap32_t acaps)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	lc->pcaps = pcaps;
Thomas Bogendoerfer 3237e1
+	lc->lpacaps = 0;
Thomas Bogendoerfer 3237e1
+	lc->speed_caps = 0;
Thomas Bogendoerfer 3237e1
 	lc->speed = 0;
Thomas Bogendoerfer 3237e1
 	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
Thomas Bogendoerfer 3237e1
-	if (lc->supported & FW_PORT_CAP_ANEG) {
Thomas Bogendoerfer 3237e1
-		lc->advertising = lc->supported & ADVERT_MASK;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	/* For Forward Error Control, we default to whatever the Firmware
Thomas Bogendoerfer 3237e1
+	 * tells us the Link is currently advertising.
Thomas Bogendoerfer 3237e1
+	 */
Thomas Bogendoerfer 3237e1
+	lc->auto_fec = fwcap_to_cc_fec(acaps);
Thomas Bogendoerfer 3237e1
+	lc->requested_fec = FEC_AUTO;
Thomas Bogendoerfer 3237e1
+	lc->fec = lc->auto_fec;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (lc->pcaps & FW_PORT_CAP32_ANEG) {
Thomas Bogendoerfer 3237e1
+		lc->acaps = acaps & ADVERT_MASK;
Thomas Bogendoerfer 3237e1
 		lc->autoneg = AUTONEG_ENABLE;
Thomas Bogendoerfer 3237e1
 		lc->requested_fc |= PAUSE_AUTONEG;
Thomas Bogendoerfer 3237e1
 	} else {
Thomas Bogendoerfer 3237e1
-		lc->advertising = 0;
Thomas Bogendoerfer 3237e1
+		lc->acaps = 0;
Thomas Bogendoerfer 3237e1
 		lc->autoneg = AUTONEG_DISABLE;
Thomas Bogendoerfer 3237e1
 	}
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
@@ -351,9 +449,30 @@ static void init_link_config(struct link
Thomas Bogendoerfer 3237e1
 int t4vf_port_init(struct adapter *adapter, int pidx)
Thomas Bogendoerfer 3237e1
 {
Thomas Bogendoerfer 3237e1
 	struct port_info *pi = adap2pinfo(adapter, pidx);
Thomas Bogendoerfer 3237e1
+	unsigned int fw_caps = adapter->params.fw_caps_support;
Thomas Bogendoerfer 3237e1
 	struct fw_vi_cmd vi_cmd, vi_rpl;
Thomas Bogendoerfer 3237e1
 	struct fw_port_cmd port_cmd, port_rpl;
Thomas Bogendoerfer 3237e1
-	int v;
Thomas Bogendoerfer 3237e1
+	enum fw_port_type port_type;
Thomas Bogendoerfer 3237e1
+	int mdio_addr;
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t pcaps, acaps;
Thomas Bogendoerfer 3237e1
+	int ret;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	/* If we haven't yet determined whether we're talking to Firmware
Thomas Bogendoerfer 3237e1
+	 * which knows the new 32-bit Port Capabilities, it's time to find
Thomas Bogendoerfer 3237e1
+	 * out now.  This will also tell new Firmware to send us Port Status
Thomas Bogendoerfer 3237e1
+	 * Updates using the new 32-bit Port Capabilities version of the
Thomas Bogendoerfer 3237e1
+	 * Port Information message.
Thomas Bogendoerfer 3237e1
+	 */
Thomas Bogendoerfer 3237e1
+	if (fw_caps == FW_CAPS_UNKNOWN) {
Thomas Bogendoerfer 3237e1
+		u32 param, val;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
Thomas Bogendoerfer 3237e1
+			 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32));
Thomas Bogendoerfer 3237e1
+		val = 1;
Thomas Bogendoerfer 3237e1
+		ret = t4vf_set_params(adapter, 1, &param, &val;;
Thomas Bogendoerfer 3237e1
+		fw_caps = (ret == 0 ? FW_CAPS32 : FW_CAPS16);
Thomas Bogendoerfer 3237e1
+		adapter->params.fw_caps_support = fw_caps;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	/*
Thomas Bogendoerfer 3237e1
 	 * Execute a VI Read command to get our Virtual Interface information
Thomas Bogendoerfer 3237e1
@@ -365,9 +484,9 @@ int t4vf_port_init(struct adapter *adapt
Thomas Bogendoerfer 3237e1
 				       FW_CMD_READ_F);
Thomas Bogendoerfer 3237e1
 	vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd));
Thomas Bogendoerfer 3237e1
 	vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID_V(pi->viid));
Thomas Bogendoerfer 3237e1
-	v = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl);
Thomas Bogendoerfer 3237e1
-	if (v)
Thomas Bogendoerfer 3237e1
-		return v;
Thomas Bogendoerfer 3237e1
+	ret = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl);
Thomas Bogendoerfer 3237e1
+	if (ret != FW_SUCCESS)
Thomas Bogendoerfer 3237e1
+		return ret;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 	BUG_ON(pi->port_id != FW_VI_CMD_PORTID_G(vi_rpl.portid_pkd));
Thomas Bogendoerfer 3237e1
 	pi->rss_size = FW_VI_CMD_RSSSIZE_G(be16_to_cpu(vi_rpl.rsssize_pkd));
Thomas Bogendoerfer 3237e1
@@ -385,21 +504,42 @@ int t4vf_port_init(struct adapter *adapt
Thomas Bogendoerfer 3237e1
 					    FW_CMD_REQUEST_F |
Thomas Bogendoerfer 3237e1
 					    FW_CMD_READ_F |
Thomas Bogendoerfer 3237e1
 					    FW_PORT_CMD_PORTID_V(pi->port_id));
Thomas Bogendoerfer 3237e1
-	port_cmd.action_to_len16 =
Thomas Bogendoerfer 3237e1
-		cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
Thomas Bogendoerfer 3237e1
-			    FW_LEN16(port_cmd));
Thomas Bogendoerfer 3237e1
-	v = t4vf_wr_mbox(adapter, &port_cmd, sizeof(port_cmd), &port_rpl);
Thomas Bogendoerfer 3237e1
-	if (v)
Thomas Bogendoerfer 3237e1
-		return v;
Thomas Bogendoerfer 3237e1
+	port_cmd.action_to_len16 = cpu_to_be32(
Thomas Bogendoerfer 3237e1
+		FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
Thomas Bogendoerfer 3237e1
+				     ? FW_PORT_ACTION_GET_PORT_INFO
Thomas Bogendoerfer 3237e1
+				     : FW_PORT_ACTION_GET_PORT_INFO32) |
Thomas Bogendoerfer 3237e1
+		FW_LEN16(port_cmd));
Thomas Bogendoerfer 3237e1
+	ret = t4vf_wr_mbox(adapter, &port_cmd, sizeof(port_cmd), &port_rpl);
Thomas Bogendoerfer 3237e1
+	if (ret != FW_SUCCESS)
Thomas Bogendoerfer 3237e1
+		return ret;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	/* Extract the various fields from the Port Information message. */
Thomas Bogendoerfer 3237e1
+	if (fw_caps == FW_CAPS16) {
Thomas Bogendoerfer 3237e1
+		u32 lstatus = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PTYPE_G(lstatus);
Thomas Bogendoerfer 3237e1
+		mdio_addr = ((lstatus & FW_PORT_CMD_MDIOCAP_F)
Thomas Bogendoerfer 3237e1
+			     ? FW_PORT_CMD_MDIOADDR_G(lstatus)
Thomas Bogendoerfer 3237e1
+			     : -1);
Thomas Bogendoerfer 3237e1
+		pcaps = fwcaps16_to_caps32(be16_to_cpu(port_rpl.u.info.pcap));
Thomas Bogendoerfer 3237e1
+		acaps = fwcaps16_to_caps32(be16_to_cpu(port_rpl.u.info.acap));
Thomas Bogendoerfer 3237e1
+	} else {
Thomas Bogendoerfer 3237e1
+		u32 lstatus32 =
Thomas Bogendoerfer 3237e1
+			   be32_to_cpu(port_rpl.u.info32.lstatus32_to_cbllen32);
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	v = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
-	pi->mdio_addr = (v & FW_PORT_CMD_MDIOCAP_F) ?
Thomas Bogendoerfer 3237e1
-			FW_PORT_CMD_MDIOADDR_G(v) : -1;
Thomas Bogendoerfer 3237e1
-	pi->port_type = FW_PORT_CMD_PTYPE_G(v);
Thomas Bogendoerfer 3237e1
-	pi->mod_type = FW_PORT_MOD_TYPE_NA;
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		mdio_addr = ((lstatus32 & FW_PORT_CMD_MDIOCAP32_F)
Thomas Bogendoerfer 3237e1
+			     ? FW_PORT_CMD_MDIOADDR32_G(lstatus32)
Thomas Bogendoerfer 3237e1
+			     : -1);
Thomas Bogendoerfer 3237e1
+		pcaps = be32_to_cpu(port_rpl.u.info32.pcaps32);
Thomas Bogendoerfer 3237e1
+		acaps = be32_to_cpu(port_rpl.u.info32.acaps32);
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
-	init_link_config(&pi->link_cfg, be16_to_cpu(port_rpl.u.info.pcap));
Thomas Bogendoerfer 3237e1
+	pi->port_type = port_type;
Thomas Bogendoerfer 3237e1
+	pi->mdio_addr = mdio_addr;
Thomas Bogendoerfer 3237e1
+	pi->mod_type = FW_PORT_MOD_TYPE_NA;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
+	init_link_config(&pi->link_cfg, pcaps, acaps);
Thomas Bogendoerfer 3237e1
 	return 0;
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
@@ -1667,6 +1807,202 @@ int t4vf_eth_eq_free(struct adapter *ada
Thomas Bogendoerfer 3237e1
 }
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 /**
Thomas Bogendoerfer 3237e1
+ *	t4vf_link_down_rc_str - return a string for a Link Down Reason Code
Thomas Bogendoerfer 3237e1
+ *	@link_down_rc: Link Down Reason Code
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Returns a string representation of the Link Down Reason Code.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+const char *t4vf_link_down_rc_str(unsigned char link_down_rc)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	static const char * const reason[] = {
Thomas Bogendoerfer 3237e1
+		"Link Down",
Thomas Bogendoerfer 3237e1
+		"Remote Fault",
Thomas Bogendoerfer 3237e1
+		"Auto-negotiation Failure",
Thomas Bogendoerfer 3237e1
+		"Reserved",
Thomas Bogendoerfer 3237e1
+		"Insufficient Airflow",
Thomas Bogendoerfer 3237e1
+		"Unable To Determine Reason",
Thomas Bogendoerfer 3237e1
+		"No RX Signal Detected",
Thomas Bogendoerfer 3237e1
+		"Reserved",
Thomas Bogendoerfer 3237e1
+	};
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (link_down_rc >= ARRAY_SIZE(reason))
Thomas Bogendoerfer 3237e1
+		return "Bad Reason Code";
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	return reason[link_down_rc];
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
+ *	t4vf_handle_get_port_info - process a FW reply message
Thomas Bogendoerfer 3237e1
+ *	@pi: the port info
Thomas Bogendoerfer 3237e1
+ *	@rpl: start of the FW message
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	Processes a GET_PORT_INFO FW reply message.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+void t4vf_handle_get_port_info(struct port_info *pi,
Thomas Bogendoerfer 3237e1
+			       const struct fw_port_cmd *cmd)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
Thomas Bogendoerfer 3237e1
+	struct adapter *adapter = pi->adapter;
Thomas Bogendoerfer 3237e1
+	struct link_config *lc = &pi->link_cfg;
Thomas Bogendoerfer 3237e1
+	int link_ok, linkdnrc;
Thomas Bogendoerfer 3237e1
+	enum fw_port_type port_type;
Thomas Bogendoerfer 3237e1
+	enum fw_port_module_type mod_type;
Thomas Bogendoerfer 3237e1
+	unsigned int speed, fc, fec;
Thomas Bogendoerfer 3237e1
+	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	/* Extract the various fields from the Port Information message. */
Thomas Bogendoerfer 3237e1
+	switch (action) {
Thomas Bogendoerfer 3237e1
+	case FW_PORT_ACTION_GET_PORT_INFO: {
Thomas Bogendoerfer 3237e1
+		u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		link_ok = (lstatus & FW_PORT_CMD_LSTATUS_F) != 0;
Thomas Bogendoerfer 3237e1
+		linkdnrc = FW_PORT_CMD_LINKDNRC_G(lstatus);
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PTYPE_G(lstatus);
Thomas Bogendoerfer 3237e1
+		mod_type = FW_PORT_CMD_MODTYPE_G(lstatus);
Thomas Bogendoerfer 3237e1
+		pcaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.pcap));
Thomas Bogendoerfer 3237e1
+		acaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.acap));
Thomas Bogendoerfer 3237e1
+		lpacaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.lpacap));
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		/* Unfortunately the format of the Link Status in the old
Thomas Bogendoerfer 3237e1
+		 * 16-bit Port Information message isn't the same as the
Thomas Bogendoerfer 3237e1
+		 * 16-bit Port Capabilities bitfield used everywhere else ...
Thomas Bogendoerfer 3237e1
+		 */
Thomas Bogendoerfer 3237e1
+		linkattr = 0;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_RXPAUSE_F)
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_FC_RX;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_TXPAUSE_F)
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_FC_TX;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_SPEED_100M;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_SPEED_1G;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_SPEED_10G;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_SPEED_25G;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_SPEED_40G;
Thomas Bogendoerfer 3237e1
+		if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
Thomas Bogendoerfer 3237e1
+			linkattr |= FW_PORT_CAP32_SPEED_100G;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		break;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	case FW_PORT_ACTION_GET_PORT_INFO32: {
Thomas Bogendoerfer 3237e1
+		u32 lstatus32;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		lstatus32 = be32_to_cpu(cmd->u.info32.lstatus32_to_cbllen32);
Thomas Bogendoerfer 3237e1
+		link_ok = (lstatus32 & FW_PORT_CMD_LSTATUS32_F) != 0;
Thomas Bogendoerfer 3237e1
+		linkdnrc = FW_PORT_CMD_LINKDNRC32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		mod_type = FW_PORT_CMD_MODTYPE32_G(lstatus32);
Thomas Bogendoerfer 3237e1
+		pcaps = be32_to_cpu(cmd->u.info32.pcaps32);
Thomas Bogendoerfer 3237e1
+		acaps = be32_to_cpu(cmd->u.info32.acaps32);
Thomas Bogendoerfer 3237e1
+		lpacaps = be32_to_cpu(cmd->u.info32.lpacaps32);
Thomas Bogendoerfer 3237e1
+		linkattr = be32_to_cpu(cmd->u.info32.linkattr32);
Thomas Bogendoerfer 3237e1
+		break;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	default:
Thomas Bogendoerfer 3237e1
+		dev_err(adapter->pdev_dev, "Handle Port Information: Bad Command/Action %#x\n",
Thomas Bogendoerfer 3237e1
+			be32_to_cpu(cmd->action_to_len16));
Thomas Bogendoerfer 3237e1
+		return;
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	fec = fwcap_to_cc_fec(acaps);
Thomas Bogendoerfer 3237e1
+	fc = fwcap_to_cc_pause(linkattr);
Thomas Bogendoerfer 3237e1
+	speed = fwcap_to_speed(linkattr);
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (mod_type != pi->mod_type) {
Thomas Bogendoerfer 3237e1
+		/* When a new Transceiver Module is inserted, the Firmware
Thomas Bogendoerfer 3237e1
+		 * will examine any Forward Error Correction parameters
Thomas Bogendoerfer 3237e1
+		 * present in the Transceiver Module i2c EPROM and determine
Thomas Bogendoerfer 3237e1
+		 * the supported and recommended FEC settings from those
Thomas Bogendoerfer 3237e1
+		 * based on IEEE 802.3 standards.  We always record the
Thomas Bogendoerfer 3237e1
+		 * IEEE 802.3 recommended "automatic" settings.
Thomas Bogendoerfer 3237e1
+		 */
Thomas Bogendoerfer 3237e1
+		lc->auto_fec = fec;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		/* Some versions of the early T6 Firmware "cheated" when
Thomas Bogendoerfer 3237e1
+		 * handling different Transceiver Modules by changing the
Thomas Bogendoerfer 3237e1
+		 * underlaying Port Type reported to the Host Drivers.  As
Thomas Bogendoerfer 3237e1
+		 * such we need to capture whatever Port Type the Firmware
Thomas Bogendoerfer 3237e1
+		 * sends us and record it in case it's different from what we
Thomas Bogendoerfer 3237e1
+		 * were told earlier.  Unfortunately, since Firmware is
Thomas Bogendoerfer 3237e1
+		 * forever, we'll need to keep this code here forever, but in
Thomas Bogendoerfer 3237e1
+		 * later T6 Firmware it should just be an assignment of the
Thomas Bogendoerfer 3237e1
+		 * same value already recorded.
Thomas Bogendoerfer 3237e1
+		 */
Thomas Bogendoerfer 3237e1
+		pi->port_type = port_type;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		pi->mod_type = mod_type;
Thomas Bogendoerfer 3237e1
+		t4vf_os_portmod_changed(adapter, pi->pidx);
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	if (link_ok != lc->link_ok || speed != lc->speed ||
Thomas Bogendoerfer 3237e1
+	    fc != lc->fc || fec != lc->fec) {	/* something changed */
Thomas Bogendoerfer 3237e1
+		if (!link_ok && lc->link_ok) {
Thomas Bogendoerfer 3237e1
+			lc->link_down_rc = linkdnrc;
Thomas Bogendoerfer 3237e1
+			dev_warn(adapter->pdev_dev, "Port %d link down, reason: %s\n",
Thomas Bogendoerfer 3237e1
+				 pi->port_id, t4vf_link_down_rc_str(linkdnrc));
Thomas Bogendoerfer 3237e1
+		}
Thomas Bogendoerfer 3237e1
+		lc->link_ok = link_ok;
Thomas Bogendoerfer 3237e1
+		lc->speed = speed;
Thomas Bogendoerfer 3237e1
+		lc->fc = fc;
Thomas Bogendoerfer 3237e1
+		lc->fec = fec;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		lc->pcaps = pcaps;
Thomas Bogendoerfer 3237e1
+		lc->lpacaps = lpacaps;
Thomas Bogendoerfer 3237e1
+		lc->acaps = acaps & ADVERT_MASK;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		if (lc->acaps & FW_PORT_CAP32_ANEG) {
Thomas Bogendoerfer 3237e1
+			lc->autoneg = AUTONEG_ENABLE;
Thomas Bogendoerfer 3237e1
+		} else {
Thomas Bogendoerfer 3237e1
+			/* When Autoneg is disabled, user needs to set
Thomas Bogendoerfer 3237e1
+			 * single speed.
Thomas Bogendoerfer 3237e1
+			 * Similar to cxgb4_ethtool.c: set_link_ksettings
Thomas Bogendoerfer 3237e1
+			 */
Thomas Bogendoerfer 3237e1
+			lc->acaps = 0;
Thomas Bogendoerfer 3237e1
+			lc->speed_caps = fwcap_to_speed(acaps);
Thomas Bogendoerfer 3237e1
+			lc->autoneg = AUTONEG_DISABLE;
Thomas Bogendoerfer 3237e1
+		}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		t4vf_os_link_changed(adapter, pi->pidx, link_ok);
Thomas Bogendoerfer 3237e1
+	}
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
+ *	t4vf_update_port_info - retrieve and update port information if changed
Thomas Bogendoerfer 3237e1
+ *	@pi: the port_info
Thomas Bogendoerfer 3237e1
+ *
Thomas Bogendoerfer 3237e1
+ *	We issue a Get Port Information Command to the Firmware and, if
Thomas Bogendoerfer 3237e1
+ *	successful, we check to see if anything is different from what we
Thomas Bogendoerfer 3237e1
+ *	last recorded and update things accordingly.
Thomas Bogendoerfer 3237e1
+ */
Thomas Bogendoerfer 3237e1
+int t4vf_update_port_info(struct port_info *pi)
Thomas Bogendoerfer 3237e1
+{
Thomas Bogendoerfer 3237e1
+	unsigned int fw_caps = pi->adapter->params.fw_caps_support;
Thomas Bogendoerfer 3237e1
+	struct fw_port_cmd port_cmd;
Thomas Bogendoerfer 3237e1
+	int ret;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+	memset(&port_cmd, 0, sizeof(port_cmd));
Thomas Bogendoerfer 3237e1
+	port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
Thomas Bogendoerfer 3237e1
+					    FW_CMD_REQUEST_F | FW_CMD_READ_F |
Thomas Bogendoerfer 3237e1
+					    FW_PORT_CMD_PORTID_V(pi->port_id));
Thomas Bogendoerfer 3237e1
+	port_cmd.action_to_len16 = cpu_to_be32(
Thomas Bogendoerfer 3237e1
+		FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
Thomas Bogendoerfer 3237e1
+				     ? FW_PORT_ACTION_GET_PORT_INFO
Thomas Bogendoerfer 3237e1
+				     : FW_PORT_ACTION_GET_PORT_INFO32) |
Thomas Bogendoerfer 3237e1
+		FW_LEN16(port_cmd));
Thomas Bogendoerfer 3237e1
+	ret = t4vf_wr_mbox(pi->adapter, &port_cmd, sizeof(port_cmd),
Thomas Bogendoerfer 3237e1
+			   &port_cmd);
Thomas Bogendoerfer 3237e1
+	if (ret)
Thomas Bogendoerfer 3237e1
+		return ret;
Thomas Bogendoerfer 3237e1
+	t4vf_handle_get_port_info(pi, &port_cmd);
Thomas Bogendoerfer 3237e1
+	return 0;
Thomas Bogendoerfer 3237e1
+}
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+/**
Thomas Bogendoerfer 3237e1
  *	t4vf_handle_fw_rpl - process a firmware reply message
Thomas Bogendoerfer 3237e1
  *	@adapter: the adapter
Thomas Bogendoerfer 3237e1
  *	@rpl: start of the firmware message
Thomas Bogendoerfer 3237e1
@@ -1685,15 +2021,12 @@ int t4vf_handle_fw_rpl(struct adapter *a
Thomas Bogendoerfer 3237e1
 		 */
Thomas Bogendoerfer 3237e1
 		const struct fw_port_cmd *port_cmd =
Thomas Bogendoerfer 3237e1
 			(const struct fw_port_cmd *)rpl;
Thomas Bogendoerfer 3237e1
-		u32 stat, mod;
Thomas Bogendoerfer 3237e1
-		int action, port_id, link_ok, speed, fc, pidx;
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-		/*
Thomas Bogendoerfer 3237e1
-		 * Extract various fields from port status change message.
Thomas Bogendoerfer 3237e1
-		 */
Thomas Bogendoerfer 3237e1
-		action = FW_PORT_CMD_ACTION_G(
Thomas Bogendoerfer 3237e1
+		int action = FW_PORT_CMD_ACTION_G(
Thomas Bogendoerfer 3237e1
 			be32_to_cpu(port_cmd->action_to_len16));
Thomas Bogendoerfer 3237e1
-		if (action != FW_PORT_ACTION_GET_PORT_INFO) {
Thomas Bogendoerfer 3237e1
+		int port_id, pidx;
Thomas Bogendoerfer 3237e1
+
Thomas Bogendoerfer 3237e1
+		if (action != FW_PORT_ACTION_GET_PORT_INFO &&
Thomas Bogendoerfer 3237e1
+		    action != FW_PORT_ACTION_GET_PORT_INFO32) {
Thomas Bogendoerfer 3237e1
 			dev_err(adapter->pdev_dev,
Thomas Bogendoerfer 3237e1
 				"Unknown firmware PORT reply action %x\n",
Thomas Bogendoerfer 3237e1
 				action);
Thomas Bogendoerfer 3237e1
@@ -1702,61 +2035,12 @@ int t4vf_handle_fw_rpl(struct adapter *a
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 		port_id = FW_PORT_CMD_PORTID_G(
Thomas Bogendoerfer 3237e1
 			be32_to_cpu(port_cmd->op_to_portid));
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-		stat = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype);
Thomas Bogendoerfer 3237e1
-		link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;
Thomas Bogendoerfer 3237e1
-		speed = 0;
Thomas Bogendoerfer 3237e1
-		fc = 0;
Thomas Bogendoerfer 3237e1
-		if (stat & FW_PORT_CMD_RXPAUSE_F)
Thomas Bogendoerfer 3237e1
-			fc |= PAUSE_RX;
Thomas Bogendoerfer 3237e1
-		if (stat & FW_PORT_CMD_TXPAUSE_F)
Thomas Bogendoerfer 3237e1
-			fc |= PAUSE_TX;
Thomas Bogendoerfer 3237e1
-		if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
Thomas Bogendoerfer 3237e1
-			speed = 100;
Thomas Bogendoerfer 3237e1
-		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
Thomas Bogendoerfer 3237e1
-			speed = 1000;
Thomas Bogendoerfer 3237e1
-		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
Thomas Bogendoerfer 3237e1
-			speed = 10000;
Thomas Bogendoerfer 3237e1
-		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
Thomas Bogendoerfer 3237e1
-			speed = 25000;
Thomas Bogendoerfer 3237e1
-		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
Thomas Bogendoerfer 3237e1
-			speed = 40000;
Thomas Bogendoerfer 3237e1
-		else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
Thomas Bogendoerfer 3237e1
-			speed = 100000;
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-		/*
Thomas Bogendoerfer 3237e1
-		 * Scan all of our "ports" (Virtual Interfaces) looking for
Thomas Bogendoerfer 3237e1
-		 * those bound to the physical port which has changed.  If
Thomas Bogendoerfer 3237e1
-		 * our recorded state doesn't match the current state,
Thomas Bogendoerfer 3237e1
-		 * signal that change to the OS code.
Thomas Bogendoerfer 3237e1
-		 */
Thomas Bogendoerfer 3237e1
 		for_each_port(adapter, pidx) {
Thomas Bogendoerfer 3237e1
 			struct port_info *pi = adap2pinfo(adapter, pidx);
Thomas Bogendoerfer 3237e1
-			struct link_config *lc;
Thomas Bogendoerfer 3237e1
 
Thomas Bogendoerfer 3237e1
 			if (pi->port_id != port_id)
Thomas Bogendoerfer 3237e1
 				continue;
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-			lc = &pi->link_cfg;
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-			mod = FW_PORT_CMD_MODTYPE_G(stat);
Thomas Bogendoerfer 3237e1
-			if (mod != pi->mod_type) {
Thomas Bogendoerfer 3237e1
-				pi->mod_type = mod;
Thomas Bogendoerfer 3237e1
-				t4vf_os_portmod_changed(adapter, pidx);
Thomas Bogendoerfer 3237e1
-			}
Thomas Bogendoerfer 3237e1
-
Thomas Bogendoerfer 3237e1
-			if (link_ok != lc->link_ok || speed != lc->speed ||
Thomas Bogendoerfer 3237e1
-			    fc != lc->fc) {
Thomas Bogendoerfer 3237e1
-				/* something changed */
Thomas Bogendoerfer 3237e1
-				lc->link_ok = link_ok;
Thomas Bogendoerfer 3237e1
-				lc->speed = speed;
Thomas Bogendoerfer 3237e1
-				lc->fc = fc;
Thomas Bogendoerfer 3237e1
-				lc->supported =
Thomas Bogendoerfer 3237e1
-					be16_to_cpu(port_cmd->u.info.pcap);
Thomas Bogendoerfer 3237e1
-				lc->lp_advertising =
Thomas Bogendoerfer 3237e1
-					be16_to_cpu(port_cmd->u.info.lpacap);
Thomas Bogendoerfer 3237e1
-				t4vf_os_link_changed(adapter, pidx, link_ok);
Thomas Bogendoerfer 3237e1
-			}
Thomas Bogendoerfer 3237e1
+			t4vf_handle_get_port_info(pi, port_cmd);
Thomas Bogendoerfer 3237e1
 		}
Thomas Bogendoerfer 3237e1
 		break;
Thomas Bogendoerfer 3237e1
 	}