From nobody Mon Dec 1 23:06:21 2025 Received: from mail-io1-f98.google.com (mail-io1-f98.google.com [209.85.166.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE56830E834 for ; Wed, 26 Nov 2025 19:50:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.98 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764186648; cv=none; b=lLg2Hwz9m6coT5xVvW7heMlLFrlk12VtnPt/hj+oLu1HkAZgHeGmK7gSwkcD6WtvmZk2BNNd8zpDeGq2aXiGV4s3eLjLIwAHS15eH+x9KfOQ6yqsDG/gI27RoGr+Johz7ZlgDFNjsHur2hsk2Xc9S0G6QJ5wRO3XGIhulFekMO0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764186648; c=relaxed/simple; bh=lHX500W4mSSKF2ULG32ABd7aw+ZTvBhjRQtKveb9heE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PLpADy0+BDnf6Y5WvgTTR5lZSLUqEGd1i4CvgUcMqN2drRECmRNd7fJEBeaVL89KlFab4pv5CBmw7MqAOdPaoABGVuEU7yMxLtEM9803qHGNYrXG3A8itdwL+l40VYg0qG6IYM4u8F06sln2c2jenkyZNzOh10/bWBalJgvFhm8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com; spf=fail smtp.mailfrom=broadcom.com; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b=fwZNF85D; arc=none smtp.client-ip=209.85.166.98 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=broadcom.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="fwZNF85D" Received: by mail-io1-f98.google.com with SMTP id ca18e2360f4ac-94905c3e2a4so55498839f.1 for ; Wed, 26 Nov 2025 11:50:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764186645; x=1764791445; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SNTtB9FFKYiyl7JpYMgCteErn1EGaQmPvKyEw6vZfnU=; b=abKLeGxD/z5J20FjllLyKqJnd4HbYGQm/KbrHTaC5bFNKlxqegZfPuIlrsUBmvhAvQ MRtTjm1u6nsjUAWEDK7MH81C12pBj1SpxahRqs7iVr0G+L3TC8WRuMFavEDJPNXUdcH7 PiYGIAa0JVzJ4JXVqM9tRyWiGCXDDYKCP0eBhyX/ub0WaJSlQ3pSvsYdCGZLp1WCoj7s T5BwHC4/lDc7hNNATrKCIXG4WQzmVtbjuspy1f80u2nN0ZRyG/KMPshB4uztbeB7n7Vt tmRMfXZbO4MdVYcsSx9mMme4tMedMSU+qyq8/6X93If0FMYJAihLkH1db2gz5mdfKCZa J+tQ== X-Forwarded-Encrypted: i=1; AJvYcCX4A8X5fJZoN/ukWJkmQfONRla1Qv0bQDI9pxaoNhu/RrZySHKPC1D2orRRulqkT7c2VG03ejG23VM2878=@vger.kernel.org X-Gm-Message-State: AOJu0YxU+t86eNBC0vtlKDUptMkX3pXC1t/fMnQXQ0T5mjrO17ih8i50 /SzEekHRPspZG+PFxjxcQZT5uKe/NclTCh0sst1WZo8r5jWQwm+kqEyTPG+rnOljqAqawtacZdo buYOjOWi0+nZVg5l6tNKupDJrgH+X4vGH8AJeJv7HGc8DB1V35oHLVwQMqsJ0ta97IMXazwOgsG pNt1vUj3XTM0PP9U/0EUelqFJLMQMPvtocvGtCcg9F1Sn3xOzYQ6PID0I5P0xW/EPQVnZ/naBf0 x7zgghLiubHjP7U4zsY7koCf7rV X-Gm-Gg: ASbGnctnHKhyvrVFq5q6bbP9GeD9R/ZmqXb4EHKAgfSceilfslhD3s1HVs0ABuw3DKW aq4OSgPacHWkwPmDLPt55dh+qUnRozE2022wct2lHKyg4w4/WLQMdJWrUgqhFFc1nzxrlEXMCHJ q33Abk7/4HwqHgtRFOEEXwHe+QnkKUh5+qHznXUfz/rS4iUOyB9iKqr7UnJ2uUR1O99hkgHsgQn KqSiVVlyxy5OdoVror3FJ0VU2JEDlvMblX8zCFT/xeYDoA638E1GHoaIs1YMK9EXSP7zFlOZWgA JJMi6HxdZu2MeOriAvzYeWbEby9QZjDAfKy1R+jXBnjCPUwz6O+Wvmzufl1BPnHaIwoaGcxknyz dZsWp0QWe3NNASDzSvJ+E1b+EfCYwF5j+t2dwuyb+b0MS5xHARJoUSpJ1fokjqSLF7y9S9OIxyD RO+pNjqMbSA78CvFXR7/WJ0h0TBm8E07/s7+mhGaL4e09a3EDrNd0= X-Google-Smtp-Source: AGHT+IE7q0hJ3lO2jkuCVs7JWKSy/YFskG9BSs+oqtbLUL4z2c2KtatSENAtVB0PnxKlj4n1wusKuJfgsECN X-Received: by 2002:a02:c8d5:0:b0:5b7:1b3a:b998 with SMTP id 8926c6da1cb9f-5b9567d00dcmr12222856173.5.1764186644712; Wed, 26 Nov 2025 11:50:44 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-11.dlp.protect.broadcom.com. [144.49.247.11]) by smtp-relay.gmail.com with ESMTPS id 8926c6da1cb9f-5b954b16f1bsm1891374173.25.2025.11.26.11.50.44 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 26 Nov 2025 11:50:44 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2955f0b8895so11106565ad.0 for ; Wed, 26 Nov 2025 11:50:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1764186643; x=1764791443; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=SNTtB9FFKYiyl7JpYMgCteErn1EGaQmPvKyEw6vZfnU=; b=fwZNF85DYXKlOoejxeT1qiA3y26vZFw7LDS099G2gQFwOMEd2GSnpARVqp0fkG4cKB lY1J36yqydKLBPk6BomZkJRT8N+rHrSfyev9U7Q0SI7Ic8qd2mFFfOlD6fiBmfbBYNRq ambSEQOwaLom9YTyqnoWnbuwToit9P/l2rixw= X-Forwarded-Encrypted: i=1; AJvYcCXAKB3H9AfAF/OLWUr0eXdRlRGg3ZVPaZzhBO4gQRERLAb0oNLyTAi64iFj9NnyEy20+LxyCah+xIxn9ks=@vger.kernel.org X-Received: by 2002:a17:903:2acd:b0:299:bda7:ae45 with SMTP id d9443c01a7336-29b5e3b884dmr240828535ad.25.1764186642821; Wed, 26 Nov 2025 11:50:42 -0800 (PST) X-Received: by 2002:a17:903:2acd:b0:299:bda7:ae45 with SMTP id d9443c01a7336-29b5e3b884dmr240828255ad.25.1764186642310; Wed, 26 Nov 2025 11:50:42 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-29b5b25e638sm206782375ad.58.2025.11.26.11.50.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Nov 2025 11:50:41 -0800 (PST) From: Bhargava Marreddy To: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, andrew+netdev@lunn.ch, horms@kernel.org Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, michael.chan@broadcom.com, pavan.chebbi@broadcom.com, vsrama-krishna.nemani@broadcom.com, vikas.gupta@broadcom.com, Bhargava Marreddy , Rajashekar Hudumula Subject: [v3, net-next 09/12] bng_en: Add ethtool link settings and capabilities support Date: Thu, 27 Nov 2025 01:19:28 +0530 Message-ID: <20251126194931.455830-10-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20251126194931.455830-1-bhargava.marreddy@broadcom.com> References: <20251126194931.455830-1-bhargava.marreddy@broadcom.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-DetectorID-Processed: b00c1d49-9d2e-4205-b15f-d015386d3d5e Content-Type: text/plain; charset="utf-8" Adds ethtool ops to query and configure link speed, duplex, autoneg, report link status, and advertise lane support. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Rajashekar Hudumula --- drivers/net/ethernet/broadcom/bnge/bnge.h | 2 + .../net/ethernet/broadcom/bnge/bnge_ethtool.c | 25 + .../net/ethernet/broadcom/bnge/bnge_link.c | 838 ++++++++++++++++++ .../net/ethernet/broadcom/bnge/bnge_link.h | 6 + 4 files changed, 871 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethern= et/broadcom/bnge/bnge.h index 68c13520a95..72d9865ba7b 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge.h @@ -224,6 +224,8 @@ struct bnge_dev { #define BNGE_PHY_FL_NO_FCS PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS #define BNGE_PHY_FL_SPEEDS2 \ (PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED << 8) +#define BNGE_PHY_FL_NO_PAUSE \ + (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8) =20 u32 msg_enable; }; diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c b/drivers/ne= t/ethernet/broadcom/bnge/bnge_ethtool.c index 569371c1b4f..b985799051b 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c @@ -11,6 +11,26 @@ =20 #include "bnge.h" #include "bnge_ethtool.h" +#include "bnge_hwrm_lib.h" + +static int bnge_nway_reset(struct net_device *dev) +{ + struct bnge_net *bn =3D netdev_priv(dev); + struct bnge_dev *bd =3D bn->bd; + int rc =3D 0; + + if (!BNGE_PHY_CFG_ABLE(bd)) + return -EOPNOTSUPP; + + if (!(bn->eth_link_info.autoneg & BNGE_AUTONEG_SPEED)) + return -EINVAL; + + if (netif_running(dev)) + rc =3D bnge_hwrm_set_link_setting(bn, true); + + return rc; +} + =20 static void bnge_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -24,7 +44,12 @@ static void bnge_get_drvinfo(struct net_device *dev, } =20 static const struct ethtool_ops bnge_ethtool_ops =3D { + .cap_link_lanes_supported =3D 1, + .get_link_ksettings =3D bnge_get_link_ksettings, + .set_link_ksettings =3D bnge_set_link_ksettings, .get_drvinfo =3D bnge_get_drvinfo, + .get_link =3D bnge_get_link, + .nway_reset =3D bnge_nway_reset, }; =20 void bnge_set_ethtool_ops(struct net_device *dev) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_link.c b/drivers/net/e= thernet/broadcom/bnge/bnge_link.c index 02deb38d81d..6dd741d3461 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_link.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.c @@ -7,6 +7,63 @@ #include "bnge_link.h" #include "bnge_hwrm_lib.h" =20 +enum bnge_media_type { + BNGE_MEDIA_UNKNOWN =3D 0, + BNGE_MEDIA_TP, + BNGE_MEDIA_CR, + BNGE_MEDIA_SR, + BNGE_MEDIA_LR_ER_FR, + BNGE_MEDIA_KR, + BNGE_MEDIA_KX, + BNGE_MEDIA_X, + __BNGE_MEDIA_END, +}; + +static const enum bnge_media_type bnge_phy_types[] =3D { + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASECR] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR4] =3D BNGE_MEDIA_KR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASELR] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASESR] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR2] =3D BNGE_MEDIA_KR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKX] =3D BNGE_MEDIA_KX, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR] =3D BNGE_MEDIA_KR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASET] =3D BNGE_MEDIA_TP, + [PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE] =3D BNGE_MEDIA_TP, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR4] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR4] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR4] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER4] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR10] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR4] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR4] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR4] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASECR] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASESR] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASELR] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASEER] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR2] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4] =3D BNGE_MEDIA_CR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4] =3D BNGE_MEDIA_SR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4] =3D BNGE_MEDIA_LR_ER_FR, + [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4] =3D BNGE_MEDIA_LR_ER_FR, +}; + u32 bnge_fw_to_ethtool_speed(u16 fw_link_speed) { switch (fw_link_speed) { @@ -485,3 +542,784 @@ void bnge_report_link(struct bnge_dev *bd) netdev_err(bd->netdev, "NIC Link is Down\n"); } } + +static void bnge_get_ethtool_modes(struct bnge_net *bn, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnge_ethtool_link_info *elink_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + elink_info =3D &bn->eth_link_info; + link_info =3D &bd->link_info; + + if (!(bd->phy_flags & BNGE_PHY_FL_NO_PAUSE)) { + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, + lk_ksettings->link_modes.supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + lk_ksettings->link_modes.supported); + } + + if (link_info->support_auto_speeds || link_info->support_auto_speeds2 || + link_info->support_pam4_auto_speeds) + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + lk_ksettings->link_modes.supported); + + if (~elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL) + return; + + if (link_info->auto_pause_setting & BNGE_LINK_PAUSE_RX) + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, + lk_ksettings->link_modes.advertising); + if (hweight8(link_info->auto_pause_setting & BNGE_LINK_PAUSE_BOTH) =3D=3D= 1) + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + lk_ksettings->link_modes.advertising); + if (link_info->lp_pause & BNGE_LINK_PAUSE_RX) + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, + lk_ksettings->link_modes.lp_advertising); + if (hweight8(link_info->lp_pause & BNGE_LINK_PAUSE_BOTH) =3D=3D 1) + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + lk_ksettings->link_modes.lp_advertising); +} + +u32 bnge_get_link(struct net_device *dev) +{ + struct bnge_net *bn =3D netdev_priv(dev); + + /* TODO: handle MF, VF, driver close case */ + return BNGE_LINK_IS_UP(bn->bd); +} + +static enum bnge_media_type +bnge_get_media(struct bnge_link_info *link_info) +{ + switch (link_info->media_type) { + case PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP: + return BNGE_MEDIA_TP; + case PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC: + return BNGE_MEDIA_CR; + default: + if (link_info->phy_type < ARRAY_SIZE(bnge_phy_types)) + return bnge_phy_types[link_info->phy_type]; + return BNGE_MEDIA_UNKNOWN; + } +} + +enum bnge_link_speed_indices { + BNGE_LINK_SPEED_UNKNOWN =3D 0, + BNGE_LINK_SPEED_50GB_IDX, + BNGE_LINK_SPEED_100GB_IDX, + BNGE_LINK_SPEED_200GB_IDX, + BNGE_LINK_SPEED_400GB_IDX, + BNGE_LINK_SPEED_800GB_IDX, + __BNGE_LINK_SPEED_END +}; + +static enum bnge_link_speed_indices bnge_fw_speed_idx(u16 speed) +{ + switch (speed) { + case BNGE_LINK_SPEED_50GB: + case BNGE_LINK_SPEED_50GB_PAM4: + return BNGE_LINK_SPEED_50GB_IDX; + case BNGE_LINK_SPEED_100GB: + case BNGE_LINK_SPEED_100GB_PAM4: + case BNGE_LINK_SPEED_100GB_PAM4_112: + return BNGE_LINK_SPEED_100GB_IDX; + case BNGE_LINK_SPEED_200GB: + case BNGE_LINK_SPEED_200GB_PAM4: + case BNGE_LINK_SPEED_200GB_PAM4_112: + return BNGE_LINK_SPEED_200GB_IDX; + case BNGE_LINK_SPEED_400GB: + case BNGE_LINK_SPEED_400GB_PAM4: + case BNGE_LINK_SPEED_400GB_PAM4_112: + return BNGE_LINK_SPEED_400GB_IDX; + case BNGE_LINK_SPEED_800GB: + case BNGE_LINK_SPEED_800GB_PAM4_112: + return BNGE_LINK_SPEED_800GB_IDX; + default: return BNGE_LINK_SPEED_UNKNOWN; + } +} + +static const enum ethtool_link_mode_bit_indices +bnge_link_modes[__BNGE_LINK_SPEED_END][BNGE_SIG_MODE_MAX][__BNGE_MEDIA_END= ] =3D { + [BNGE_LINK_SPEED_50GB_IDX] =3D { + [BNGE_SIG_MODE_PAM4] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, + }, + }, + [BNGE_LINK_SPEED_100GB_IDX] =3D { + [BNGE_SIG_MODE_NRZ] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, + }, + [BNGE_SIG_MODE_PAM4] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_= BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, + }, + [BNGE_SIG_MODE_PAM4_112] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, + }, + }, + [BNGE_LINK_SPEED_200GB_IDX] =3D { + [BNGE_SIG_MODE_PAM4] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_= BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, + }, + [BNGE_SIG_MODE_PAM4_112] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_= BIT, + }, + }, + [BNGE_LINK_SPEED_400GB_IDX] =3D { + [BNGE_SIG_MODE_PAM4] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_= BIT, + }, + [BNGE_SIG_MODE_PAM4_112] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, + [BNGE_MEDIA_LR_ER_FR] =3D ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_= BIT, + }, + }, + [BNGE_LINK_SPEED_800GB_IDX] =3D { + [BNGE_SIG_MODE_PAM4_112] =3D { + [BNGE_MEDIA_CR] =3D ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT, + [BNGE_MEDIA_KR] =3D ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT, + [BNGE_MEDIA_SR] =3D ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT, + }, + }, +}; + +#define BNGE_LINK_MODE_UNKNOWN -1 + +static enum ethtool_link_mode_bit_indices +bnge_get_link_mode(struct bnge_net *bn) +{ + enum ethtool_link_mode_bit_indices link_mode; + struct bnge_ethtool_link_info *elink_info; + enum bnge_link_speed_indices speed; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + enum bnge_media_type media; + u8 sig_mode; + + elink_info =3D &bn->eth_link_info; + link_info =3D &bd->link_info; + + if (link_info->phy_link_status !=3D BNGE_LINK_LINK) + return BNGE_LINK_MODE_UNKNOWN; + + media =3D bnge_get_media(link_info); + if (BNGE_AUTO_MODE(link_info->auto_mode)) { + speed =3D bnge_fw_speed_idx(link_info->link_speed); + sig_mode =3D link_info->active_fec_sig_mode & + PORT_PHY_QCFG_RESP_SIGNAL_MODE_MASK; + } else { + speed =3D bnge_fw_speed_idx(elink_info->req_link_speed); + sig_mode =3D elink_info->req_signal_mode; + } + if (sig_mode >=3D BNGE_SIG_MODE_MAX) + return BNGE_LINK_MODE_UNKNOWN; + + /* Since ETHTOOL_LINK_MODE_10baseT_Half_BIT is defined as 0 and + * not actually supported, the zeroes in this map can be safely + * used to represent unknown link modes. + */ + link_mode =3D bnge_link_modes[speed][sig_mode][media]; + if (!link_mode) + return BNGE_LINK_MODE_UNKNOWN; + + switch (link_mode) { + case ETHTOOL_LINK_MODE_100baseT_Full_BIT: + if (~link_info->duplex & BNGE_LINK_DUPLEX_FULL) + link_mode =3D ETHTOOL_LINK_MODE_100baseT_Half_BIT; + break; + case ETHTOOL_LINK_MODE_1000baseT_Full_BIT: + if (~link_info->duplex & BNGE_LINK_DUPLEX_FULL) + link_mode =3D ETHTOOL_LINK_MODE_1000baseT_Half_BIT; + break; + default: + break; + } + + return link_mode; +} + +static const u16 bnge_nrz_speed_masks[] =3D { + [BNGE_LINK_SPEED_100GB_IDX] =3D BNGE_LINK_SPEED_MSK_100GB, + [__BNGE_LINK_SPEED_END - 1] =3D 0 /* make any legal speed a valid index */ +}; + +static const u16 bnge_pam4_speed_masks[] =3D { + [BNGE_LINK_SPEED_50GB_IDX] =3D BNGE_LINK_PAM4_SPEED_MSK_50GB, + [BNGE_LINK_SPEED_100GB_IDX] =3D BNGE_LINK_PAM4_SPEED_MSK_100GB, + [BNGE_LINK_SPEED_200GB_IDX] =3D BNGE_LINK_PAM4_SPEED_MSK_200GB, + [__BNGE_LINK_SPEED_END - 1] =3D 0 /* make any legal speed a valid index */ +}; + +static const u16 bnge_nrz_speeds2_masks[] =3D { + [BNGE_LINK_SPEED_100GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_100GB, + [__BNGE_LINK_SPEED_END - 1] =3D 0 /* make any legal speed a valid index */ +}; + +static const u16 bnge_pam4_speeds2_masks[] =3D { + [BNGE_LINK_SPEED_50GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_50GB_PAM4, + [BNGE_LINK_SPEED_100GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_100GB_PAM4, + [BNGE_LINK_SPEED_200GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_200GB_PAM4, + [BNGE_LINK_SPEED_400GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_400GB_PAM4, +}; + +static const u16 bnge_pam4_112_speeds2_masks[] =3D { + [BNGE_LINK_SPEED_100GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_100GB_PAM4_112, + [BNGE_LINK_SPEED_200GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_200GB_PAM4_112, + [BNGE_LINK_SPEED_400GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_400GB_PAM4_112, + [BNGE_LINK_SPEED_800GB_IDX] =3D BNGE_LINK_SPEEDS2_MSK_800GB_PAM4_112, +}; + +static enum bnge_link_speed_indices +bnge_encoding_speed_idx(u8 sig_mode, u16 phy_flags, u16 speed_msk) +{ + const u16 *speeds; + int idx, len; + + switch (sig_mode) { + case BNGE_SIG_MODE_NRZ: + if (phy_flags & BNGE_PHY_FL_SPEEDS2) { + speeds =3D bnge_nrz_speeds2_masks; + len =3D ARRAY_SIZE(bnge_nrz_speeds2_masks); + } else { + speeds =3D bnge_nrz_speed_masks; + len =3D ARRAY_SIZE(bnge_nrz_speed_masks); + } + break; + case BNGE_SIG_MODE_PAM4: + if (phy_flags & BNGE_PHY_FL_SPEEDS2) { + speeds =3D bnge_pam4_speeds2_masks; + len =3D ARRAY_SIZE(bnge_pam4_speeds2_masks); + } else { + speeds =3D bnge_pam4_speed_masks; + len =3D ARRAY_SIZE(bnge_pam4_speed_masks); + } + break; + case BNGE_SIG_MODE_PAM4_112: + speeds =3D bnge_pam4_112_speeds2_masks; + len =3D ARRAY_SIZE(bnge_pam4_112_speeds2_masks); + break; + default: + return BNGE_LINK_SPEED_UNKNOWN; + } + + for (idx =3D 0; idx < len; idx++) { + if (speeds[idx] =3D=3D speed_msk) + return idx; + } + + return BNGE_LINK_SPEED_UNKNOWN; +} + +#define BNGE_FW_SPEED_MSK_BITS 16 + +static void +__bnge_get_ethtool_speeds(unsigned long fw_mask, enum bnge_media_type medi= a, + u8 sig_mode, u16 phy_flags, unsigned long *et_mask) +{ + enum ethtool_link_mode_bit_indices link_mode; + enum bnge_link_speed_indices speed; + u8 bit; + + for_each_set_bit(bit, &fw_mask, BNGE_FW_SPEED_MSK_BITS) { + speed =3D bnge_encoding_speed_idx(sig_mode, phy_flags, 1 << bit); + if (!speed) + continue; + + link_mode =3D bnge_link_modes[speed][sig_mode][media]; + if (!link_mode) + continue; + + linkmode_set_bit(link_mode, et_mask); + } +} + +static void +bnge_get_ethtool_speeds(unsigned long fw_mask, enum bnge_media_type media, + u8 sig_mode, u16 phy_flags, unsigned long *et_mask) +{ + if (media) { + __bnge_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags, + et_mask); + return; + } + + /* list speeds for all media if unknown */ + for (media =3D 1; media < __BNGE_MEDIA_END; media++) + __bnge_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags, + et_mask); +} + +static void +bnge_get_all_ethtool_support_speeds(struct bnge_dev *bd, + enum bnge_media_type media, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnge_link_info *link_info =3D &bd->link_info; + u16 sp_nrz, sp_pam4, sp_pam4_112 =3D 0; + u16 phy_flags =3D bd->phy_flags; + + if (phy_flags & BNGE_PHY_FL_SPEEDS2) { + sp_nrz =3D link_info->support_speeds2; + sp_pam4 =3D link_info->support_speeds2; + sp_pam4_112 =3D link_info->support_speeds2; + } else { + sp_nrz =3D link_info->support_speeds; + sp_pam4 =3D link_info->support_pam4_speeds; + } + bnge_get_ethtool_speeds(sp_nrz, media, BNGE_SIG_MODE_NRZ, phy_flags, + lk_ksettings->link_modes.supported); + bnge_get_ethtool_speeds(sp_pam4, media, BNGE_SIG_MODE_PAM4, phy_flags, + lk_ksettings->link_modes.supported); + bnge_get_ethtool_speeds(sp_pam4_112, media, BNGE_SIG_MODE_PAM4_112, + phy_flags, lk_ksettings->link_modes.supported); +} + +static void +bnge_get_all_ethtool_adv_speeds(struct bnge_net *bn, + enum bnge_media_type media, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + u16 sp_nrz, sp_pam4, sp_pam4_112 =3D 0; + struct bnge_dev *bd =3D bn->bd; + u16 phy_flags; + + phy_flags =3D bd->phy_flags; + sp_nrz =3D elink_info->advertising; + + if (phy_flags & BNGE_PHY_FL_SPEEDS2) { + sp_pam4 =3D elink_info->advertising; + sp_pam4_112 =3D elink_info->advertising; + } else { + sp_pam4 =3D elink_info->advertising_pam4; + } + bnge_get_ethtool_speeds(sp_nrz, media, BNGE_SIG_MODE_NRZ, phy_flags, + lk_ksettings->link_modes.advertising); + bnge_get_ethtool_speeds(sp_pam4, media, BNGE_SIG_MODE_PAM4, phy_flags, + lk_ksettings->link_modes.advertising); + bnge_get_ethtool_speeds(sp_pam4_112, media, BNGE_SIG_MODE_PAM4_112, + phy_flags, lk_ksettings->link_modes.advertising); +} + +static void +bnge_get_all_ethtool_lp_speeds(struct bnge_dev *bd, + enum bnge_media_type media, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnge_link_info *link_info =3D &bd->link_info; + u16 phy_flags =3D bd->phy_flags; + + bnge_get_ethtool_speeds(link_info->lp_auto_link_speeds, media, + BNGE_SIG_MODE_NRZ, phy_flags, + lk_ksettings->link_modes.lp_advertising); + bnge_get_ethtool_speeds(link_info->lp_auto_pam4_link_speeds, media, + BNGE_SIG_MODE_PAM4, phy_flags, + lk_ksettings->link_modes.lp_advertising); +} + +static void bnge_update_speed(u32 *delta, bool installed_media, u16 *speed= s, + u16 speed_msk, const unsigned long *et_mask, + enum ethtool_link_mode_bit_indices mode) +{ + bool mode_desired =3D linkmode_test_bit(mode, et_mask); + + if (!mode) + return; + + /* enabled speeds for installed media should override */ + if (installed_media && mode_desired) { + *speeds |=3D speed_msk; + *delta |=3D speed_msk; + return; + } + + /* many to one mapping, only allow one change per fw_speed bit */ + if (!(*delta & speed_msk) && (mode_desired =3D=3D !(*speeds & speed_msk))= ) { + *speeds ^=3D speed_msk; + *delta |=3D speed_msk; + } +} + +static void bnge_set_ethtool_speeds(struct bnge_net *bn, + const unsigned long *et_mask) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + u16 const *sp_msks, *sp_pam4_msks, *sp_pam4_112_msks; + u16 *adv, *adv_pam4, *adv_pam4_112 =3D NULL; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + enum bnge_media_type media; + u32 delta_pam4_112 =3D 0; + u32 delta_pam4 =3D 0; + u32 delta_nrz =3D 0; + int i, m; + + link_info =3D &bd->link_info; + media =3D bnge_get_media(link_info); + adv =3D &elink_info->advertising; + + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) { + adv_pam4 =3D &elink_info->advertising; + adv_pam4_112 =3D &elink_info->advertising; + sp_msks =3D bnge_nrz_speeds2_masks; + sp_pam4_msks =3D bnge_pam4_speeds2_masks; + sp_pam4_112_msks =3D bnge_pam4_112_speeds2_masks; + } else { + adv_pam4 =3D &elink_info->advertising_pam4; + sp_msks =3D bnge_nrz_speed_masks; + sp_pam4_msks =3D bnge_pam4_speed_masks; + } + for (i =3D 1; i < __BNGE_LINK_SPEED_END; i++) { + /* accept any legal media from user */ + for (m =3D 1; m < __BNGE_MEDIA_END; m++) { + bnge_update_speed(&delta_nrz, m =3D=3D media, + adv, sp_msks[i], et_mask, + bnge_link_modes[i][BNGE_SIG_MODE_NRZ][m]); + bnge_update_speed(&delta_pam4, m =3D=3D media, + adv_pam4, sp_pam4_msks[i], et_mask, + bnge_link_modes[i][BNGE_SIG_MODE_PAM4][m]); + if (!adv_pam4_112) + continue; + + bnge_update_speed(&delta_pam4_112, m =3D=3D media, + adv_pam4_112, sp_pam4_112_msks[i], et_mask, + bnge_link_modes[i][BNGE_SIG_MODE_PAM4_112][m]); + } + } +} + +static void +bnge_fw_to_ethtool_advertised_fec(struct bnge_link_info *link_info, + struct ethtool_link_ksettings *lk_ksettings) +{ + u16 fec_cfg =3D link_info->fec_cfg; + + if ((fec_cfg & BNGE_FEC_NONE) || !(fec_cfg & BNGE_FEC_AUTONEG)) { + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, + lk_ksettings->link_modes.advertising); + return; + } + if (fec_cfg & BNGE_FEC_ENC_BASE_R) + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, + lk_ksettings->link_modes.advertising); + if (fec_cfg & BNGE_FEC_ENC_RS) + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, + lk_ksettings->link_modes.advertising); + if (fec_cfg & BNGE_FEC_ENC_LLRS) + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, + lk_ksettings->link_modes.advertising); +} + +static void +bnge_fw_to_ethtool_support_fec(struct bnge_link_info *link_info, + struct ethtool_link_ksettings *lk_ksettings) +{ + u16 fec_cfg =3D link_info->fec_cfg; + + if (fec_cfg & BNGE_FEC_NONE) { + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, + lk_ksettings->link_modes.supported); + return; + } + if (fec_cfg & BNGE_FEC_ENC_BASE_R_CAP) + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, + lk_ksettings->link_modes.supported); + if (fec_cfg & BNGE_FEC_ENC_RS_CAP) + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, + lk_ksettings->link_modes.supported); + if (fec_cfg & BNGE_FEC_ENC_LLRS_CAP) + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, + lk_ksettings->link_modes.supported); +} + +static void bnge_get_default_speeds(struct bnge_net *bn, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct ethtool_link_settings *base =3D &lk_ksettings->base; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + if (link_info->link_state =3D=3D BNGE_LINK_STATE_UP) { + base->speed =3D bnge_fw_to_ethtool_speed(link_info->link_speed); + base->duplex =3D DUPLEX_HALF; + if (link_info->duplex & BNGE_LINK_DUPLEX_FULL) + base->duplex =3D DUPLEX_FULL; + lk_ksettings->lanes =3D link_info->active_lanes; + } else if (!elink_info->autoneg) { + base->speed =3D bnge_fw_to_ethtool_speed(elink_info->req_link_speed); + base->duplex =3D DUPLEX_HALF; + if (elink_info->req_duplex =3D=3D BNGE_LINK_DUPLEX_FULL) + base->duplex =3D DUPLEX_FULL; + } +} + +int bnge_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *lk_ksettings) +{ + struct ethtool_link_settings *base =3D &lk_ksettings->base; + enum ethtool_link_mode_bit_indices link_mode; + struct bnge_net *bn =3D netdev_priv(dev); + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + enum bnge_media_type media; + + ethtool_link_ksettings_zero_link_mode(lk_ksettings, lp_advertising); + ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); + ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); + base->duplex =3D DUPLEX_UNKNOWN; + base->speed =3D SPEED_UNKNOWN; + link_info =3D &bd->link_info; + + mutex_lock(&bd->link_lock); + bnge_get_ethtool_modes(bn, lk_ksettings); + media =3D bnge_get_media(link_info); + bnge_get_all_ethtool_support_speeds(bd, media, lk_ksettings); + bnge_fw_to_ethtool_support_fec(link_info, lk_ksettings); + link_mode =3D bnge_get_link_mode(bn); + if (link_mode !=3D BNGE_LINK_MODE_UNKNOWN) + ethtool_params_from_link_mode(lk_ksettings, link_mode); + else + bnge_get_default_speeds(bn, lk_ksettings); + + if (bn->eth_link_info.autoneg) { + bnge_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + lk_ksettings->link_modes.advertising); + base->autoneg =3D AUTONEG_ENABLE; + bnge_get_all_ethtool_adv_speeds(bn, media, lk_ksettings); + if (link_info->phy_link_status =3D=3D BNGE_LINK_LINK) + bnge_get_all_ethtool_lp_speeds(bd, media, lk_ksettings); + } else { + base->autoneg =3D AUTONEG_DISABLE; + } + + base->port =3D PORT_NONE; + if (link_info->media_type =3D=3D PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { + base->port =3D PORT_TP; + linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, + lk_ksettings->link_modes.supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, + lk_ksettings->link_modes.advertising); + } else { + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + lk_ksettings->link_modes.supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + lk_ksettings->link_modes.advertising); + + if (link_info->media_type =3D=3D PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) + base->port =3D PORT_DA; + else + base->port =3D PORT_FIBRE; + } + base->phy_address =3D link_info->phy_addr; + mutex_unlock(&bd->link_lock); + + return 0; +} + +static int +bnge_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) +{ + u16 support_pam4_spds, support_spds2, support_spds; + struct bnge_ethtool_link_info *elink_info; + struct bnge_net *bn =3D netdev_priv(dev); + struct bnge_link_info *link_info; + u8 sig_mode =3D BNGE_SIG_MODE_NRZ; + struct bnge_dev *bd =3D bn->bd; + u32 lanes_needed =3D 1; + u16 fw_speed =3D 0; + + elink_info =3D &bn->eth_link_info; + link_info =3D &bd->link_info; + support_pam4_spds =3D link_info->support_pam4_speeds; + support_spds2 =3D link_info->support_speeds2; + support_spds =3D link_info->support_speeds; + + switch (ethtool_speed) { + case SPEED_50000: + if (((support_spds & BNGE_LINK_SPEED_MSK_50GB) || + (support_spds2 & BNGE_LINK_SPEEDS2_MSK_50GB)) && + lanes !=3D 1) { + fw_speed =3D PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; + lanes_needed =3D 2; + } else if (support_pam4_spds & BNGE_LINK_PAM4_SPEED_MSK_50GB) { + fw_speed =3D PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; + sig_mode =3D BNGE_SIG_MODE_PAM4; + } else if (support_spds2 & BNGE_LINK_SPEEDS2_MSK_50GB_PAM4) { + fw_speed =3D BNGE_LINK_SPEED_50GB_PAM4; + sig_mode =3D BNGE_SIG_MODE_PAM4; + } + break; + case SPEED_100000: + if (((support_spds & BNGE_LINK_SPEED_MSK_100GB) || + (support_spds2 & BNGE_LINK_SPEEDS2_MSK_100GB)) && + lanes !=3D 2 && lanes !=3D 1) { + fw_speed =3D PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; + lanes_needed =3D 4; + } else if (support_pam4_spds & BNGE_LINK_PAM4_SPEED_MSK_100GB) { + fw_speed =3D PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; + sig_mode =3D BNGE_SIG_MODE_PAM4; + lanes_needed =3D 2; + } else if ((support_spds2 & BNGE_LINK_SPEEDS2_MSK_100GB_PAM4) && + lanes !=3D 1) { + fw_speed =3D BNGE_LINK_SPEED_100GB_PAM4; + sig_mode =3D BNGE_SIG_MODE_PAM4; + lanes_needed =3D 2; + } else if (support_spds2 & BNGE_LINK_SPEEDS2_MSK_100GB_PAM4_112) { + fw_speed =3D BNGE_LINK_SPEED_100GB_PAM4_112; + sig_mode =3D BNGE_SIG_MODE_PAM4_112; + } + break; + case SPEED_200000: + if (support_pam4_spds & BNGE_LINK_PAM4_SPEED_MSK_200GB) { + fw_speed =3D PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; + sig_mode =3D BNGE_SIG_MODE_PAM4; + lanes_needed =3D 4; + } else if ((support_spds2 & BNGE_LINK_SPEEDS2_MSK_200GB_PAM4) && + lanes !=3D 2) { + fw_speed =3D BNGE_LINK_SPEED_200GB_PAM4; + sig_mode =3D BNGE_SIG_MODE_PAM4; + lanes_needed =3D 4; + } else if (support_spds2 & BNGE_LINK_SPEEDS2_MSK_200GB_PAM4_112) { + fw_speed =3D BNGE_LINK_SPEED_200GB_PAM4_112; + sig_mode =3D BNGE_SIG_MODE_PAM4_112; + lanes_needed =3D 2; + } + break; + case SPEED_400000: + if ((support_spds2 & BNGE_LINK_SPEEDS2_MSK_400GB_PAM4) && + lanes !=3D 4) { + fw_speed =3D BNGE_LINK_SPEED_400GB_PAM4; + sig_mode =3D BNGE_SIG_MODE_PAM4; + lanes_needed =3D 8; + } else if (support_spds2 & BNGE_LINK_SPEEDS2_MSK_400GB_PAM4_112) { + fw_speed =3D BNGE_LINK_SPEED_400GB_PAM4_112; + sig_mode =3D BNGE_SIG_MODE_PAM4_112; + lanes_needed =3D 4; + } + break; + case SPEED_800000: + if (support_spds2 & BNGE_LINK_SPEEDS2_MSK_800GB_PAM4_112) { + fw_speed =3D BNGE_LINK_SPEED_800GB_PAM4_112; + sig_mode =3D BNGE_SIG_MODE_PAM4_112; + lanes_needed =3D 8; + } + } + + if (!fw_speed) { + netdev_err(dev, "unsupported speed!\n"); + return -EINVAL; + } + + if (lanes && lanes !=3D lanes_needed) { + netdev_err(dev, "unsupported number of lanes for speed\n"); + return -EINVAL; + } + + if (elink_info->req_link_speed =3D=3D fw_speed && + elink_info->req_signal_mode =3D=3D sig_mode && + elink_info->autoneg =3D=3D 0) + return -EALREADY; + + elink_info->req_link_speed =3D fw_speed; + elink_info->req_signal_mode =3D sig_mode; + elink_info->req_duplex =3D BNGE_LINK_DUPLEX_FULL; + elink_info->autoneg =3D 0; + elink_info->advertising =3D 0; + elink_info->advertising_pam4 =3D 0; + + return 0; +} + +int bnge_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *lk_ksettings) +{ + const struct ethtool_link_settings *base =3D &lk_ksettings->base; + struct bnge_ethtool_link_info *elink_info; + struct bnge_net *bn =3D netdev_priv(dev); + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + bool set_pause =3D false; + u32 speed, lanes =3D 0; + int rc =3D 0; + + elink_info =3D &bn->eth_link_info; + link_info =3D &bd->link_info; + + if (!BNGE_PHY_CFG_ABLE(bd)) + return -EOPNOTSUPP; + + mutex_lock(&bd->link_lock); + if (base->autoneg =3D=3D AUTONEG_ENABLE) { + bnge_set_ethtool_speeds(bn, + lk_ksettings->link_modes.advertising); + elink_info->autoneg |=3D BNGE_AUTONEG_SPEED; + if (!elink_info->advertising && !elink_info->advertising_pam4) { + elink_info->advertising =3D link_info->support_auto_speeds; + elink_info->advertising_pam4 =3D + link_info->support_pam4_auto_speeds; + } + /* any change to autoneg will cause link change, therefore the + * driver should put back the original pause setting in autoneg + */ + if (!(bd->phy_flags & BNGE_PHY_FL_NO_PAUSE)) + set_pause =3D true; + } else { + u8 phy_type =3D link_info->phy_type; + + if (phy_type =3D=3D PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || + phy_type =3D=3D PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || + link_info->media_type =3D=3D PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { + netdev_err(dev, "10GBase-T devices must autoneg\n"); + rc =3D -EINVAL; + goto set_setting_exit; + } + if (base->duplex =3D=3D DUPLEX_HALF) { + netdev_err(dev, "HALF DUPLEX is not supported!\n"); + rc =3D -EINVAL; + goto set_setting_exit; + } + speed =3D base->speed; + lanes =3D lk_ksettings->lanes; + rc =3D bnge_force_link_speed(dev, speed, lanes); + if (rc) { + if (rc =3D=3D -EALREADY) + rc =3D 0; + goto set_setting_exit; + } + } + + if (netif_running(dev)) + rc =3D bnge_hwrm_set_link_setting(bn, set_pause); + +set_setting_exit: + mutex_unlock(&bd->link_lock); + return rc; +} diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_link.h b/drivers/net/e= thernet/broadcom/bnge/bnge_link.h index 65da27c510b..995ca731879 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_link.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.h @@ -182,4 +182,10 @@ void bnge_init_ethtool_link_settings(struct bnge_net *= bn); u32 bnge_fw_to_ethtool_speed(u16 fw_link_speed); int bnge_probe_phy(struct bnge_net *bd, bool fw_dflt); bool bnge_phy_qcaps_no_speed(struct hwrm_port_phy_qcaps_output *resp); +int bnge_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *lk_ksettings); +int bnge_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *lk_ksettings); +u32 bnge_get_link(struct net_device *dev); +u16 bnge_get_force_speed(struct bnge_link_info *link_info); #endif /* _BNGE_LINK_H_ */ --=20 2.47.3