git: c63d67e137f3 - main - if_bnxt: 50G, 100G and 200G PAM4 support

From: Sumit Saxena <ssaxena_at_FreeBSD.org>
Date: Thu, 07 Mar 2024 19:27:17 UTC
The branch main has been updated by ssaxena:

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

commit c63d67e137f353f4bc4d0d56bd793f83204a3e1e
Author:     Chandrakanth Patil <chandrakanth.patil@broadcom.com>
AuthorDate: 2024-03-06 13:21:52 +0000
Commit:     Sumit Saxena <ssaxena@FreeBSD.org>
CommitDate: 2024-03-07 19:16:39 +0000

    if_bnxt: 50G, 100G and 200G PAM4 support
    
    Add support for 50G, 100G and 200G PAM4 support
    
    Reviewed by:            imp
    Approved by:            imp
    Differential revision:  https://reviews.freebsd.org/D42959
---
 sys/dev/bnxt/bnxt.h      |  31 ++++++-
 sys/dev/bnxt/bnxt_hwrm.c |  78 ++++++++++++++++-
 sys/dev/bnxt/bnxt_hwrm.h |   1 +
 sys/dev/bnxt/if_bnxt.c   | 213 +++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 284 insertions(+), 39 deletions(-)

diff --git a/sys/dev/bnxt/bnxt.h b/sys/dev/bnxt/bnxt.h
index 4397e0478a0c..204284d45428 100644
--- a/sys/dev/bnxt/bnxt.h
+++ b/sys/dev/bnxt/bnxt.h
@@ -306,12 +306,33 @@ struct bnxt_link_info {
 #define PHY_VER_LEN		3
 	uint8_t		phy_ver[PHY_VER_LEN];
 	uint8_t		phy_type;
+#define BNXT_PHY_STATE_ENABLED		0
+#define BNXT_PHY_STATE_DISABLED		1
+	uint8_t		phy_state;
+
 	uint16_t	link_speed;
 	uint16_t	support_speeds;
+	uint16_t	support_pam4_speeds;
 	uint16_t	auto_link_speeds;
-	uint16_t	auto_link_speed;
+	uint16_t	auto_pam4_link_speeds;
 	uint16_t	force_link_speed;
+	uint16_t	force_pam4_link_speed;
+	bool		force_pam4_speed_set_by_user;
+
+	uint16_t	advertising;
+	uint16_t	advertising_pam4;
+
 	uint32_t	preemphasis;
+	uint16_t	support_auto_speeds;
+	uint16_t	support_force_speeds;
+	uint16_t	support_pam4_auto_speeds;
+	uint16_t	support_pam4_force_speeds;
+#define BNXT_SIG_MODE_NRZ	HWRM_PORT_PHY_QCFG_OUTPUT_SIGNAL_MODE_NRZ
+#define BNXT_SIG_MODE_PAM4	HWRM_PORT_PHY_QCFG_OUTPUT_SIGNAL_MODE_PAM4
+	uint8_t		req_signal_mode;
+
+	uint8_t		active_fec_sig_mode;
+	uint8_t		sig_mode;
 
 	/* copy of requested setting */
 	uint8_t		autoneg;
@@ -323,6 +344,14 @@ struct bnxt_link_info {
 	struct hwrm_port_phy_qcfg_output    phy_qcfg_resp;
 };
 
+enum bnxt_phy_type {
+	BNXT_MEDIA_CR = 0,
+	BNXT_MEDIA_LR,
+	BNXT_MEDIA_SR,
+	BNXT_MEDIA_KR,
+	BNXT_MEDIA_END
+};
+
 enum bnxt_cp_type {
 	BNXT_DEFAULT,
 	BNXT_TX,
diff --git a/sys/dev/bnxt/bnxt_hwrm.c b/sys/dev/bnxt/bnxt_hwrm.c
index 97574c768235..481d45350488 100644
--- a/sys/dev/bnxt/bnxt_hwrm.c
+++ b/sys/dev/bnxt/bnxt_hwrm.c
@@ -857,6 +857,7 @@ static void
 bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
     struct hwrm_port_phy_cfg_input *req)
 {
+	struct bnxt_link_info *link_info = &softc->link_info;
 	uint8_t autoneg = softc->link_info.autoneg;
 	uint16_t fw_link_speed = softc->link_info.req_link_speed;
 
@@ -869,8 +870,15 @@ bnxt_hwrm_set_link_common(struct bnxt_softc *softc,
 		req->flags |=
 		    htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG);
 	} else {
-		req->force_link_speed = htole16(fw_link_speed);
 		req->flags |= htole32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE);
+
+		if (link_info->force_pam4_speed_set_by_user) {
+			req->force_pam4_link_speed = htole16(fw_link_speed);
+			req->enables |= htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAM4_LINK_SPEED);
+			link_info->force_pam4_speed_set_by_user = false;
+		} else {
+			req->force_link_speed = htole16(fw_link_speed);
+		}
 	}
 
 	/* tell chimp that the setting takes effect immediately */
@@ -2284,7 +2292,7 @@ bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc)
 	else
 		link_info->link_speed = 0;
 	link_info->force_link_speed = le16toh(resp->force_link_speed);
-	link_info->auto_link_speed = le16toh(resp->auto_link_speed);
+	link_info->auto_link_speeds = le16toh(resp->auto_link_speed);
 	link_info->support_speeds = le16toh(resp->support_speeds);
 	link_info->auto_link_speeds = le16toh(resp->auto_link_speed_mask);
 	link_info->preemphasis = le32toh(resp->preemphasis);
@@ -2304,6 +2312,72 @@ bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc)
 	link_info->phy_addr = resp->eee_config_phy_addr &
 	    HWRM_PORT_PHY_QCFG_OUTPUT_PHY_ADDR_MASK;
 	link_info->module_status = resp->module_status;
+	link_info->support_pam4_speeds = le16toh(resp->support_pam4_speeds);
+	link_info->auto_pam4_link_speeds = le16toh(resp->auto_pam4_link_speed_mask);
+	link_info->force_pam4_link_speed = le16toh(resp->force_pam4_link_speed);
+
+	if (softc->hwrm_spec_code >= 0x10504)
+		link_info->active_fec_sig_mode = resp->active_fec_signal_mode;
+
+exit:
+	BNXT_HWRM_UNLOCK(softc);
+	return rc;
+}
+
+static bool
+bnxt_phy_qcaps_no_speed(struct hwrm_port_phy_qcaps_output *resp)
+{
+	if (!resp->supported_speeds_auto_mode &&
+	    !resp->supported_speeds_force_mode &&
+	    !resp->supported_pam4_speeds_auto_mode &&
+	    !resp->supported_pam4_speeds_force_mode)
+		return true;
+
+	return false;
+}
+
+int bnxt_hwrm_phy_qcaps(struct bnxt_softc *softc)
+{
+	struct bnxt_link_info *link_info = &softc->link_info;
+	struct hwrm_port_phy_qcaps_output *resp =
+	    (void *)softc->hwrm_cmd_resp.idi_vaddr;
+	struct hwrm_port_phy_qcaps_input req = {};
+	int rc;
+
+	if (softc->hwrm_spec_code < 0x10201)
+		return 0;
+
+	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_QCAPS);
+
+	BNXT_HWRM_LOCK(softc);
+	rc = _hwrm_send_message(softc, &req, sizeof(req));
+	if (rc)
+		goto exit;
+
+	if (softc->hwrm_spec_code >= 0x10a01) {
+		if (bnxt_phy_qcaps_no_speed(resp)) {
+			link_info->phy_state = BNXT_PHY_STATE_DISABLED;
+			device_printf(softc->dev, "Ethernet link disabled\n");
+		} else if (link_info->phy_state == BNXT_PHY_STATE_DISABLED) {
+			link_info->phy_state = BNXT_PHY_STATE_ENABLED;
+			device_printf(softc->dev, "Ethernet link enabled\n");
+			/* Phy re-enabled, reprobe the speeds */
+			link_info->support_auto_speeds = 0;
+			link_info->support_pam4_auto_speeds = 0;
+		}
+	}
+	if (resp->supported_speeds_auto_mode)
+		link_info->support_auto_speeds =
+			le16toh(resp->supported_speeds_auto_mode);
+	if (resp->supported_speeds_force_mode)
+		link_info->support_force_speeds =
+			le16toh(resp->supported_speeds_force_mode);
+	if (resp->supported_pam4_speeds_auto_mode)
+		link_info->support_pam4_auto_speeds =
+			le16toh(resp->supported_pam4_speeds_auto_mode);
+	if (resp->supported_pam4_speeds_force_mode)
+		link_info->support_pam4_force_speeds =
+			le16toh(resp->supported_pam4_speeds_force_mode);
 
 exit:
 	BNXT_HWRM_UNLOCK(softc);
diff --git a/sys/dev/bnxt/bnxt_hwrm.h b/sys/dev/bnxt/bnxt_hwrm.h
index 6dd015a15d40..930ff424ecb8 100644
--- a/sys/dev/bnxt/bnxt_hwrm.h
+++ b/sys/dev/bnxt/bnxt_hwrm.h
@@ -116,6 +116,7 @@ int bnxt_hwrm_fw_set_time(struct bnxt_softc *softc, uint16_t year,
     uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
     uint16_t millisecond, uint16_t zone);
 int bnxt_hwrm_port_phy_qcfg(struct bnxt_softc *softc);
+int bnxt_hwrm_phy_qcaps(struct bnxt_softc *softc);
 uint16_t bnxt_hwrm_get_wol_fltrs(struct bnxt_softc *softc, uint16_t handle);
 int bnxt_hwrm_alloc_wol_fltr(struct bnxt_softc *softc);
 int bnxt_hwrm_free_wol_fltr(struct bnxt_softc *softc);
diff --git a/sys/dev/bnxt/if_bnxt.c b/sys/dev/bnxt/if_bnxt.c
index f82d32c3ff5b..4abd8b425444 100644
--- a/sys/dev/bnxt/if_bnxt.c
+++ b/sys/dev/bnxt/if_bnxt.c
@@ -2134,6 +2134,9 @@ bnxt_media_change(if_ctx_t ctx)
 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
 		return EINVAL;
 
+	softc->link_info.req_signal_mode =
+			HWRM_PORT_PHY_QCFG_OUTPUT_SIGNAL_MODE_PAM4;
+
 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
 	case IFM_100_T:
 		softc->link_info.autoneg &= ~BNXT_AUTONEG_SPEED;
@@ -2189,10 +2192,22 @@ bnxt_media_change(if_ctx_t ctx)
 		break;
 	case IFM_50G_CR2:
 	case IFM_50G_KR2:
+	case IFM_50G_SR2:
 		softc->link_info.autoneg &= ~BNXT_AUTONEG_SPEED;
 		softc->link_info.req_link_speed =
 		    HWRM_PORT_PHY_CFG_INPUT_FORCE_LINK_SPEED_50GB;
 		break;
+	case IFM_50G_CP:
+	case IFM_50G_LR:
+	case IFM_50G_SR:
+	case IFM_50G_KR_PAM4:
+		softc->link_info.autoneg &= ~BNXT_AUTONEG_SPEED;
+		softc->link_info.req_link_speed =
+		    HWRM_PORT_PHY_CFG_INPUT_FORCE_PAM4_LINK_SPEED_50GB;
+		softc->link_info.req_signal_mode =
+			HWRM_PORT_PHY_QCFG_OUTPUT_SIGNAL_MODE_PAM4;
+		softc->link_info.force_pam4_speed_set_by_user = true;
+		break;
 	case IFM_100G_CR4:
 	case IFM_100G_KR4:
 	case IFM_100G_LR4:
@@ -2201,6 +2216,30 @@ bnxt_media_change(if_ctx_t ctx)
 		softc->link_info.req_link_speed =
 			HWRM_PORT_PHY_CFG_INPUT_FORCE_LINK_SPEED_100GB;
 		break;
+	case IFM_100G_CP2:
+	case IFM_100G_SR2:
+	case IFM_100G_KR_PAM4:
+	case IFM_100G_KR2_PAM4:
+		softc->link_info.autoneg &= ~BNXT_AUTONEG_SPEED;
+		softc->link_info.req_link_speed =
+			HWRM_PORT_PHY_CFG_INPUT_FORCE_PAM4_LINK_SPEED_100GB;
+		softc->link_info.req_signal_mode =
+			HWRM_PORT_PHY_QCFG_OUTPUT_SIGNAL_MODE_PAM4;
+		softc->link_info.force_pam4_speed_set_by_user = true;
+		break;
+	case IFM_200G_SR4:
+	case IFM_200G_FR4:
+	case IFM_200G_LR4:
+	case IFM_200G_DR4:
+	case IFM_200G_CR4_PAM4:
+	case IFM_200G_KR4_PAM4:
+		softc->link_info.autoneg &= ~BNXT_AUTONEG_SPEED;
+		softc->link_info.req_link_speed =
+			HWRM_PORT_PHY_CFG_INPUT_FORCE_PAM4_LINK_SPEED_200GB;
+		softc->link_info.force_pam4_speed_set_by_user = true;
+		softc->link_info.req_signal_mode =
+			HWRM_PORT_PHY_QCFG_OUTPUT_SIGNAL_MODE_PAM4;
+		break;
 	default:
 		device_printf(softc->dev,
 		    "Unsupported media type!  Using auto\n");
@@ -2941,6 +2980,13 @@ bnxt_probe_phy(struct bnxt_softc *softc)
 	struct bnxt_link_info *link_info = &softc->link_info;
 	int rc = 0;
 
+	rc = bnxt_hwrm_phy_qcaps(softc);
+	if (rc) {
+		device_printf(softc->dev,
+			      "Probe phy can't get phy capabilities (rc: %x)\n", rc);
+		return rc;
+	}
+
 	rc = bnxt_update_link(softc, false);
 	if (rc) {
 		device_printf(softc->dev,
@@ -2949,26 +2995,99 @@ bnxt_probe_phy(struct bnxt_softc *softc)
 	}
 
 	bnxt_get_port_module_status(softc);
+
 	/*initialize the ethool setting copy with NVM settings */
 	if (link_info->auto_mode != HWRM_PORT_PHY_QCFG_OUTPUT_AUTO_MODE_NONE)
 		link_info->autoneg |= BNXT_AUTONEG_SPEED;
 
 	link_info->req_duplex = link_info->duplex_setting;
+
+	/* NRZ link speed */
 	if (link_info->autoneg & BNXT_AUTONEG_SPEED)
-		link_info->req_link_speed = link_info->auto_link_speed;
+		link_info->req_link_speed = link_info->auto_link_speeds;
 	else
 		link_info->req_link_speed = link_info->force_link_speed;
+
+	/* PAM4 link speed */
+	if (link_info->auto_pam4_link_speeds)
+		link_info->req_link_speed = link_info->auto_pam4_link_speeds;
+	if (link_info->force_pam4_link_speed)
+		link_info->req_link_speed = link_info->force_pam4_link_speed;
+
 	return (rc);
 }
 
+static void
+add_media(struct bnxt_softc *softc, uint8_t media_type, uint16_t supported,
+	  uint16_t supported_pam4)
+{
+	switch (media_type) {
+		case BNXT_MEDIA_CR:
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_50G, IFM_50G_CP);
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_100G, IFM_100G_CP2);
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_200G, IFM_200G_CR4_PAM4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_CR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_50GB, IFM_50G_CR2);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_CR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_CR);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_CR1);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_CX);
+			break;
+
+		case BNXT_MEDIA_LR:
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_50G, IFM_50G_LR);
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_200G, IFM_200G_LR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_LR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_50GB, IFM_50G_LR2);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_LR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_LR);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_LR);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_LX);
+			break;
+
+		case BNXT_MEDIA_SR:
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_50G, IFM_50G_SR);
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_100G, IFM_100G_SR2);
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_200G, IFM_200G_SR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_SR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_50GB, IFM_50G_SR2);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_SR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_SR);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_SR);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_SX);
+			break;
+
+		case BNXT_MEDIA_KR:
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_50G, IFM_50G_KR_PAM4);
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_100G, IFM_100G_KR2_PAM4);
+			BNXT_IFMEDIA_ADD(supported_pam4, PAM4_SPEEDS_200G, IFM_200G_KR4_PAM4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_KR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_50GB, IFM_50G_KR2);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_50GB, IFM_50G_KR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_KR4);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_KR);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_20GB, IFM_20G_KR2);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_KR);
+			BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_KX);
+			break;
+
+		default:
+			break;
+
+	}
+	return;
+
+}
+
 static void
 bnxt_add_media_types(struct bnxt_softc *softc)
 {
 	struct bnxt_link_info *link_info = &softc->link_info;
-	uint16_t supported;
-	uint8_t phy_type = get_phy_type(softc);
+	uint16_t supported = 0, supported_pam4 = 0;
+	uint8_t phy_type = get_phy_type(softc), media_type;
 
 	supported = link_info->support_speeds;
+	supported_pam4 = link_info->support_pam4_speeds;
 
 	/* Auto is always supported */
 	ifmedia_add(softc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
@@ -2977,55 +3096,44 @@ bnxt_add_media_types(struct bnxt_softc *softc)
 		return;
 
 	switch (phy_type) {
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_200G_BASECR4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASECR4:
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASECR2:
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_50G_BASECR:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASECR4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_L:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_S:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASECR_CA_N:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASECR:
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_CR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_50GB, IFM_50G_CR2);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_CR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_CR);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_CR1);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_CX);
+		media_type = BNXT_MEDIA_CR;
 		break;
 
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_200G_BASELR4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASELR4:
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_50G_BASELR:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASELR4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASELR:
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_LR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_LR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_LR);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_LR);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_LX);
+		media_type = BNXT_MEDIA_LR;
 		break;
 
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_200G_BASESR4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASESR10:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASESR4:
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_50G_BASESR:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASESR4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASESR:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_BASEER4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_100G_BASEER4:
+	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_200G_BASEER4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_25G_BASESR:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_1G_BASESX:
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_SR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_SR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_SR);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_SR);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_SX);
+		media_type = BNXT_MEDIA_SR;
 		break;
 
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR4:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR2:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKR:
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_100GB, IFM_100G_KR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_50GB, IFM_50G_KR2);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_KR4);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_25GB, IFM_25G_KR);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_20GB, IFM_20G_KR2);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_KR);
-		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_KX);
+		media_type = BNXT_MEDIA_KR;
 		break;
 
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_40G_ACTIVE_CABLE:
@@ -3033,11 +3141,11 @@ bnxt_add_media_types(struct bnxt_softc *softc)
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_AOC);
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_XLAUI);
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_40GB, IFM_40G_XLAUI_AC);
-		break;
+		return;
 
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_1G_BASECX:
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GBHD, IFM_1000_CX);
-		break;
+		return;
 
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_1G_BASET:
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASET:
@@ -3047,27 +3155,39 @@ bnxt_add_media_types(struct bnxt_softc *softc)
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_T);
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_100MB, IFM_100_T);
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_10MB, IFM_10_T);
-		break;
+		return;
 
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASEKX:
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_10GB, IFM_10G_KR);
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_2_5GB, IFM_2500_KX);
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_KX);
-		break;
+		return;
 
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_SGMIIEXTPHY:
 		BNXT_IFMEDIA_ADD(supported, SPEEDS_1GB, IFM_1000_SGMII);
-		break;
+		return;
 
 	case HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_UNKNOWN:
 		/* Only Autoneg is supported for TYPE_UNKNOWN */
-		device_printf(softc->dev, "Unknown phy type\n");
-		break;
+		return;
 
         default:
 		/* Only Autoneg is supported for new phy type values */
 		device_printf(softc->dev, "phy type %d not supported by driver\n", phy_type);
-		break;
+		return;
+	}
+
+	/* add_media is invoked twice, once with a firmware speed mask of 0 and a valid
+	 * value for both NRZ and PAM4 sig mode. This ensures accurate display of all
+	 * supported medias and currently configured media in the "ifconfig -m" output
+	 */
+
+	if (link_info->sig_mode == BNXT_SIG_MODE_PAM4) {
+		add_media(softc, media_type, supported, 0);
+		add_media(softc, media_type, 0, supported_pam4);
+	} else {
+		add_media(softc, media_type, 0, supported_pam4);
+		add_media(softc, media_type, supported, 0);
 	}
 
 	return;
@@ -3166,6 +3286,7 @@ bnxt_report_link(struct bnxt_softc *softc)
 {
 	struct bnxt_link_info *link_info = &softc->link_info;
 	const char *duplex = NULL, *flow_ctrl = NULL;
+	const char *signal_mode = "";
 
 	if (link_info->link_up == link_info->last_link_up) {
 		if (!link_info->link_up)
@@ -3190,9 +3311,27 @@ bnxt_report_link(struct bnxt_softc *softc)
 			flow_ctrl = "FC - receive";
 		else
 			flow_ctrl = "FC - none";
+
+		if (softc->link_info.phy_qcfg_resp.option_flags &
+		    HWRM_PORT_PHY_QCFG_OUTPUT_OPTION_FLAGS_SIGNAL_MODE_KNOWN) {
+			uint8_t sig_mode = softc->link_info.active_fec_sig_mode &
+				      HWRM_PORT_PHY_QCFG_OUTPUT_SIGNAL_MODE_MASK;
+			switch (sig_mode) {
+			case BNXT_SIG_MODE_NRZ:
+				signal_mode = "(NRZ) ";
+				break;
+			case BNXT_SIG_MODE_PAM4:
+				signal_mode = "(PAM4) ";
+				break;
+			default:
+				break;
+			}
+		link_info->sig_mode = sig_mode;
+		}
+
 		iflib_link_state_change(softc->ctx, LINK_STATE_UP,
 		    IF_Gbps(100));
-		device_printf(softc->dev, "Link is UP %s, %s - %d Mbps \n", duplex,
+		device_printf(softc->dev, "Link is UP %s %s, %s - %d Mbps \n", duplex, signal_mode,
 		    flow_ctrl, (link_info->link_speed * 100));
 	} else {
 		iflib_link_state_change(softc->ctx, LINK_STATE_DOWN,
@@ -3378,7 +3517,7 @@ bnxt_def_cp_task(void *context)
 	softc->db_ops.bnxt_db_rx_cq(cpr, 1);
 }
 
-static uint8_t
+uint8_t
 get_phy_type(struct bnxt_softc *softc)
 {
 	struct bnxt_link_info *link_info = &softc->link_info;
@@ -3471,6 +3610,8 @@ bnxt_get_baudrate(struct bnxt_link_info *link)
 		return IF_Gbps(100);
 	case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_10MB:
 		return IF_Mbps(10);
+	case HWRM_PORT_PHY_QCFG_OUTPUT_LINK_SPEED_200GB:
+		return IF_Gbps(200);
 	}
 	return IF_Gbps(100);
 }