From nobody Sun Apr 5 18:20:21 2026 Received: from mail-pl1-f225.google.com (mail-pl1-f225.google.com [209.85.214.225]) (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 1E4662F6925 for ; Mon, 23 Feb 2026 16:37:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.225 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864653; cv=none; b=h6EGA1faqa9HZmQ+yDJG1rfm1jOFjswXU78nQjN2YmpnTpZhPBhaq+wOgePqmzUSRbdvgkfSVB5XwGUdl3mr1U2LSspsdGI2lqHo/fcR6uBBmrtOZS9G+WCcYIq1hzI3aohEvd8XYSLEeT/8BPdhW3vi0+G2XuICbX88XZBWBss= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864653; c=relaxed/simple; bh=1PI8WR/QfyYhgdDskRti90NGiPXxK286+GwVSfvHDnU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FqPfgiMV6jH+cxrq0XaXC2Mn1agAEs5DfjbKFFfx9i6M0gBCTCN/QxpUjt7lKDV5Q+avt1OL4EkOmFPXT8rDxVZmV2NHbtXCJ+fAzT4R5+31cvVQmcy+I9Sfxi2Fpc+2LulZVJtvNfyxxIMrgkvMh7zwXU1ID/dBx1nleh1Kc18= 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=LvgS8d72; arc=none smtp.client-ip=209.85.214.225 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="LvgS8d72" Received: by mail-pl1-f225.google.com with SMTP id d9443c01a7336-2a9296b3926so30965365ad.1 for ; Mon, 23 Feb 2026 08:37:31 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771864651; x=1772469451; 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=fuYgrfs/Q0g/vVNofvxW+PM6Q1g2Ph6NmJqvydo7chw=; b=Q+fmsfHxIj0crcr4g2nLULNMeHZjA/NdypX7jl/EFELGigMwvhTCfCcSh61lvPgoyc D31Y+funHrhD+6Wg3yERN28Nw1TdFZw2wIJ/gXonGdZFuJOQB+jdaY6BgASxhJAX2vTz xqhSm8cMLlhfACy5uO6MWyONEkXxzBhwol8b+ULEpx1HChObtMOuvrKw4BW+wHVp/d/Q TfTnODqjsOrO/hhWIgkuFOrUqxZ/qZPz8BFbUq20QDnnXrgbeiBcJlVBdPbSXV7RlWyp wFeDcx7SPkrV7E2LDHoSw7qAroMWW6GJgciq/38Eg5F7Hzqvc0o5feqBBo8rVpN8pZQC frWA== X-Forwarded-Encrypted: i=1; AJvYcCVywGOdCkm35YMXqEP7j++kNFuEY0GvUtarIUO/aWeBEXRoeuxEMaX/V2uYeMsJy+elO4RbZAx0TVwpLl4=@vger.kernel.org X-Gm-Message-State: AOJu0Yz9lIcquqkJ/1cPL3KfG4qR70+mEmMyM/BHtxZyiwBFrY2km2Fv IzYuQAitfD1MVSGgMW7iNdjrEznxFbhg8kevNUYve14UZqsW0oOrnI8JS0BSJiqTZ3NY81cYgBu 5Mno/1eOOjKIjwX29wMOxUY63dc2weELLognGA7yHHY1624Z3CKk7e+NjEgpd+RkS7iQ8qjs1qK rxPQoGQSUMf9SLvtf639iIRYluXOLu0onuXLmb+PA0wQ6Y1UZhRyJCfABn7L/WEhIGp+ZTlJZy8 kDdclse3EOm7BIoobhY7KCkkg== X-Gm-Gg: ATEYQzyk3LzTQ7kpEvkHTSRY4oF83MSWVZKcUzw2SIAnaqz91i7mgrc0rBnjt4NerSY 8TJHoQDpQAKxDPG9ZP0tXlIUUIOvAimQZYl/BRag4xJ5Fz+kNufLqsD5r/l+1RnNeeX6b797u1B eUAVTYf5nM2jVDTsIItNXJ21F3bm++ZG/9v+rmHp/fYEhB6G3mJnR6RcVkYqRWXw8KXuKCyFxSV MI1W2NRitvE1um6S8ZUcqsOgbl/hGP82izvaZ1h0Yy6gHBiZ3d4iPeTX6D6gNFGXs0JOol6zcRN 6Ms+rp1RUn005zXMQozCD4lRtbUS9sBMxd7zhf4ljn0k5BhkNSEYDQqUyNe9bJQIs2Iha8VaDNF K2yv/XrUes6GdRDwMq3/3XS6R1Zh4/YKlYa8LPdZpZ/XQjsvm8+X24Lm9mDqaPLK7MYBFD3FDXu dn0djVFrljy0efCFNOhdfFfLdDVlWublGdLZnCg7iUYOZwyj28H5R8ddusypf0Cva/tQ== X-Received: by 2002:a17:902:ce0e:b0:299:e031:173 with SMTP id d9443c01a7336-2ad744e0f75mr92614655ad.35.1771864651276; Mon, 23 Feb 2026 08:37:31 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-116.dlp.protect.broadcom.com. [144.49.247.116]) by smtp-relay.gmail.com with ESMTPS id d9443c01a7336-2ad74e1893bsm8752285ad.18.2026.02.23.08.37.30 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2026 08:37:31 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-2a92a3f5de9so25208075ad.2 for ; Mon, 23 Feb 2026 08:37:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1771864649; x=1772469449; 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=fuYgrfs/Q0g/vVNofvxW+PM6Q1g2Ph6NmJqvydo7chw=; b=LvgS8d72Vg05ok04ye/+CMCv3Cz2ZcYPaY2z6RvxtitHH7w833/zOeKebq0G59uqoy v4YTO7uVnqHfsS1Le+Vmv5+vosHU7YOYh1bSGnH+FmMcptNTIC2p9U9aILCtzzuE5NEU HUmeFOo0lHGI67tDr8AiI3gBGWPDuJA0iyBvI= X-Forwarded-Encrypted: i=1; AJvYcCVrwaqc+Ks00F8umQieaFGkPeq0Igi96qa/DAO2rfhUdGrnrpjmxUFo7lUv1M3X2YEKpZ+dGbS6/m4JpyY=@vger.kernel.org X-Received: by 2002:a17:903:3d0e:b0:2aa:f0ec:36f3 with SMTP id d9443c01a7336-2ad7457e700mr74915105ad.57.1771864649396; Mon, 23 Feb 2026 08:37:29 -0800 (PST) X-Received: by 2002:a17:903:3d0e:b0:2aa:f0ec:36f3 with SMTP id d9443c01a7336-2ad7457e700mr74914765ad.57.1771864648921; Mon, 23 Feb 2026 08:37:28 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ad74e3445fsm96763825ad.13.2026.02.23.08.37.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 08:37:28 -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 , Ajit Kumar Khaparde Subject: [PATCH net-next 1/7] bng_en: add per-PF workqueue, timer, and slow-path task Date: Mon, 23 Feb 2026 22:06:35 +0530 Message-ID: <20260223163641.755200-2-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260223163641.755200-1-bhargava.marreddy@broadcom.com> References: <20260223163641.755200-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" Add a dedicated single-thread workqueue and a timer for each PF to drive deferred slow-path work such as link event handling and stats collection. An interrupt semaphore guards timer re-entry. The open and close paths now start and drain these resources. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Ajit Kumar Khaparde --- .../net/ethernet/broadcom/bnge/bnge_netdev.c | 88 ++++++++++++++++++- .../net/ethernet/broadcom/bnge/bnge_netdev.h | 19 +++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.c index b8e258842c6..a1bb1f01246 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -101,6 +101,44 @@ static int bnge_alloc_ring_stats(struct bnge_net *bn) return rc; } =20 +static void bnge_timer(struct timer_list *t) +{ + struct bnge_net *bn =3D timer_container_of(bn, t, timer); + struct bnge_dev *bd =3D bn->bd; + + if (!netif_running(bn->netdev) || + !test_bit(BNGE_STATE_OPEN, &bd->state)) + return; + + if (atomic_read(&bn->intr_sem) !=3D 0) + goto bnge_restart_timer; + + /* Periodic work added by later patches */ + +bnge_restart_timer: + mod_timer(&bn->timer, jiffies + bn->current_interval); +} + +static void bnge_sp_task(struct work_struct *work) +{ + struct bnge_net *bn =3D container_of(work, struct bnge_net, sp_task); + struct bnge_dev *bd =3D bn->bd; + + set_bit(BNGE_STATE_IN_SP_TASK, &bn->state); + /* Ensure sp_task state is visible before checking BNGE_STATE_OPEN */ + smp_mb__after_atomic(); + if (!test_bit(BNGE_STATE_OPEN, &bd->state)) { + clear_bit(BNGE_STATE_IN_SP_TASK, &bn->state); + return; + } + + /* Event handling work added by later patches */ + + /* Ensure all sp_task work is done before clearing the state */ + smp_mb__before_atomic(); + clear_bit(BNGE_STATE_IN_SP_TASK, &bn->state); +} + static void bnge_free_nq_desc_arr(struct bnge_nq_ring_info *nqr) { struct bnge_ring_struct *ring =3D &nqr->ring_struct; @@ -1960,6 +1998,7 @@ static void bnge_disable_int_sync(struct bnge_net *bn) struct bnge_dev *bd =3D bn->bd; int i; =20 + atomic_inc(&bn->intr_sem); bnge_disable_int(bn); for (i =3D 0; i < bd->nq_nr_rings; i++) { int map_idx =3D bnge_cp_num_to_irq_num(bn, i); @@ -1973,6 +2012,7 @@ static void bnge_enable_int(struct bnge_net *bn) struct bnge_dev *bd =3D bn->bd; int i; =20 + atomic_set(&bn->intr_sem, 0); for (i =3D 0; i < bd->nq_nr_rings; i++) { struct bnge_napi *bnapi =3D bn->bnapi[i]; struct bnge_nq_ring_info *nqr; @@ -2517,6 +2557,9 @@ static int bnge_open_core(struct bnge_net *bn) bnge_enable_int(bn); =20 bnge_tx_enable(bn); + + mod_timer(&bn->timer, jiffies + bn->current_interval); + return 0; =20 err_free_irq: @@ -2552,8 +2595,14 @@ static void bnge_close_core(struct bnge_net *bn) bnge_tx_disable(bn); =20 clear_bit(BNGE_STATE_OPEN, &bd->state); + /* Ensure BNGE_STATE_OPEN is cleared before checking drv_busy */ + smp_mb__after_atomic(); + while (bnge_drv_busy(bn)) + msleep(20); + bnge_shutdown_nic(bn); bnge_disable_napi(bn); + timer_delete_sync(&bn->timer); bnge_free_all_rings_bufs(bn); bnge_free_irq(bn); bnge_del_napi(bn); @@ -2700,6 +2749,23 @@ static void bnge_init_ring_params(struct bnge_net *b= n) bn->netdev->cfg->hds_thresh =3D max(BNGE_DEFAULT_RX_COPYBREAK, rx_size); } =20 +static struct workqueue_struct * +bnge_create_workqueue_thread(struct bnge_dev *bd, const char *thread_name) +{ + struct workqueue_struct *wq; + char *wq_name; + + wq_name =3D kasprintf(GFP_KERNEL, "%s-%s", thread_name, + dev_name(bd->dev)); + if (!wq_name) + return NULL; + + wq =3D create_singlethread_workqueue(wq_name); + kfree(wq_name); + + return wq; +} + int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs) { struct net_device *netdev; @@ -2784,6 +2850,17 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_i= rqs) if (bd->tso_max_segs) netif_set_tso_max_segs(netdev, bd->tso_max_segs); =20 + INIT_WORK(&bn->sp_task, bnge_sp_task); + timer_setup(&bn->timer, bnge_timer, 0); + bn->current_interval =3D BNGE_TIMER_INTERVAL; + + bn->bnge_pf_wq =3D bnge_create_workqueue_thread(bd, "bnge_pf_wq"); + if (!bn->bnge_pf_wq) { + netdev_err(netdev, "Unable to create workqueue.\n"); + rc =3D -ENOMEM; + goto err_netdev; + } + bn->rx_ring_size =3D BNGE_DEFAULT_RX_RING_SIZE; bn->tx_ring_size =3D BNGE_DEFAULT_TX_RING_SIZE; bn->rx_dir =3D DMA_FROM_DEVICE; @@ -2799,11 +2876,13 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_= irqs) rc =3D register_netdev(netdev); if (rc) { dev_err(bd->dev, "Register netdev failed rc: %d\n", rc); - goto err_netdev; + goto err_free_workq; } =20 return 0; =20 +err_free_workq: + destroy_workqueue(bn->bnge_pf_wq); err_netdev: free_netdev(netdev); return rc; @@ -2812,8 +2891,15 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_i= rqs) void bnge_netdev_free(struct bnge_dev *bd) { struct net_device *netdev =3D bd->netdev; + struct bnge_net *bn; + + bn =3D netdev_priv(netdev); =20 unregister_netdev(netdev); + + cancel_work_sync(&bn->sp_task); + destroy_workqueue(bn->bnge_pf_wq); + free_netdev(netdev); bd->netdev =3D NULL; } diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.h index 70f1a7c2481..f7446b7c4ba 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -224,6 +224,13 @@ struct bnge_tpa_info { #define BNGE_NQ_HDL_TYPE(hdl) (((hdl) & BNGE_NQ_HDL_TYPE_MASK) >> \ BNGE_NQ_HDL_TYPE_SHIFT) =20 +enum bnge_net_state { + BNGE_STATE_NAPI_DISABLED, + BNGE_STATE_IN_SP_TASK, +}; + +#define BNGE_TIMER_INTERVAL HZ + struct bnge_net { struct bnge_dev *bd; struct net_device *netdev; @@ -281,13 +288,18 @@ struct bnge_net { u32 stats_coal_ticks; =20 unsigned long state; -#define BNGE_STATE_NAPI_DISABLED 0 =20 u32 msg_enable; u16 max_tpa; __be16 vxlan_port; __be16 nge_port; __be16 vxlan_gpe_port; + + atomic_t intr_sem; + unsigned int current_interval; + struct timer_list timer; + struct workqueue_struct *bnge_pf_wq; + struct work_struct sp_task; }; =20 #define BNGE_DEFAULT_RX_RING_SIZE 511 @@ -556,6 +568,11 @@ struct bnge_l2_filter { refcount_t refcnt; }; =20 +static inline bool bnge_drv_busy(struct bnge_net *bn) +{ + return test_bit(BNGE_STATE_IN_SP_TASK, &bn->state); +} + u16 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr); u16 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr); void bnge_fill_hw_rss_tbl(struct bnge_net *bn, struct bnge_vnic_info *vnic= ); --=20 2.47.3 From nobody Sun Apr 5 18:20:21 2026 Received: from mail-qt1-f225.google.com (mail-qt1-f225.google.com [209.85.160.225]) (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 AD62D316184 for ; Mon, 23 Feb 2026 16:37:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.225 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864660; cv=none; b=l2srenJimQlNHy1ao16GHaRPTOTGyz0dfaOWVNruLUbeB9EypT2aA/tbF1R9RTDCLnTLuATb/MYG7oqiBWM14/PID556f2ucvdCm4u5fpxR4mZdentKOKHwSEQ7FwX21fJdi3zEMKc/uishLeKWlV18Tj0H2YHul58qKlxL1/C8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864660; c=relaxed/simple; bh=wQGVCwa0RP7dK5Rd5zZUwJ7zRY7LJrr9Tp4c9C70mPE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lKmU24WOCnHw7sXeDApHdmuXEZaEHErkVdaLjg2vAajc0HD7wvPneMNmX3exnYjXMiahxgtkoot1GkGYC70dr9K+Zwnbf/Nka+R205K1fQAySZ1p1VxRleAqkRMknsxzxgZtbaM1gWCDla2WHpdkhW/eYP8Q4YKO4yrxHQlQYOw= 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=ceDsZFcq; arc=none smtp.client-ip=209.85.160.225 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="ceDsZFcq" Received: by mail-qt1-f225.google.com with SMTP id d75a77b69052e-506a747448dso37759551cf.0 for ; Mon, 23 Feb 2026 08:37:37 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771864657; x=1772469457; 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=b2WgL0XTnKHGEog/Fy8xzGNYfzRcEZ1aS+qMu0BxhsM=; b=JyKKnnXpofAjWoczx+18+JVefupczp4ZuqDZv0Q7a7JzqR54f+RP/rn/Wy15rPxL9r tt2QJzqxGKw8Z5UCO6Ne3+nsmUGun17j4ZSq7s94Sb6GT0vfIMHv7qWqxnFpt293DxoK AB2k4lpHaRZ5Aw9XGKzPoC5k0vGiEV4NIonP3JbQeIn1vKfVU+B3J/qDIOxVG6L5/4fA S6pisZdKrkez33MymODyrZSi2a/pZ3T4AB77st7XVwAHxP1xX9JRRFwBSWoi5ZWA5Jbz LgqX3gkzIC1Nyie4I/iLO+CarepYC6Fab/D+a8hRNSAnqOMEiEUeai2ikTWCdDSdEMkb eqUQ== X-Forwarded-Encrypted: i=1; AJvYcCUhDGwndQWIdKoKL6DajRnA2Nvase+9ESebK6pnKBKJU/1VPYp5jl8FLaTXJVg1ObbsYTuA6JGOY7RMidY=@vger.kernel.org X-Gm-Message-State: AOJu0YzI0nrthcjNmmcr5CM1KQYMSBpviCN868QVSdHDAUT5V7heQMKa EmwsOQ4JsZ16orzw7TFmxiR5racX76WFkk4QMjfGpDZRGHrGohQJg4dhx48pXHK/KyeuPLCp0rU NRw9pJFb4C9iK61xZNZxhODJ2p/U6WoUYcsh4dkgaE8JWetPRCCwPUl/DCwC6UA11tfscpiBvGv 9gkfywFcQksMh4x3aDMpPvnAR86v8FpZeXMeJq8taPpMh3Pg3V1rNvd8aO+HGaua0+/KqXR35/w h7PF3SstKQYyZt2RnXRP3ufig== X-Gm-Gg: AZuq6aLvp93yuNvVeWiEZ3J24OOShpKd+accAU/4DsBocTYGO7XZDsIsf3Km7CQdQQ8 Yjt9nkLYIcwdNVisBenWLUaZEDr9jYYhE1Us6U3HeMiFnIA9cAFSVNmMJCrZNU4jvfjEuxP/uuW CT7u/2NBiFgIM5LFhYDZAzFKyUCy8S5J6htE1diU15lC+pObt1A7JiwWSH+VF4pFNBRSIVC0ReY V1Hwnv64a74vcPHRDczTeiuc4E+uogid2NzaeYQmGTq5WqAkuFxRKBO9WZM1YlMb2PFug8rRoKB 41MSahHPRwsnpvDCUq2Kxc9+60kh13eH30rH+d7SVheKU/+AgGxibhZygk8I364nlbLbWlPfR0H +7ioi/ccIQzgwCgfCxbiM4lV3M5ZggRW94cnoufi2N9I9N1TIcdf235QuBIfX8DU06ZJZ8rQWte gd+d9xGuC37obyv5yAaqB13Xs2MYPrfMNyFr8hE/s0ZU+qmDu92IFmd/ggJ1FhCyuSNg== X-Received: by 2002:ac8:7c55:0:b0:501:3b8c:7d72 with SMTP id d75a77b69052e-5070bbdb9e4mr129315491cf.27.1771864656414; Mon, 23 Feb 2026 08:37:36 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-117.dlp.protect.broadcom.com. [144.49.247.117]) by smtp-relay.gmail.com with ESMTPS id 6a1803df08f44-8997e752e62sm9476546d6.30.2026.02.23.08.37.35 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2026 08:37:36 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2a863be8508so48987385ad.2 for ; Mon, 23 Feb 2026 08:37:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1771864655; x=1772469455; 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=b2WgL0XTnKHGEog/Fy8xzGNYfzRcEZ1aS+qMu0BxhsM=; b=ceDsZFcqk/KcEahUs8wlaWvV0/yGIRZoOnz7W319wVE51VY8Y5j/8FR9Xi0N4PE1Qt 1yUG2mP4xCG0LYgkvoFK7uWrokPs7xyCdCZk0NsbgJQJIe4C6C5xjk1yVH2ZVWqhPDAM 5gjukLo/47CvoN5oEEbDHNSlS9u3dsfFCc9GY= X-Forwarded-Encrypted: i=1; AJvYcCUf5H61hX+S7ly4xaaaD9Uyv7GmfAsiEUqtvzkL7Yjnhi/cVbzrhLVRgDY0OARP5c/t4Vr8yHqAeDl0Aww=@vger.kernel.org X-Received: by 2002:a17:902:fc48:b0:2a0:c1e4:e25 with SMTP id d9443c01a7336-2ad74582c6dmr76083765ad.54.1771864654529; Mon, 23 Feb 2026 08:37:34 -0800 (PST) X-Received: by 2002:a17:902:fc48:b0:2a0:c1e4:e25 with SMTP id d9443c01a7336-2ad74582c6dmr76083455ad.54.1771864653870; Mon, 23 Feb 2026 08:37:33 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ad74e3445fsm96763825ad.13.2026.02.23.08.37.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 08:37:33 -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 , Ajit Kumar Khaparde Subject: [PATCH net-next 2/7] bng_en: query PHY capabilities and report link status Date: Mon, 23 Feb 2026 22:06:36 +0530 Message-ID: <20260223163641.755200-3-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260223163641.755200-1-bhargava.marreddy@broadcom.com> References: <20260223163641.755200-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" Query PHY capabilities and supported speeds from firmware, retrieve current link state (speed, duplex, pause, FEC), and log the information. Seed initial link state during probe. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Rajashekar Hudumula Reviewed-by: Ajit Kumar Khaparde --- drivers/net/ethernet/broadcom/bnge/Makefile | 3 +- drivers/net/ethernet/broadcom/bnge/bnge.h | 14 + .../net/ethernet/broadcom/bnge/bnge_core.c | 4 + .../ethernet/broadcom/bnge/bnge_hwrm_lib.c | 225 +++++++++ .../ethernet/broadcom/bnge/bnge_hwrm_lib.h | 5 + .../net/ethernet/broadcom/bnge/bnge_link.c | 463 ++++++++++++++++++ .../net/ethernet/broadcom/bnge/bnge_link.h | 193 ++++++++ .../net/ethernet/broadcom/bnge/bnge_netdev.c | 56 ++- .../net/ethernet/broadcom/bnge/bnge_netdev.h | 12 + 9 files changed, 972 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/broadcom/bnge/bnge_link.c create mode 100644 drivers/net/ethernet/broadcom/bnge/bnge_link.h diff --git a/drivers/net/ethernet/broadcom/bnge/Makefile b/drivers/net/ethe= rnet/broadcom/bnge/Makefile index fa604ee2026..8e07cb307d2 100644 --- a/drivers/net/ethernet/broadcom/bnge/Makefile +++ b/drivers/net/ethernet/broadcom/bnge/Makefile @@ -11,4 +11,5 @@ bng_en-y :=3D bnge_core.o \ bnge_netdev.o \ bnge_ethtool.o \ bnge_auxr.o \ - bnge_txrx.o + bnge_txrx.o \ + bnge_link.o diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethern= et/broadcom/bnge/bnge.h index f376913aa32..dabf559c754 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge.h @@ -94,6 +94,11 @@ struct bnge_queue_info { u8 queue_profile; }; =20 +#define BNGE_PHY_FLAGS2_SHIFT 8 +#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) + struct bnge_dev { struct device *dev; struct pci_dev *pdev; @@ -207,6 +212,15 @@ struct bnge_dev { =20 struct bnge_auxr_priv *aux_priv; struct bnge_auxr_dev *auxr_dev; + + /* To protect link related settings during link changes and + * ethtool settings changes. + */ + struct mutex link_lock; + struct bnge_link_info link_info; + + /* Copied from flags and flags2 in hwrm_port_phy_qcaps_output */ + u32 phy_flags; }; =20 static inline bool bnge_is_roce_en(struct bnge_dev *bd) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/e= thernet/broadcom/bnge/bnge_core.c index b4090283df0..2d063b6cf49 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c @@ -282,6 +282,8 @@ static int bnge_probe_one(struct pci_dev *pdev, const s= truct pci_device_id *ent) goto err_devl_free; } =20 + mutex_init(&bd->link_lock); + rc =3D bnge_init_hwrm_resources(bd); if (rc) goto err_bar_unmap; @@ -352,6 +354,7 @@ static int bnge_probe_one(struct pci_dev *pdev, const s= truct pci_device_id *ent) bnge_cleanup_hwrm_resources(bd); =20 err_bar_unmap: + mutex_destroy(&bd->link_lock); bnge_unmap_bars(pdev); =20 err_devl_free: @@ -382,6 +385,7 @@ static void bnge_remove_one(struct pci_dev *pdev) =20 bnge_cleanup_hwrm_resources(bd); =20 + mutex_destroy(&bd->link_lock); bnge_unmap_bars(pdev); =20 bnge_devlink_free(bd); diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c b/drivers/n= et/ethernet/broadcom/bnge/bnge_hwrm_lib.c index 91a4ef9e315..3e6a5bd45a0 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c @@ -981,6 +981,231 @@ void bnge_hwrm_vnic_ctx_free_one(struct bnge_dev *bd, vnic->fw_rss_cos_lb_ctx[ctx_idx] =3D INVALID_HW_RING_ID; } =20 +static bool bnge_phy_qcaps_no_speed(struct hwrm_port_phy_qcaps_output *res= p) +{ + if (!resp->supported_speeds_auto_mode && + !resp->supported_speeds_force_mode && + !resp->supported_pam4_speeds_auto_mode && + !resp->supported_pam4_speeds_force_mode && + !resp->supported_speeds2_auto_mode && + !resp->supported_speeds2_force_mode) + return true; + return false; +} + +int bnge_hwrm_phy_qcaps(struct bnge_dev *bd) +{ + struct bnge_link_info *link_info =3D &bd->link_info; + struct hwrm_port_phy_qcaps_output *resp; + struct hwrm_port_phy_qcaps_input *req; + int rc; + + rc =3D bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_QCAPS); + if (rc) + return rc; + + resp =3D bnge_hwrm_req_hold(bd, req); + rc =3D bnge_hwrm_req_send(bd, req); + if (rc) + goto hwrm_phy_qcaps_exit; + + bd->phy_flags =3D resp->flags | + (le16_to_cpu(resp->flags2) << BNGE_PHY_FLAGS2_SHIFT); + + if (bnge_phy_qcaps_no_speed(resp)) { + link_info->phy_enabled =3D false; + netdev_warn(bd->netdev, "Ethernet link disabled\n"); + } else if (!link_info->phy_enabled) { + link_info->phy_enabled =3D true; + netdev_info(bd->netdev, "Ethernet link enabled\n"); + /* Phy re-enabled, reprobe the speeds */ + link_info->support_auto_speeds =3D 0; + link_info->support_pam4_auto_speeds =3D 0; + link_info->support_auto_speeds2 =3D 0; + } + + if (resp->supported_speeds_auto_mode) + link_info->support_auto_speeds =3D + le16_to_cpu(resp->supported_speeds_auto_mode); + if (resp->supported_pam4_speeds_auto_mode) + link_info->support_pam4_auto_speeds =3D + le16_to_cpu(resp->supported_pam4_speeds_auto_mode); + if (resp->supported_speeds2_auto_mode) + link_info->support_auto_speeds2 =3D + le16_to_cpu(resp->supported_speeds2_auto_mode); + + bd->port_count =3D resp->port_cnt; + +hwrm_phy_qcaps_exit: + bnge_hwrm_req_drop(bd, req); + return rc; +} + +int bnge_hwrm_set_link_setting(struct bnge_net *bn, bool set_pause) +{ + struct hwrm_port_phy_cfg_input *req; + struct bnge_dev *bd =3D bn->bd; + int rc; + + rc =3D bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_CFG); + if (rc) + return rc; + + if (set_pause) + bnge_hwrm_set_pause_common(bn, req); + + bnge_hwrm_set_link_common(bn, req); + + return bnge_hwrm_req_send(bd, req); +} + +int bnge_update_link(struct bnge_net *bn, bool chng_link_state) +{ + struct hwrm_port_phy_qcfg_output *resp; + struct hwrm_port_phy_qcfg_input *req; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + bool support_changed; + u8 link_state; + int rc; + + link_info =3D &bd->link_info; + link_state =3D link_info->link_state; + + rc =3D bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_QCFG); + if (rc) + return rc; + + resp =3D bnge_hwrm_req_hold(bd, req); + rc =3D bnge_hwrm_req_send(bd, req); + if (rc) { + bnge_hwrm_req_drop(bd, req); + return rc; + } + + memcpy(&link_info->phy_qcfg_resp, resp, sizeof(*resp)); + link_info->phy_link_status =3D resp->link; + link_info->duplex =3D resp->duplex_state; + link_info->pause =3D resp->pause; + link_info->auto_mode =3D resp->auto_mode; + link_info->auto_pause_setting =3D resp->auto_pause; + link_info->lp_pause =3D resp->link_partner_adv_pause; + link_info->force_pause_setting =3D resp->force_pause; + link_info->duplex_setting =3D resp->duplex_cfg; + if (link_info->phy_link_status =3D=3D BNGE_LINK_LINK) { + link_info->link_speed =3D le16_to_cpu(resp->link_speed); + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) + link_info->active_lanes =3D resp->active_lanes; + } else { + link_info->link_speed =3D 0; + link_info->active_lanes =3D 0; + } + link_info->force_link_speed =3D le16_to_cpu(resp->force_link_speed); + link_info->force_pam4_link_speed =3D + le16_to_cpu(resp->force_pam4_link_speed); + link_info->force_link_speed2 =3D le16_to_cpu(resp->force_link_speeds2); + link_info->support_speeds =3D le16_to_cpu(resp->support_speeds); + link_info->support_pam4_speeds =3D le16_to_cpu(resp->support_pam4_speeds); + link_info->support_speeds2 =3D le16_to_cpu(resp->support_speeds2); + link_info->auto_link_speeds =3D le16_to_cpu(resp->auto_link_speed_mask); + link_info->auto_pam4_link_speeds =3D + le16_to_cpu(resp->auto_pam4_link_speed_mask); + link_info->auto_link_speeds2 =3D le16_to_cpu(resp->auto_link_speeds2); + link_info->lp_auto_link_speeds =3D + le16_to_cpu(resp->link_partner_adv_speeds); + link_info->lp_auto_pam4_link_speeds =3D + resp->link_partner_pam4_adv_speeds; + link_info->media_type =3D resp->media_type; + link_info->phy_type =3D resp->phy_type; + link_info->phy_addr =3D resp->eee_config_phy_addr & + PORT_PHY_QCFG_RESP_PHY_ADDR_MASK; + link_info->module_status =3D resp->module_status; + + link_info->fec_cfg =3D le16_to_cpu(resp->fec_cfg); + link_info->active_fec_sig_mode =3D resp->active_fec_signal_mode; + + if (chng_link_state) { + if (link_info->phy_link_status =3D=3D BNGE_LINK_LINK) + link_info->link_state =3D BNGE_LINK_STATE_UP; + else + link_info->link_state =3D BNGE_LINK_STATE_DOWN; + if (link_state !=3D link_info->link_state) + bnge_report_link(bd); + } else { + /* always link down if not required to update link state */ + link_info->link_state =3D BNGE_LINK_STATE_DOWN; + } + bnge_hwrm_req_drop(bd, req); + + if (!BNGE_PHY_CFG_ABLE(bd)) + return 0; + + support_changed =3D bnge_support_speed_dropped(bn); + if (support_changed && (bn->eth_link_info.autoneg & BNGE_AUTONEG_SPEED)) + rc =3D bnge_hwrm_set_link_setting(bn, true); + return rc; +} + +int bnge_hwrm_set_pause(struct bnge_net *bn) +{ + struct hwrm_port_phy_cfg_input *req; + struct bnge_dev *bd =3D bn->bd; + int rc; + + rc =3D bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_CFG); + if (rc) + return rc; + + bnge_hwrm_set_pause_common(bn, req); + + if ((bn->eth_link_info.autoneg & BNGE_AUTONEG_FLOW_CTRL) || + bn->eth_link_info.force_link_chng) + bnge_hwrm_set_link_common(bn, req); + + rc =3D bnge_hwrm_req_send(bd, req); + if (!rc && !(bn->eth_link_info.autoneg & BNGE_AUTONEG_FLOW_CTRL)) { + /* Since changing of pause setting doesn't trigger any link + * change event, the driver needs to update the current pause + * result upon successful return of the phy_cfg command + */ + bd->link_info.force_pause_setting =3D + bd->link_info.pause =3D bn->eth_link_info.req_flow_ctrl; + bd->link_info.auto_pause_setting =3D 0; + if (!bn->eth_link_info.force_link_chng) + bnge_report_link(bd); + } + bn->eth_link_info.force_link_chng =3D false; + + return rc; +} + +int bnge_hwrm_shutdown_link(struct bnge_dev *bd) +{ + struct hwrm_port_phy_cfg_input *req; + int rc; + + if (!BNGE_PHY_CFG_ABLE(bd)) + return 0; + + rc =3D bnge_hwrm_req_init(bd, req, HWRM_PORT_PHY_CFG); + if (rc) + return rc; + + req->flags =3D cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE_LINK_DWN); + rc =3D bnge_hwrm_req_send(bd, req); + if (!rc) { + mutex_lock(&bd->link_lock); + /* Device is not obliged to link down in certain scenarios, + * even when forced. Setting the state unknown is consistent + * with driver startup and will force link state to be + * reported during subsequent open based on PORT_PHY_QCFG. + */ + bd->link_info.link_state =3D BNGE_LINK_STATE_UNKNOWN; + mutex_unlock(&bd->link_lock); + } + return rc; +} + void bnge_hwrm_stat_ctx_free(struct bnge_net *bn) { struct hwrm_stat_ctx_free_input *req; diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h b/drivers/n= et/ethernet/broadcom/bnge/bnge_hwrm_lib.h index 38b046237fe..86ca3ac2244 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h @@ -57,4 +57,9 @@ int hwrm_ring_alloc_send_msg(struct bnge_net *bn, int bnge_hwrm_set_async_event_cr(struct bnge_dev *bd, int idx); int bnge_hwrm_vnic_set_tpa(struct bnge_dev *bd, struct bnge_vnic_info *vni= c, u32 tpa_flags); +int bnge_update_link(struct bnge_net *bn, bool chng_link_state); +int bnge_hwrm_phy_qcaps(struct bnge_dev *bd); +int bnge_hwrm_set_link_setting(struct bnge_net *bn, bool set_pause); +int bnge_hwrm_set_pause(struct bnge_net *bn); +int bnge_hwrm_shutdown_link(struct bnge_dev *bd); #endif /* _BNGE_HWRM_LIB_H_ */ diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_link.c b/drivers/net/e= thernet/broadcom/bnge/bnge_link.c new file mode 100644 index 00000000000..bff04dfadac --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.c @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2025 Broadcom. + +#include + +#include "bnge.h" +#include "bnge_link.h" +#include "bnge_hwrm_lib.h" + +static u32 bnge_fw_to_ethtool_speed(u16 fw_link_speed) +{ + switch (fw_link_speed) { + case BNGE_LINK_SPEED_50GB: + case BNGE_LINK_SPEED_50GB_PAM4: + return SPEED_50000; + case BNGE_LINK_SPEED_100GB: + case BNGE_LINK_SPEED_100GB_PAM4: + case BNGE_LINK_SPEED_100GB_PAM4_112: + return SPEED_100000; + case BNGE_LINK_SPEED_200GB: + case BNGE_LINK_SPEED_200GB_PAM4: + case BNGE_LINK_SPEED_200GB_PAM4_112: + return SPEED_200000; + case BNGE_LINK_SPEED_400GB: + case BNGE_LINK_SPEED_400GB_PAM4: + case BNGE_LINK_SPEED_400GB_PAM4_112: + return SPEED_400000; + case BNGE_LINK_SPEED_800GB: + case BNGE_LINK_SPEED_800GB_PAM4_112: + return SPEED_800000; + default: + return SPEED_UNKNOWN; + } +} + +static void bnge_set_auto_speed(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) { + elink_info->advertising =3D link_info->auto_link_speeds2; + return; + } + elink_info->advertising =3D link_info->auto_link_speeds; + elink_info->advertising_pam4 =3D link_info->auto_pam4_link_speeds; +} + +static void bnge_set_force_speed(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) { + elink_info->req_link_speed =3D link_info->force_link_speed2; + switch (elink_info->req_link_speed) { + case BNGE_LINK_SPEED_50GB_PAM4: + case BNGE_LINK_SPEED_100GB_PAM4: + case BNGE_LINK_SPEED_200GB_PAM4: + case BNGE_LINK_SPEED_400GB_PAM4: + elink_info->req_signal_mode =3D BNGE_SIG_MODE_PAM4; + break; + case BNGE_LINK_SPEED_100GB_PAM4_112: + case BNGE_LINK_SPEED_200GB_PAM4_112: + case BNGE_LINK_SPEED_400GB_PAM4_112: + case BNGE_LINK_SPEED_800GB_PAM4_112: + elink_info->req_signal_mode =3D BNGE_SIG_MODE_PAM4_112; + break; + default: + elink_info->req_signal_mode =3D BNGE_SIG_MODE_NRZ; + break; + } + } else if (link_info->force_pam4_link_speed) { + elink_info->req_link_speed =3D link_info->force_pam4_link_speed; + elink_info->req_signal_mode =3D BNGE_SIG_MODE_PAM4; + } else { + elink_info->req_link_speed =3D link_info->force_link_speed; + elink_info->req_signal_mode =3D BNGE_SIG_MODE_NRZ; + } +} + +void bnge_init_ethtool_link_settings(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + if (BNGE_AUTO_MODE(link_info->auto_mode)) { + elink_info->autoneg =3D BNGE_AUTONEG_SPEED; + if (link_info->auto_pause_setting & + PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE) + elink_info->autoneg |=3D BNGE_AUTONEG_FLOW_CTRL; + bnge_set_auto_speed(bn); + } else { + bnge_set_force_speed(bn); + elink_info->req_duplex =3D link_info->duplex_setting; + } + if (elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL) + elink_info->req_flow_ctrl =3D + link_info->auto_pause_setting & BNGE_LINK_PAUSE_BOTH; + else + elink_info->req_flow_ctrl =3D link_info->force_pause_setting; +} + +int bnge_probe_phy(struct bnge_net *bn, bool fw_dflt) +{ + struct bnge_dev *bd =3D bn->bd; + int rc; + + bd->phy_flags =3D 0; + rc =3D bnge_hwrm_phy_qcaps(bd); + if (rc) { + netdev_err(bn->netdev, + "Probe PHY can't get PHY qcaps (rc: %d)\n", rc); + return rc; + } + if (bd->phy_flags & BNGE_PHY_FL_NO_FCS) + bn->netdev->priv_flags |=3D IFF_SUPP_NOFCS; + else + bn->netdev->priv_flags &=3D ~IFF_SUPP_NOFCS; + if (!fw_dflt) + return 0; + + mutex_lock(&bd->link_lock); + rc =3D bnge_update_link(bn, false); + if (rc) { + mutex_unlock(&bd->link_lock); + netdev_err(bn->netdev, "Probe PHY can't update link (rc: %d)\n", + rc); + return rc; + } + bnge_init_ethtool_link_settings(bn); + mutex_unlock(&bd->link_lock); + + return 0; +} + +void bnge_hwrm_set_link_common(struct bnge_net *bn, + struct hwrm_port_phy_cfg_input *req) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_dev *bd =3D bn->bd; + + if (elink_info->autoneg & BNGE_AUTONEG_SPEED) { + req->auto_mode |=3D PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK; + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) { + req->enables |=3D cpu_to_le32(BNGE_PHY_AUTO_SPEEDS2_MASK); + req->auto_link_speeds2_mask =3D + cpu_to_le16(elink_info->advertising); + } else if (elink_info->advertising) { + req->enables |=3D cpu_to_le32(BNGE_PHY_AUTO_SPEED_MASK); + req->auto_link_speed_mask =3D + cpu_to_le16(elink_info->advertising); + } + if (elink_info->advertising_pam4) { + req->enables |=3D + cpu_to_le32(BNGE_PHY_AUTO_PAM4_SPEED_MASK); + req->auto_link_pam4_speed_mask =3D + cpu_to_le16(elink_info->advertising_pam4); + } + req->enables |=3D cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_MODE); + req->flags |=3D cpu_to_le32(BNGE_PHY_FLAGS_RESTART_AUTO); + } else { + req->flags |=3D cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE); + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) { + req->force_link_speeds2 =3D + cpu_to_le16(elink_info->req_link_speed); + req->enables |=3D + cpu_to_le32(BNGE_PHY_FLAGS_ENA_FORCE_SPEEDS2); + netif_info(bn, link, bn->netdev, + "Forcing FW speed2: %d\n", + (u32)elink_info->req_link_speed); + } else if (elink_info->req_signal_mode =3D=3D BNGE_SIG_MODE_PAM4) { + req->force_pam4_link_speed =3D + cpu_to_le16(elink_info->req_link_speed); + req->enables |=3D + cpu_to_le32(BNGE_PHY_FLAGS_ENA_FORCE_PM4_SPEED); + } else { + req->force_link_speed =3D + cpu_to_le16(elink_info->req_link_speed); + } + } + + /* tell FW that the setting takes effect immediately */ + req->flags |=3D cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); +} + +static bool bnge_auto_speed_updated(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) + return elink_info->advertising !=3D link_info->auto_link_speeds2; + + return elink_info->advertising !=3D link_info->auto_link_speeds || + elink_info->advertising_pam4 !=3D link_info->auto_pam4_link_speeds; +} + +void bnge_hwrm_set_pause_common(struct bnge_net *bn, + struct hwrm_port_phy_cfg_input *req) +{ + if (bn->eth_link_info.autoneg & BNGE_AUTONEG_FLOW_CTRL) { + req->auto_pause =3D PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE; + if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_RX) + req->auto_pause |=3D PORT_PHY_CFG_REQ_AUTO_PAUSE_RX; + if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_TX) + req->auto_pause |=3D PORT_PHY_CFG_REQ_AUTO_PAUSE_TX; + req->enables |=3D + cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE); + } else { + if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_RX) + req->force_pause |=3D PORT_PHY_CFG_REQ_FORCE_PAUSE_RX; + if (bn->eth_link_info.req_flow_ctrl & BNGE_LINK_PAUSE_TX) + req->force_pause |=3D PORT_PHY_CFG_REQ_FORCE_PAUSE_TX; + req->enables |=3D + cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_FORCE_PAUSE); + req->auto_pause =3D req->force_pause; + req->enables |=3D + cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE); + } +} + +static bool bnge_force_speed_updated(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) + return elink_info->req_link_speed !=3D link_info->force_link_speed2; + + if (elink_info->req_signal_mode =3D=3D BNGE_SIG_MODE_NRZ) + return elink_info->req_link_speed !=3D link_info->force_link_speed; + + return elink_info->req_signal_mode =3D=3D BNGE_SIG_MODE_PAM4 && + elink_info->req_link_speed !=3D link_info->force_pam4_link_speed; +} + +int bnge_update_phy_setting(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + bool update_pause =3D false; + bool update_link =3D false; + int rc; + + link_info =3D &bd->link_info; + elink_info =3D &bn->eth_link_info; + rc =3D bnge_update_link(bn, true); + if (rc) { + netdev_err(bn->netdev, "failed to update link (rc: %d)\n", + rc); + return rc; + } + + if ((elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL) && + (link_info->auto_pause_setting & BNGE_LINK_PAUSE_BOTH) !=3D + elink_info->req_flow_ctrl) + update_pause =3D true; + if (!(elink_info->autoneg & BNGE_AUTONEG_FLOW_CTRL) && + link_info->force_pause_setting !=3D elink_info->req_flow_ctrl) + update_pause =3D true; + if (!(elink_info->autoneg & BNGE_AUTONEG_SPEED)) { + if (BNGE_AUTO_MODE(link_info->auto_mode)) + update_link =3D true; + if (bnge_force_speed_updated(bn)) + update_link =3D true; + if (elink_info->req_duplex !=3D link_info->duplex_setting) + update_link =3D true; + } else { + if (link_info->auto_mode =3D=3D BNGE_LINK_AUTO_NONE) + update_link =3D true; + if (bnge_auto_speed_updated(bn)) + update_link =3D true; + } + + /* The last close may have shut down the link, so need to call + * PHY_CFG to bring it back up. + */ + if (!BNGE_LINK_IS_UP(bd)) + update_link =3D true; + + if (update_link) + rc =3D bnge_hwrm_set_link_setting(bn, update_pause); + else if (update_pause) + rc =3D bnge_hwrm_set_pause(bn); + + if (rc) { + netdev_err(bn->netdev, + "failed to update PHY setting (rc: %d)\n", rc); + return rc; + } + + return 0; +} + +void bnge_get_port_module_status(struct bnge_net *bn) +{ + struct hwrm_port_phy_qcfg_output *resp; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + u8 module_status; + + link_info =3D &bd->link_info; + resp =3D &link_info->phy_qcfg_resp; + + if (bnge_update_link(bn, true)) + return; + + module_status =3D link_info->module_status; + switch (module_status) { + case PORT_PHY_QCFG_RESP_MODULE_STATUS_DISABLETX: + case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: + case PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG: + netdev_warn(bn->netdev, + "Unqualified SFP+ module detected on port %d\n", + bd->pf.port_id); + netdev_warn(bn->netdev, "Module part number %s\n", + resp->phy_vendor_partnumber); + if (module_status =3D=3D PORT_PHY_QCFG_RESP_MODULE_STATUS_DISABLETX) + netdev_warn(bn->netdev, "TX is disabled\n"); + if (module_status =3D=3D PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN) + netdev_warn(bn->netdev, "SFP+ module is shut down\n"); + break; + } +} + +static bool bnge_support_dropped(u16 advertising, u16 supported) +{ + return (advertising & ~supported) !=3D 0; +} + +bool bnge_support_speed_dropped(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + /* Check if any advertised speeds are no longer supported. The caller + * holds the link_lock mutex, so we can modify link_info settings. + */ + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) { + if (bnge_support_dropped(elink_info->advertising, + link_info->support_auto_speeds2)) { + elink_info->advertising =3D + link_info->support_auto_speeds2; + return true; + } + return false; + } + if (bnge_support_dropped(elink_info->advertising, + link_info->support_auto_speeds)) { + elink_info->advertising =3D link_info->support_auto_speeds; + return true; + } + if (bnge_support_dropped(elink_info->advertising_pam4, + link_info->support_pam4_auto_speeds)) { + elink_info->advertising_pam4 =3D + link_info->support_pam4_auto_speeds; + return true; + } + return false; +} + +static char *bnge_report_fec(struct bnge_link_info *link_info) +{ + u8 active_fec =3D link_info->active_fec_sig_mode & + PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; + + switch (active_fec) { + default: + case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: + return "None"; + case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: + return "Clause 74 BaseR"; + case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: + return "Clause 91 RS(528,514)"; + case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: + return "Clause 91 RS544_1XN"; + case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: + return "Clause 91 RS(544,514)"; + case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: + return "Clause 91 RS272_1XN"; + case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: + return "Clause 91 RS(272,257)"; + } +} + +void bnge_report_link(struct bnge_dev *bd) +{ + if (BNGE_LINK_IS_UP(bd)) { + const char *signal =3D ""; + const char *flow_ctrl; + const char *duplex; + u32 speed; + u16 fec; + + netif_carrier_on(bd->netdev); + speed =3D bnge_fw_to_ethtool_speed(bd->link_info.link_speed); + if (speed =3D=3D SPEED_UNKNOWN) { + netdev_info(bd->netdev, + "NIC Link is Up, speed unknown\n"); + return; + } + if (bd->link_info.duplex =3D=3D BNGE_LINK_DUPLEX_FULL) + duplex =3D "full"; + else + duplex =3D "half"; + if (bd->link_info.pause =3D=3D BNGE_LINK_PAUSE_BOTH) + flow_ctrl =3D "ON - receive & transmit"; + else if (bd->link_info.pause =3D=3D BNGE_LINK_PAUSE_TX) + flow_ctrl =3D "ON - transmit"; + else if (bd->link_info.pause =3D=3D BNGE_LINK_PAUSE_RX) + flow_ctrl =3D "ON - receive"; + else + flow_ctrl =3D "none"; + if (bd->link_info.phy_qcfg_resp.option_flags & + PORT_PHY_QCFG_RESP_OPTION_FLAGS_SIGNAL_MODE_KNOWN) { + u8 sig_mode =3D bd->link_info.active_fec_sig_mode & + PORT_PHY_QCFG_RESP_SIGNAL_MODE_MASK; + switch (sig_mode) { + case PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ: + signal =3D "(NRZ) "; + break; + case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4: + signal =3D "(PAM4 56Gbps) "; + break; + case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112: + signal =3D "(PAM4 112Gbps) "; + break; + default: + break; + } + } + netdev_info(bd->netdev, "NIC Link is Up, %u Mbps %s%s duplex, Flow contr= ol: %s\n", + speed, signal, duplex, flow_ctrl); + fec =3D bd->link_info.fec_cfg; + if (!(fec & PORT_PHY_QCFG_RESP_FEC_CFG_FEC_NONE_SUPPORTED)) + netdev_info(bd->netdev, "FEC autoneg %s encoding: %s\n", + (fec & BNGE_FEC_AUTONEG) ? "on" : "off", + bnge_report_fec(&bd->link_info)); + } else { + netif_carrier_off(bd->netdev); + netdev_err(bd->netdev, "NIC Link is Down\n"); + } +} diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_link.h b/drivers/net/e= thernet/broadcom/bnge/bnge_link.h new file mode 100644 index 00000000000..2adf32dab5a --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2025 Broadcom */ + +#ifndef _BNGE_LINK_H_ +#define _BNGE_LINK_H_ + +#define BNGE_PHY_CFG_ABLE(bd) \ + ((bd)->link_info.phy_enabled) + +#define BNGE_PHY_AUTO_SPEEDS2_MASK \ + PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK +#define BNGE_PHY_AUTO_SPEED_MASK \ + PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK +#define BNGE_PHY_AUTO_PAM4_SPEED_MASK \ + PORT_PHY_CFG_REQ_ENABLES_AUTO_PAM4_LINK_SPEED_MASK +#define BNGE_PHY_FLAGS_RESTART_AUTO \ + PORT_PHY_CFG_REQ_FLAGS_RESTART_AUTONEG +#define BNGE_PHY_FLAGS_ENA_FORCE_SPEEDS2 \ + PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2 +#define BNGE_PHY_FLAGS_ENA_FORCE_PM4_SPEED \ + PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED + +#define BNGE_LINK_LINK PORT_PHY_QCFG_RESP_LINK_LINK + +enum bnge_link_state { + BNGE_LINK_STATE_UNKNOWN, + BNGE_LINK_STATE_DOWN, + BNGE_LINK_STATE_UP, +}; + +#define BNGE_LINK_IS_UP(bd) \ + ((bd)->link_info.link_state =3D=3D BNGE_LINK_STATE_UP) + +#define BNGE_LINK_DUPLEX_FULL PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL + +#define BNGE_LINK_PAUSE_TX PORT_PHY_QCFG_RESP_PAUSE_TX +#define BNGE_LINK_PAUSE_RX PORT_PHY_QCFG_RESP_PAUSE_RX +#define BNGE_LINK_PAUSE_BOTH (PORT_PHY_QCFG_RESP_PAUSE_RX | \ + PORT_PHY_QCFG_RESP_PAUSE_TX) + +#define BNGE_LINK_AUTO_NONE PORT_PHY_QCFG_RESP_AUTO_MODE_NONE +#define BNGE_LINK_AUTO_MSK PORT_PHY_QCFG_RESP_AUTO_MODE_SPEED_MASK +#define BNGE_AUTO_MODE(mode) ((mode) > BNGE_LINK_AUTO_NONE && \ + (mode) <=3D BNGE_LINK_AUTO_MSK) + +#define BNGE_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB +#define BNGE_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB +#define BNGE_LINK_SPEED_200GB PORT_PHY_QCFG_RESP_LINK_SPEED_200GB +#define BNGE_LINK_SPEED_400GB PORT_PHY_QCFG_RESP_LINK_SPEED_400GB +#define BNGE_LINK_SPEED_800GB PORT_PHY_QCFG_RESP_LINK_SPEED_800GB + +#define BNGE_LINK_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_50GB +#define BNGE_LINK_SPEED_MSK_100GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_100GB + +#define BNGE_LINK_PAM4_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEE= DS_50G +#define BNGE_LINK_PAM4_SPEED_MSK_100GB \ + PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_100G +#define BNGE_LINK_PAM4_SPEED_MSK_200GB \ + PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_200G + +#define BNGE_LINK_SPEEDS2_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB +#define BNGE_LINK_SPEEDS2_MSK_100GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100= GB +#define BNGE_LINK_SPEEDS2_MSK_50GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB_PAM4_56 +#define BNGE_LINK_SPEEDS2_MSK_100GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_56 +#define BNGE_LINK_SPEEDS2_MSK_200GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_56 +#define BNGE_LINK_SPEEDS2_MSK_400GB_PAM4 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_56 +#define BNGE_LINK_SPEEDS2_MSK_100GB_PAM4_112 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_112 +#define BNGE_LINK_SPEEDS2_MSK_200GB_PAM4_112 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_112 +#define BNGE_LINK_SPEEDS2_MSK_400GB_PAM4_112 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_112 +#define BNGE_LINK_SPEEDS2_MSK_800GB_PAM4_112 \ + PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_800GB_PAM4_112 + +#define BNGE_LINK_SPEED_50GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56 +#define BNGE_LINK_SPEED_100GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56 +#define BNGE_LINK_SPEED_200GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56 +#define BNGE_LINK_SPEED_400GB_PAM4 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56 +#define BNGE_LINK_SPEED_100GB_PAM4_112 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112 +#define BNGE_LINK_SPEED_200GB_PAM4_112 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112 +#define BNGE_LINK_SPEED_400GB_PAM4_112 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112 +#define BNGE_LINK_SPEED_800GB_PAM4_112 \ + PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_800GB_PAM4_112 + +#define BNGE_FEC_NONE PORT_PHY_QCFG_RESP_FEC_CFG_FEC_NONE_SUPPORTED +#define BNGE_FEC_AUTONEG PORT_PHY_QCFG_RESP_FEC_CFG_FEC_AUTONEG_ENABLED +#define BNGE_FEC_ENC_BASE_R_CAP \ + PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE74_SUPPORTED +#define BNGE_FEC_ENC_BASE_R PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE74_ENABLED +#define BNGE_FEC_ENC_RS_CAP \ + PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_SUPPORTED +#define BNGE_FEC_ENC_LLRS_CAP \ + (PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_1XN_SUPPORTED | \ + PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_IEEE_SUPPORTED) +#define BNGE_FEC_ENC_RS \ + (PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_ENABLED | \ + PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_1XN_ENABLED | \ + PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_IEEE_ENABLED) +#define BNGE_FEC_ENC_LLRS \ + (PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_1XN_ENABLED | \ + PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_IEEE_ENABLED) + +struct bnge_link_info { + u8 phy_type; + u8 media_type; + u8 phy_addr; + u8 phy_link_status; + bool phy_enabled; + + u8 link_state; + u8 active_lanes; + u8 duplex; + u8 pause; + u8 lp_pause; + u8 auto_pause_setting; + u8 force_pause_setting; + u8 duplex_setting; + u8 auto_mode; + u16 link_speed; + u16 support_speeds; + u16 support_pam4_speeds; + u16 support_speeds2; + + u16 auto_link_speeds; /* fw adv setting */ + u16 auto_pam4_link_speeds; + u16 auto_link_speeds2; + + u16 support_auto_speeds; + u16 support_pam4_auto_speeds; + u16 support_auto_speeds2; + + u16 lp_auto_link_speeds; + u16 lp_auto_pam4_link_speeds; + u16 force_link_speed; + u16 force_pam4_link_speed; + u16 force_link_speed2; + + u8 module_status; + u8 active_fec_sig_mode; + u16 fec_cfg; + + /* A copy of phy_qcfg output used to report link + * info to VF + */ + struct hwrm_port_phy_qcfg_output phy_qcfg_resp; + + bool phy_retry; + unsigned long phy_retry_expires; +}; + +#define BNGE_AUTONEG_SPEED 1 +#define BNGE_AUTONEG_FLOW_CTRL 2 + +#define BNGE_SIG_MODE_NRZ PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ +#define BNGE_SIG_MODE_PAM4 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4 +#define BNGE_SIG_MODE_PAM4_112 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112 +#define BNGE_SIG_MODE_MAX (PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST + 1) + +struct bnge_ethtool_link_info { + /* copy of requested setting from ethtool cmd */ + u8 autoneg; + u8 req_signal_mode; + u8 req_duplex; + u8 req_flow_ctrl; + u16 req_link_speed; + u16 advertising; /* user adv setting */ + u16 advertising_pam4; + bool force_link_chng; +}; + +void bnge_hwrm_set_link_common(struct bnge_net *bn, + struct hwrm_port_phy_cfg_input *req); +void bnge_hwrm_set_pause_common(struct bnge_net *bn, + struct hwrm_port_phy_cfg_input *req); +int bnge_update_phy_setting(struct bnge_net *bn); +void bnge_get_port_module_status(struct bnge_net *bn); +void bnge_report_link(struct bnge_dev *bd); +bool bnge_support_speed_dropped(struct bnge_net *bn); +void bnge_init_ethtool_link_settings(struct bnge_net *bn); +int bnge_probe_phy(struct bnge_net *bn, bool fw_dflt); +#endif /* _BNGE_LINK_H_ */ diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.c index a1bb1f01246..2ad0021d38e 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -101,6 +101,17 @@ static int bnge_alloc_ring_stats(struct bnge_net *bn) return rc; } =20 +void __bnge_queue_sp_work(struct bnge_net *bn) +{ + queue_work(bn->bnge_pf_wq, &bn->sp_task); +} + +static void bnge_queue_sp_work(struct bnge_net *bn, unsigned int event) +{ + set_bit(event, &bn->sp_event); + __bnge_queue_sp_work(bn); +} + static void bnge_timer(struct timer_list *t) { struct bnge_net *bn =3D timer_container_of(bn, t, timer); @@ -113,7 +124,14 @@ static void bnge_timer(struct timer_list *t) if (atomic_read(&bn->intr_sem) !=3D 0) goto bnge_restart_timer; =20 - /* Periodic work added by later patches */ + if (bd->link_info.phy_retry) { + if (time_after(jiffies, bd->link_info.phy_retry_expires)) { + bd->link_info.phy_retry =3D false; + netdev_warn(bn->netdev, "failed to update PHY settings after maximum re= tries.\n"); + } else { + bnge_queue_sp_work(bn, BNGE_UPDATE_PHY_SP_EVENT); + } + } =20 bnge_restart_timer: mod_timer(&bn->timer, jiffies + bn->current_interval); @@ -132,7 +150,19 @@ static void bnge_sp_task(struct work_struct *work) return; } =20 - /* Event handling work added by later patches */ + if (test_and_clear_bit(BNGE_UPDATE_PHY_SP_EVENT, &bn->sp_event)) { + int rc; + + mutex_lock(&bd->link_lock); + rc =3D bnge_update_phy_setting(bn); + mutex_unlock(&bd->link_lock); + if (rc) { + netdev_warn(bn->netdev, "update PHY settings retry failed\n"); + } else { + bd->link_info.phy_retry =3D false; + netdev_info(bn->netdev, "update PHY settings retry succeeded\n"); + } + } =20 /* Ensure all sp_task work is done before clearing the state */ smp_mb__before_atomic(); @@ -2516,6 +2546,8 @@ static void bnge_tx_enable(struct bnge_net *bn) /* Make sure napi polls see @dev_state change */ synchronize_net(); netif_tx_wake_all_queues(bn->netdev); + if (BNGE_LINK_IS_UP(bn->bd)) + netif_carrier_on(bn->netdev); } =20 static int bnge_open_core(struct bnge_net *bn) @@ -2552,6 +2584,16 @@ static int bnge_open_core(struct bnge_net *bn) =20 bnge_enable_napi(bn); =20 + mutex_lock(&bd->link_lock); + rc =3D bnge_update_phy_setting(bn); + mutex_unlock(&bd->link_lock); + if (rc) { + netdev_warn(bn->netdev, "failed to update PHY settings (rc: %d)\n", + rc); + bd->link_info.phy_retry =3D true; + bd->link_info.phy_retry_expires =3D jiffies + 5 * HZ; + } + set_bit(BNGE_STATE_OPEN, &bd->state); =20 bnge_enable_int(bn); @@ -2560,6 +2602,11 @@ static int bnge_open_core(struct bnge_net *bn) =20 mod_timer(&bn->timer, jiffies + bn->current_interval); =20 + /* Poll link status and check for SFP+ module status */ + mutex_lock(&bd->link_lock); + bnge_get_port_module_status(bn); + mutex_unlock(&bd->link_lock); + return 0; =20 err_free_irq: @@ -2615,6 +2662,7 @@ static int bnge_close(struct net_device *dev) struct bnge_net *bn =3D netdev_priv(dev); =20 bnge_close_core(bn); + bnge_hwrm_shutdown_link(bn->bd); =20 return 0; } @@ -2872,6 +2920,10 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_i= rqs) bnge_init_l2_fltr_tbl(bn); bnge_init_mac_addr(bd); =20 + rc =3D bnge_probe_phy(bn, true); + if (rc) + goto err_netdev; + netdev->request_ops_lock =3D true; rc =3D register_netdev(netdev); if (rc) { diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.h index f7446b7c4ba..041ef5792f6 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -9,6 +9,7 @@ #include #include "bnge_db.h" #include "bnge_hw_def.h" +#include "bnge_link.h" =20 struct tx_bd { __le32 tx_bd_len_flags_type; @@ -231,6 +232,13 @@ enum bnge_net_state { =20 #define BNGE_TIMER_INTERVAL HZ =20 +enum bnge_sp_event { + BNGE_LINK_CHNG_SP_EVENT, + BNGE_LINK_SPEED_CHNG_SP_EVENT, + BNGE_LINK_CFG_CHANGE_SP_EVENT, + BNGE_UPDATE_PHY_SP_EVENT, +}; + struct bnge_net { struct bnge_dev *bd; struct net_device *netdev; @@ -300,6 +308,9 @@ struct bnge_net { struct timer_list timer; struct workqueue_struct *bnge_pf_wq; struct work_struct sp_task; + unsigned long sp_event; + + struct bnge_ethtool_link_info eth_link_info; }; =20 #define BNGE_DEFAULT_RX_RING_SIZE 511 @@ -583,4 +594,5 @@ u8 *__bnge_alloc_rx_frag(struct bnge_net *bn, dma_addr_= t *mapping, struct bnge_rx_ring_info *rxr, gfp_t gfp); int bnge_alloc_rx_netmem(struct bnge_net *bn, struct bnge_rx_ring_info *rx= r, u16 prod, gfp_t gfp); +void __bnge_queue_sp_work(struct bnge_net *bn); #endif /* _BNGE_NETDEV_H_ */ --=20 2.47.3 From nobody Sun Apr 5 18:20:21 2026 Received: from mail-ua1-f98.google.com (mail-ua1-f98.google.com [209.85.222.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 2E7BE324B22 for ; Mon, 23 Feb 2026 16:37:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.98 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864666; cv=none; b=dWV+fMKE/2Fqp9woF8EPeMowkhdKsTbc4KoLNR7xlyFO550DnQwuagpgA2Xx37YD4uojGPaD4URoWvuTjIht4InGGNyWEIJn/ujpZmEO88KvbXfIjtj7bY+xkQ4wZkYcwgzn2kZtm34wrN7MksUK5wsitrDvipYxZcathi71EeI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864666; c=relaxed/simple; bh=zxHI6ZonX4MtUvBVvWVA7mLNiairc57vQUyHnOgsO9A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=U6nyB4C/zmXfsCkvrR7tS2sSN3HERuQ/dIN5vmKO+tj6cKXLcPtvuPa1x2VcpcSZHHslHkg9D+HvrWTss52juYZkn4cp8irkWJ0PKW9saICyb6NqD9qFAHe7WPWFt6PbnjFrvJriFdHYFp2YdLCUwUh1DWWfDoc8jwvUgeskjZE= 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=DFBXyOYJ; arc=none smtp.client-ip=209.85.222.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="DFBXyOYJ" Received: by mail-ua1-f98.google.com with SMTP id a1e0cc1a2514c-948af5e704cso1156647241.3 for ; Mon, 23 Feb 2026 08:37:41 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771864661; x=1772469461; 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=Dzb/jARPn2B02cssPHrDGXwmpZ1YWqu7LCCpgY0lOdo=; b=xLn/DEWsVwHhRbKBB0bw1q/41V76k9OLush3Zmg3WBnCFD22om+0CyMqIFNmpCVijp Hgq3EFzgE6L7XH6+n9N5SFdjyjBCgUwqVboaFj9TMr7McNBAtU7elz4W2QuCINfKBbiE mlSOWPn4fBAdcvfiPnalKg+cKQjJ4ZuXs0X9WAx2atfsaGRKORLwB+ldLO9RUqppQIaY 0dSmCajOjCVE97l/b5y7k+hDMUMx+g0yiI1XhqmJXxSt99U+d+C+CsyG+pTRppOx11/U nXvVwNzTqYqSVw3UbLQWLfv/JfU7FjfNr1Ffi5NeaiBPmCrJkL6z1kKDXsS5yVXCqZln DVqA== X-Forwarded-Encrypted: i=1; AJvYcCUje44uHqc7O8I8NEH4z9QS/goDQ0MzDEBbH5SWJA98rZc2Ln6IXiS1h0tD9hBEKqSMGzVem9LctUuLMzo=@vger.kernel.org X-Gm-Message-State: AOJu0YzUnbjg3ehtH7wKJjo3poG50KdVymFgJOAFfbAM+37I44+g3z// khmFuJkVHhUBAyRjLLC9Ri67LOlvkUO5Ys+k5NvT1XIjlAAokdaRN/5F6vNu2fYtTkzZ6TxJ/6V uRH08u7JP+v+NUx/d4SAKWcXQC83cSp3oLmv2i0B3S1XZH17td7jvYL06mXUlJt7XSyxMtEoyc2 /1nVGSwtVtT8RCeVRMVM0y1m6Ry/e+0WM8RGpiy3n5hWGxhN7YF1sTXgEZYc2oJ+4Zx7uZxFEjh 1rKVA4nzEEroxjhcxWQztDHHg== X-Gm-Gg: AZuq6aK/EhHDwemP6+cA3YuAb1z0sKQHGBSIOCYG5h0Oigv7My1t2iPhiyKSo4LlOiN MQaEK52Zhq80pzQjdK34qSOB8C/xcV2N1BLkDI9kTaqMtT9IIf/jtimGpedH8ZVUkdytf3zxVLY p6p5KktsF9CjjYUILImbJHONko8bR2rJM7oPfhTm9Mr9wbp2BdxMlT27fCufS2jR3Vfr0ueb4Mc B44ItkEoMV37w4ks4dvC3I42fAUDJqq7ZnqyTnQdp0/z41ptels/q7VbTEpfimobEAXtXmhXkOT R9jv5yvwKOCo61fg9dXtu/s1FScPYvBE7LZD0bHzrN2q2g9nie3tW4TFnt2RDigt9JG0ww+B2BI rz63coucmmGphKHv6aoEf5EcwvukqGpv7QbHnLPpw9zIIjmIFz5ot5NxtXlxGrptELMDp8IHCxF d6qbKoU//la5GbBT3sNfBrXD3hQv6oXitBfxNBL+rC2BKcDIZ5FquhV+8jK8y8d8qJVQ== X-Received: by 2002:a05:6102:6312:10b0:5fe:c506:c83 with SMTP id ada2fe7eead31-5fec5060caamr1311369137.39.1771864660934; Mon, 23 Feb 2026 08:37:40 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-103.dlp.protect.broadcom.com. [144.49.247.103]) by smtp-relay.gmail.com with ESMTPS id ada2fe7eead31-5feb63fb9d9sm848737137.4.2026.02.23.08.37.40 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2026 08:37:40 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-2ad44941ea2so28098045ad.1 for ; Mon, 23 Feb 2026 08:37:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1771864660; x=1772469460; 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=Dzb/jARPn2B02cssPHrDGXwmpZ1YWqu7LCCpgY0lOdo=; b=DFBXyOYJ45sufxwfl7RRat/oSPMvffYEH8xCrqAE0E++mxijmEEwmwOFxqDOmIao8O 4CcbTvLPeOH32MHBitJ7XwZX/5D6vHxAEEPE2OA5biPsou77W/dJurysi1MCQVQoE1B9 hGF4418FWIV5EdQ/A2dTFFpRSXbcvIMz3yJHw= X-Forwarded-Encrypted: i=1; AJvYcCWc5mZ67ZJKLbutbZ/a4tpbg5TmK5iaKgtUqngDxF1oc4KtrwuBkEPN5u/5u4cXlNn/Yzdj9uwb3p0/KlY=@vger.kernel.org X-Received: by 2002:a17:902:ef0b:b0:2aa:d288:7bf9 with SMTP id d9443c01a7336-2ad74511f55mr92886495ad.31.1771864659233; Mon, 23 Feb 2026 08:37:39 -0800 (PST) X-Received: by 2002:a17:902:ef0b:b0:2aa:d288:7bf9 with SMTP id d9443c01a7336-2ad74511f55mr92886145ad.31.1771864658654; Mon, 23 Feb 2026 08:37:38 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ad74e3445fsm96763825ad.13.2026.02.23.08.37.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 08:37:38 -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 , Ajit Kumar Khaparde Subject: [PATCH net-next 3/7] bng_en: add ethtool link settings, get_link, and nway_reset Date: Mon, 23 Feb 2026 22:06:37 +0530 Message-ID: <20260223163641.755200-4-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260223163641.755200-1-bhargava.marreddy@broadcom.com> References: <20260223163641.755200-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" Add get/set_link_ksettings, get_link, and nway_reset support. Report supported, advertised, and link-partner speeds across NRZ, PAM4, and PAM4-112 signaling modes. Enable lane count reporting. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Rajashekar Hudumula Reviewed-by: Ajit Kumar Khaparde --- drivers/net/ethernet/broadcom/bnge/bnge.h | 2 + .../net/ethernet/broadcom/bnge/bnge_core.c | 1 + .../net/ethernet/broadcom/bnge/bnge_ethtool.c | 24 + .../net/ethernet/broadcom/bnge/bnge_link.c | 801 ++++++++++++++++++ .../net/ethernet/broadcom/bnge/bnge_link.h | 7 + 5 files changed, 835 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethern= et/broadcom/bnge/bnge.h index dabf559c754..8d8c8ede285 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge.h @@ -98,6 +98,8 @@ struct bnge_queue_info { #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 struct bnge_dev { struct device *dev; diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/e= thernet/broadcom/bnge/bnge_core.c index 2d063b6cf49..c2d10159a05 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c @@ -10,6 +10,7 @@ #include "bnge_devlink.h" #include "bnge_hwrm.h" #include "bnge_hwrm_lib.h" +#include "bnge_link.h" =20 MODULE_LICENSE("GPL"); MODULE_DESCRIPTION(DRV_SUMMARY); diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c b/drivers/ne= t/ethernet/broadcom/bnge/bnge_ethtool.c index 569371c1b4f..e4d3041db0a 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c @@ -11,6 +11,25 @@ =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 +43,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 bff04dfadac..f037229db7b 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_link.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.c @@ -7,6 +7,51 @@ #include "bnge_link.h" #include "bnge_hwrm_lib.h" =20 +enum bnge_media_type { + BNGE_MEDIA_UNKNOWN =3D 0, + BNGE_MEDIA_CR, + BNGE_MEDIA_SR, + BNGE_MEDIA_LR_ER_FR, + BNGE_MEDIA_KR, + __BNGE_MEDIA_END, +}; + +static const enum bnge_media_type bnge_phy_types[] =3D { + [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, +}; + static u32 bnge_fw_to_ethtool_speed(u16 fw_link_speed) { switch (fw_link_speed) { @@ -461,3 +506,759 @@ 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); + + 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_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; + } +} + +/* Compile-time link mode mapping table. + * Indexed by [speed_idx][sig_mode][media]. + */ +#define BNGE_LINK_M(speed, sig, media, lm) \ + [BNGE_LINK_SPEED_##speed##_IDX] \ + [BNGE_SIG_MODE_##sig] \ + [BNGE_MEDIA_##media] =3D ETHTOOL_LINK_MODE_##lm##_Full_BIT + +static const enum ethtool_link_mode_bit_indices +bnge_link_modes[__BNGE_LINK_SPEED_END] + [BNGE_SIG_MODE_MAX] + [__BNGE_MEDIA_END] =3D { + /* 50GB PAM4 */ + BNGE_LINK_M(50GB, PAM4, CR, 50000baseCR), + BNGE_LINK_M(50GB, PAM4, SR, 50000baseSR), + BNGE_LINK_M(50GB, PAM4, LR_ER_FR, 50000baseLR_ER_FR), + BNGE_LINK_M(50GB, PAM4, KR, 50000baseKR), + + /* 100GB NRZ */ + BNGE_LINK_M(100GB, NRZ, CR, 100000baseCR4), + BNGE_LINK_M(100GB, NRZ, SR, 100000baseSR4), + BNGE_LINK_M(100GB, NRZ, LR_ER_FR, 100000baseLR4_ER4), + BNGE_LINK_M(100GB, NRZ, KR, 100000baseKR4), + + /* 100GB PAM4 */ + BNGE_LINK_M(100GB, PAM4, CR, 100000baseCR2), + BNGE_LINK_M(100GB, PAM4, SR, 100000baseSR2), + BNGE_LINK_M(100GB, PAM4, LR_ER_FR, 100000baseLR2_ER2_FR2), + BNGE_LINK_M(100GB, PAM4, KR, 100000baseKR2), + + /* 100GB PAM4_112 */ + BNGE_LINK_M(100GB, PAM4_112, CR, 100000baseCR), + BNGE_LINK_M(100GB, PAM4_112, SR, 100000baseSR), + BNGE_LINK_M(100GB, PAM4_112, LR_ER_FR, 100000baseLR_ER_FR), + BNGE_LINK_M(100GB, PAM4_112, KR, 100000baseKR), + + /* 200GB PAM4 */ + BNGE_LINK_M(200GB, PAM4, CR, 200000baseCR4), + BNGE_LINK_M(200GB, PAM4, SR, 200000baseSR4), + BNGE_LINK_M(200GB, PAM4, LR_ER_FR, 200000baseLR4_ER4_FR4), + BNGE_LINK_M(200GB, PAM4, KR, 200000baseKR4), + + /* 200GB PAM4_112 */ + BNGE_LINK_M(200GB, PAM4_112, CR, 200000baseCR2), + BNGE_LINK_M(200GB, PAM4_112, SR, 200000baseSR2), + BNGE_LINK_M(200GB, PAM4_112, LR_ER_FR, 200000baseLR2_ER2_FR2), + BNGE_LINK_M(200GB, PAM4_112, KR, 200000baseKR2), + + /* 400GB PAM4 */ + BNGE_LINK_M(400GB, PAM4, CR, 400000baseCR8), + BNGE_LINK_M(400GB, PAM4, SR, 400000baseSR8), + BNGE_LINK_M(400GB, PAM4, LR_ER_FR, 400000baseLR8_ER8_FR8), + BNGE_LINK_M(400GB, PAM4, KR, 400000baseKR8), + + /* 400GB PAM4_112 */ + BNGE_LINK_M(400GB, PAM4_112, CR, 400000baseCR4), + BNGE_LINK_M(400GB, PAM4_112, SR, 400000baseSR4), + BNGE_LINK_M(400GB, PAM4_112, LR_ER_FR, 400000baseLR4_ER4_FR4), + BNGE_LINK_M(400GB, PAM4_112, KR, 400000baseKR4), + + /* 800GB PAM4_112 */ + BNGE_LINK_M(800GB, PAM4_112, CR, 800000baseCR8), + BNGE_LINK_M(800GB, PAM4_112, SR, 800000baseSR8), + BNGE_LINK_M(800GB, PAM4_112, KR, 800000baseKR8), +}; + +#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; + + 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, u32 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, u32 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, u32 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; + u32 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; + u32 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; + u32 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 =3D NULL; + 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; + } + + 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; + } + break; + default: + break; + } + + 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; + 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 { + if (base->duplex =3D=3D DUPLEX_HALF) { + netdev_err(dev, "HALF DUPLEX is not supported!\n"); + rc =3D -EINVAL; + goto set_setting_exit; + } + rc =3D bnge_force_link_speed(dev, base->speed, + lk_ksettings->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 2adf32dab5a..12be5cab579 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_link.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.h @@ -4,6 +4,8 @@ #ifndef _BNGE_LINK_H_ #define _BNGE_LINK_H_ =20 +#include + #define BNGE_PHY_CFG_ABLE(bd) \ ((bd)->link_info.phy_enabled) =20 @@ -190,4 +192,9 @@ void bnge_report_link(struct bnge_dev *bd); bool bnge_support_speed_dropped(struct bnge_net *bn); void bnge_init_ethtool_link_settings(struct bnge_net *bn); int bnge_probe_phy(struct bnge_net *bn, bool fw_dflt); +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); #endif /* _BNGE_LINK_H_ */ --=20 2.47.3 From nobody Sun Apr 5 18:20:21 2026 Received: from mail-pl1-f227.google.com (mail-pl1-f227.google.com [209.85.214.227]) (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 D87A13246F8 for ; Mon, 23 Feb 2026 16:37:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.227 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864669; cv=none; b=Esn6czaVofX3cCOvokPJP39g0/EP5wIN/GO52c+Ejn0/fUKHAefl4Yug8M7DAkopghRYPZUR/Eus3ZYoflCSU38hvbUCYQq8Q4ai+A3OsBJKKGxHFXwazOZrwv5ovwB/lSszOZrxJTNaWXmyHjZEwq0azYnJ8oO9HR8Jd+iJAW8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864669; c=relaxed/simple; bh=rbI+wS4h/nAII8/38ytw6Qa6YcvqjRY+zAAuPNjnqLI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hdGLdS+p7W2wBw9oQz0J9+Y8VMbIAeFaOF4cXBZRa2G9cGq15FIUt0NyQPo5DvQX+bRF/cPmp8iQWfz9zmCm3s28D5FGxshRvTow1bd782Jo5weAwHkIzkFx1JUa+QMgZeVD35hiDX0k1vJniHgUe13bx9Ts+AwJfabLuJBCiN8= 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=HbwLO5xN; arc=none smtp.client-ip=209.85.214.227 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="HbwLO5xN" Received: by mail-pl1-f227.google.com with SMTP id d9443c01a7336-2a871daa98fso31713105ad.1 for ; Mon, 23 Feb 2026 08:37:46 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771864666; x=1772469466; 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=QXqcrYrUMpsk0hJeQOkUygfghc5Wbge/uByCmNLlVLs=; b=rPdYK9IKBrZOQQ90qaFKNtgW4tLNgjyf76Bw04FMubImh25ZLqTdhUGrxbLUo8YA1b yM6Ft2d8TrzGiOzgB04euhvYh/9u/0AY4/usic3yDdoyk4R+35C1MS7/NKgoroaBc+m2 6wsgkHbcVTvmFbQVBZyQyGv/5OFqitUYiaKlSWJ/kt9uEjFUBS07Jv99tYb9iRQn28DA SS5UNuNXeOF2xJpJLlPCCDl47jcUfha0CfUAS1KaI8nwEI1nGv2GVKHm/bpDp9kQXwc8 OPa4gRd4eu37922r+MX+wMDnzEdDCfmLSKsNt1jXx0ipjYDlZdDxon8qbtNlFzhtAUdT pF8A== X-Forwarded-Encrypted: i=1; AJvYcCW+Mib0VGKNUaUr0LVlplo668mLS/p3JGfQPxQAwXHaEAo5SLwqQK7K7LFEV1qRcsstmxYR25z/AVJTxiU=@vger.kernel.org X-Gm-Message-State: AOJu0YzcPdjcUsbDgbr61GfJeOv+p6gQnu0fdqQ7JqZzPQV1cEOTcS6Y QM5UQ/akNMKgNaG2KkfmxEkv62+eKUDCM2PGbo8t3VlOecISdWXJ4j1weK4lGuO8h+5CL12UMIk tZHsxNxyKEIH8CV7KpnDhYw9LkdBnUABUEXgti4rLLglQrOOy/yQtP6m49TpD5mb2WkiKHCXVKW WtiCOSvW2Tipws24XFURuFTKPdenOf8Skf2Q/3REBiiYQVz6hvgd1pJNprv9c+qQKct03HuAmxl v7ahbOcjEjEJu1dRia5XK9xog== X-Gm-Gg: ATEYQzxoeCsW8KoAIx/fojCKgb+81JK5xZVJwwT7AY/Vryl9bvdAcutGj6k2UUskdIF 3QcE6B9Xs4dIaOVN7suAdQp6zNePu8P/DUqufhtdSc9UYIIphtw+pEFTt2JoZJfvQJWj3PJ9+hG a7fXzQaA9n73gw8sE5eJeCNcZroIqcVcWGZFtqhQD27J7aN9QYiaWMVjppxn+kPfaTGOPa6as9X mRQhIg/s6Ot04JSJS13wrWeTfD7kSfjZ/+Fb4Q9tl/1Uc9JfBOHbK3JQZO8Rac+i+aD773lRk1l NBrc+YfohXfXtDR9j3Coiz2bWk84B6k1/zRDMtOq1Ytn5N17XzggTpKbKM4M2fI9D0TMnc4AbCQ YGXGs723dU05Q/VDrhPP9q+AJjPBHAJQEWd4/YnrKV6PjRhUmgrO3hpnlKOZd7quyVehextRcmf d72JililYm1oEg3oAtMYcpc3qOeaybqkJbSTqSWlaoFXAhoM+fpBbJd4VRHZVpKiLV+w== X-Received: by 2002:a17:903:2ece:b0:2a9:638b:a4 with SMTP id d9443c01a7336-2ad74419e31mr87375925ad.6.1771864665926; Mon, 23 Feb 2026 08:37:45 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-103.dlp.protect.broadcom.com. [144.49.247.103]) by smtp-relay.gmail.com with ESMTPS id d9443c01a7336-2ad74fd698bsm8760065ad.33.2026.02.23.08.37.45 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2026 08:37:45 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-2a8c273332cso429400125ad.1 for ; Mon, 23 Feb 2026 08:37:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1771864664; x=1772469464; 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=QXqcrYrUMpsk0hJeQOkUygfghc5Wbge/uByCmNLlVLs=; b=HbwLO5xNW1o6MbwmKV9qLsdZnuMJu4Un2dFmJcSHVldyro+2Y75aXPLSnb3TCRr9gL ANuGl/+AujIByV5fYAKl1h51CVW99OBZ8V7ByE5axaV3xvjgAyRGSsCyYA//2c3AY53V gzWR1YC8yba95PMR3ksI8YznFkkx60h6Gclzk= X-Forwarded-Encrypted: i=1; AJvYcCUesdghHc379A7OK418v6VRjCmnUEqZ7iPTUlD8RbPCiWPn3jNovR33aMKu8EOO4qoxmpH3NkYTzLRRgKI=@vger.kernel.org X-Received: by 2002:a17:902:d502:b0:2a9:410:2413 with SMTP id d9443c01a7336-2ad7450552fmr95590065ad.29.1771864663918; Mon, 23 Feb 2026 08:37:43 -0800 (PST) X-Received: by 2002:a17:902:d502:b0:2a9:410:2413 with SMTP id d9443c01a7336-2ad7450552fmr95589755ad.29.1771864663405; Mon, 23 Feb 2026 08:37:43 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ad74e3445fsm96763825ad.13.2026.02.23.08.37.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 08:37:43 -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 , Ajit Kumar Khaparde Subject: [PATCH net-next 4/7] bng_en: add support for link async events Date: Mon, 23 Feb 2026 22:06:38 +0530 Message-ID: <20260223163641.755200-5-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260223163641.755200-1-bhargava.marreddy@broadcom.com> References: <20260223163641.755200-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" Register for firmware asynchronous events, including link-status, link-speed, and PHY configuration changes. Upon event reception, re-query the PHY and update ethtool settings accordingly. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Rajashekar Hudumula Reviewed-by: Ajit Kumar Khaparde --- .../ethernet/broadcom/bnge/bnge_hwrm_lib.c | 17 ++++++- .../net/ethernet/broadcom/bnge/bnge_link.c | 47 +++++++++++++++++++ .../net/ethernet/broadcom/bnge/bnge_link.h | 4 ++ .../net/ethernet/broadcom/bnge/bnge_netdev.c | 19 ++++++++ .../net/ethernet/broadcom/bnge/bnge_txrx.c | 35 ++++++++++++-- 5 files changed, 117 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c b/drivers/n= et/ethernet/broadcom/bnge/bnge_hwrm_lib.c index 3e6a5bd45a0..43d5ba15728 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c @@ -15,6 +15,13 @@ #include "bnge_rmem.h" #include "bnge_resc.h" =20 +static const u16 bnge_async_events_arr[] =3D { + ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE, + ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE, + ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE, + ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE, +}; + int bnge_hwrm_ver_get(struct bnge_dev *bd) { u32 dev_caps_cfg, hwrm_ver, hwrm_spec_code; @@ -166,10 +173,12 @@ int bnge_hwrm_fw_set_time(struct bnge_dev *bd) =20 int bnge_hwrm_func_drv_rgtr(struct bnge_dev *bd) { + DECLARE_BITMAP(async_events_bmap, 256); + u32 *events =3D (u32 *)async_events_bmap; struct hwrm_func_drv_rgtr_output *resp; struct hwrm_func_drv_rgtr_input *req; u32 flags; - int rc; + int rc, i; =20 rc =3D bnge_hwrm_req_init(bd, req, HWRM_FUNC_DRV_RGTR); if (rc) @@ -190,6 +199,12 @@ int bnge_hwrm_func_drv_rgtr(struct bnge_dev *bd) req->ver_min =3D cpu_to_le16(DRV_VER_MIN); req->ver_upd =3D cpu_to_le16(DRV_VER_UPD); =20 + memset(async_events_bmap, 0, sizeof(async_events_bmap)); + for (i =3D 0; i < ARRAY_SIZE(bnge_async_events_arr); i++) + __set_bit(bnge_async_events_arr[i], async_events_bmap); + for (i =3D 0; i < ARRAY_SIZE(req->async_event_fwd); i++) + req->async_event_fwd[i] |=3D cpu_to_le32(events[i]); + resp =3D bnge_hwrm_req_hold(bd, req); rc =3D bnge_hwrm_req_send(bd, req); if (!rc) { diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_link.c b/drivers/net/e= thernet/broadcom/bnge/bnge_link.c index f037229db7b..9f0f9b4db1d 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_link.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.c @@ -94,6 +94,21 @@ static void bnge_set_auto_speed(struct bnge_net *bn) elink_info->advertising_pam4 =3D link_info->auto_pam4_link_speeds; } =20 +static u16 bnge_get_force_speed(struct bnge_net *bn) +{ + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + struct bnge_link_info *link_info; + struct bnge_dev *bd =3D bn->bd; + + link_info =3D &bd->link_info; + + if (bd->phy_flags & BNGE_PHY_FL_SPEEDS2) + return link_info->force_link_speed2; + if (elink_info->req_signal_mode =3D=3D BNGE_SIG_MODE_PAM4) + return link_info->force_pam4_link_speed; + return link_info->force_link_speed; +} + static void bnge_set_force_speed(struct bnge_net *bn) { struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; @@ -1262,3 +1277,35 @@ int bnge_set_link_ksettings(struct net_device *dev, =20 return rc; } + +void bnge_link_async_event_process(struct bnge_net *bn, + u16 event_id, u32 evt_data) +{ + switch (event_id) { + case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE: { + struct bnge_ethtool_link_info *elink_info =3D &bn->eth_link_info; + + /* print unsupported speed warning in forced speed mode only */ + if (!(elink_info->autoneg & BNGE_AUTONEG_SPEED) && + (evt_data & BNGE_SPEED_CFG_CHANGE_SP_NOT_SUPP)) { + u16 fw_speed =3D bnge_get_force_speed(bn); + u32 speed =3D bnge_fw_to_ethtool_speed(fw_speed); + + if (speed !=3D SPEED_UNKNOWN) + netdev_warn(bn->netdev, "Link speed %d no longer supported\n", + speed); + } + set_bit(BNGE_LINK_SPEED_CHNG_SP_EVENT, &bn->sp_event); + fallthrough; + } + case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE: + case ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE: + set_bit(BNGE_LINK_CFG_CHANGE_SP_EVENT, &bn->sp_event); + fallthrough; + case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE: + set_bit(BNGE_LINK_CHNG_SP_EVENT, &bn->sp_event); + break; + default: + break; + } +} diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_link.h b/drivers/net/e= thernet/broadcom/bnge/bnge_link.h index 12be5cab579..bdcb75a941c 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_link.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_link.h @@ -197,4 +197,8 @@ int bnge_set_link_ksettings(struct net_device *dev, int bnge_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *lk_ksettings); u32 bnge_get_link(struct net_device *dev); +#define BNGE_SPEED_CFG_CHANGE_SP_NOT_SUPP BIT(17) + +void bnge_link_async_event_process(struct bnge_net *bn, + u16 event_id, u32 evt_data); #endif /* _BNGE_LINK_H_ */ diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.c index 2ad0021d38e..4909727547e 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -164,6 +164,25 @@ static void bnge_sp_task(struct work_struct *work) } } =20 + if (test_and_clear_bit(BNGE_LINK_CHNG_SP_EVENT, &bn->sp_event)) { + int rc; + + mutex_lock(&bd->link_lock); + if (test_and_clear_bit(BNGE_LINK_SPEED_CHNG_SP_EVENT, + &bn->sp_event)) + bnge_hwrm_phy_qcaps(bd); + + rc =3D bnge_update_link(bn, true); + if (rc) + netdev_err(bn->netdev, "SP task cannot update link (rc: %d)\n", + rc); + + if (test_and_clear_bit(BNGE_LINK_CFG_CHANGE_SP_EVENT, + &bn->sp_event)) + bnge_init_ethtool_link_settings(bn); + mutex_unlock(&bd->link_lock); + } + /* Ensure all sp_task work is done before clearing the state */ smp_mb__before_atomic(); clear_bit(BNGE_STATE_IN_SP_TASK, &bn->state); diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_txrx.c b/drivers/net/e= thernet/broadcom/bnge/bnge_txrx.c index a2616f03755..88f9cf1db30 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_txrx.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_txrx.c @@ -1128,6 +1128,29 @@ static void __bnge_poll_work_done(struct bnge_net *b= n, struct bnge_napi *bnapi, } } =20 +static void bnge_async_event_process(struct bnge_net *bn, + struct hwrm_async_event_cmpl *cmpl) +{ + u16 event_id =3D le16_to_cpu(cmpl->event_id); + u32 data1 =3D le32_to_cpu(cmpl->event_data1); + u32 data2 =3D le32_to_cpu(cmpl->event_data2); + + netdev_dbg(bn->netdev, "hwrm event 0x%x {0x%x, 0x%x}\n", + event_id, data1, data2); + + switch (event_id) { + case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE: + case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE: + case ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE: + case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE: + bnge_link_async_event_process(bn, event_id, data1); + break; + default: + return; + } + __bnge_queue_sp_work(bn); +} + static void bnge_hwrm_update_token(struct bnge_dev *bd, u16 seq_id, enum bnge_hwrm_wait_state state) @@ -1146,7 +1169,7 @@ bnge_hwrm_update_token(struct bnge_dev *bd, u16 seq_i= d, dev_err(bd->dev, "Invalid hwrm seq id %d\n", seq_id); } =20 -static int bnge_hwrm_handler(struct bnge_dev *bd, struct tx_cmp *txcmp) +static int bnge_hwrm_handler(struct bnge_net *bn, struct tx_cmp *txcmp) { struct hwrm_cmpl *h_cmpl =3D (struct hwrm_cmpl *)txcmp; u16 cmpl_type =3D TX_CMP_TYPE(txcmp), seq_id; @@ -1154,10 +1177,14 @@ static int bnge_hwrm_handler(struct bnge_dev *bd, s= truct tx_cmp *txcmp) switch (cmpl_type) { case CMPL_BASE_TYPE_HWRM_DONE: seq_id =3D le16_to_cpu(h_cmpl->sequence_id); - bnge_hwrm_update_token(bd, seq_id, BNGE_HWRM_COMPLETE); + bnge_hwrm_update_token(bn->bd, seq_id, BNGE_HWRM_COMPLETE); break; =20 case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT: + bnge_async_event_process(bn, + (struct hwrm_async_event_cmpl *)txcmp); + break; + default: break; } @@ -1235,7 +1262,7 @@ static int __bnge_poll_work(struct bnge_net *bn, stru= ct bnge_cp_ring_info *cpr, } else if (unlikely(cmp_type =3D=3D CMPL_BASE_TYPE_HWRM_DONE || cmp_type =3D=3D CMPL_BASE_TYPE_HWRM_FWD_REQ || cmp_type =3D=3D CMPL_BA_TY_HWRM_ASY_EVT)) { - bnge_hwrm_handler(bn->bd, txcmp); + bnge_hwrm_handler(bn, txcmp); } raw_cons =3D NEXT_RAW_CMP(raw_cons); =20 @@ -1355,7 +1382,7 @@ int bnge_napi_poll(struct napi_struct *napi, int budg= et) budget - work_done); nqr->has_more_work |=3D cpr->has_more_work; } else { - bnge_hwrm_handler(bn->bd, (struct tx_cmp *)nqcmp); + bnge_hwrm_handler(bn, (struct tx_cmp *)nqcmp); } raw_cons =3D NEXT_RAW_CMP(raw_cons); } --=20 2.47.3 From nobody Sun Apr 5 18:20:21 2026 Received: from mail-qv1-f99.google.com (mail-qv1-f99.google.com [209.85.219.99]) (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 E839F315D35 for ; Mon, 23 Feb 2026 16:37:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864674; cv=none; b=Tzj15z/z1lthiNp31sv6OXimEsMkV2MISpzO5QhCAelCAripQ4oUncCcq1JrFv2l566GOeD790FwiTjkGAH4VKrEnns0DX7nfZnMKHpp3YvMJtewS7QerQ/J90DwDcf11kHayWYF5qNPuT0AymSCa614o1oQWGN8XRg0zbEVKhg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864674; c=relaxed/simple; bh=yAMk7TEyKuVIntg+6qonIrWjug4I4WlDt69r+aSxAbE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a8BgBoELUG0gt2SnquT3loAILlsDIACHmrDhOyZMhKAzMYSqZsfHv5LZXCHM54EqEvPLD8u2r3tQ2T1m8MnfBQvEfmjYHtYwjFza2QBQrEnZWdiuorA19HYBqONtMLUkDu0ObMu3xd83b4t7B6/sULy667VqHHAJeOtA5etp8oA= 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=UnQ9344+; arc=none smtp.client-ip=209.85.219.99 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="UnQ9344+" Received: by mail-qv1-f99.google.com with SMTP id 6a1803df08f44-896f8feee14so55160436d6.0 for ; Mon, 23 Feb 2026 08:37:51 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771864671; x=1772469471; 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=RpCjYQGu9v7Uz5w/jl5uHhDYOP0WsPSErLV0p3fOu8w=; b=WBpMPcUUceYbSIzixn1D+oiz+fCPUIdU6vxTNOso1uTJmgSkFjhvvqRMi4XGPaqSvp l8NKXgtfu81PqYa6FgnKIHcPxoOjMQDB4fzQ8+eQTOkZqW8BlGzpKU4krBJUu4rMqRdi l7vRRVHCen0BP9SE7nuTLESN1x2BDAFzuAHFw8b51XMvIEXqRpkzF5q24fCGAG7w8UrY eVH9lBF2i6H0gBIevxsqIzQRmXHAGFLCFiVYWIlAAsvNCcQSBxPvRBhhgMQgDieNeDId VgjaCqsnFv2gnPUjHBX4rJUlk+zz2vRq6e4Bc7ehZUao1mlolVtisMrgDjM5lQnZFWbZ Iphw== X-Forwarded-Encrypted: i=1; AJvYcCUUyiLMP0RPNUUmDLK11OB+uN8U4WcimtaNHX5WfVVxTytlJx2QvNC4nZCiHGTUOMitQIZL/MukJRPYjTQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yz9CVGWLjqy9CCw5rNi0C0EBNVoCl/GUV+pqBqF92uMHfpjrkf8 wx5QOAo3LlN76EsNbcKztmVn9hz2ul/Oo2bNylb9ZJ84bk0N/LkqW8u9/FXAd2rEpXRz0mH/WS0 qU2d19/uEZuKsK3whrXMeQMvIdd00ytqYTfHWUVymOp+JOSrwPnmKyp0kVe/Wjymw0iAAc9d5GI NFn5Z9PK4vEI8hzFLYc+0GoYXD4A2lKHtk1X0F4iWxELkbIBSPOgdygwlA6cF8/7J240NjQpm6f 2rD9Cnmmhsoy8bmA0I3tsKYEg== X-Gm-Gg: ATEYQzyC2wbYvlstEBRdKLowHRL4aRnbhzNgMfkJiwV3opn5nQPmSR7bufxMZv24zKE eJhaEZ86kGLTeBmDKgAP28g+Rn3cXLeH7Vb9SMhFS/lanf3Iw/8NpvuMG+kx3jtQcRrJNCO0fdZ XnyfGsIwdt+eHqiD+W4PVPJCw3YmTSJsR76+hVfClvnMiCqmYRkZ6y80s5iaLfn7GF+Opux6j// JoguAqby6fmC61V+tngkbaNXoZ/K1+2bwo6q7bGpTS0ubYSddzsYAKzHhH4KIB2t0y1huwu8it7 AVFsRAKPSqVkn7fQHJSzXSXWVWqrfvD2lqif1LxDrnRjTLgldSbjZMtGovgYrvSIJcILmfyGB6D LHKFu6dMCpu1AVOGoxl2sHhvG70awHypKs9OGYYcygF30PZRjdp5iVQb5dx1SVq91bZDIUiXkwq Ue7bBF8OS3uuY3WF+qI5k2WGnNmSnyhviFTVKoAAn3R/E77HAgW1DBbwFHClRD4CE5GA== X-Received: by 2002:ad4:5de3:0:b0:894:768a:a8c1 with SMTP id 6a1803df08f44-89979f36cc3mr122235576d6.66.1771864670690; Mon, 23 Feb 2026 08:37:50 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-116.dlp.protect.broadcom.com. [144.49.247.116]) by smtp-relay.gmail.com with ESMTPS id 6a1803df08f44-8997e73ad1bsm8998346d6.29.2026.02.23.08.37.50 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2026 08:37:50 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2aaeafeadbcso52756595ad.1 for ; Mon, 23 Feb 2026 08:37:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1771864669; x=1772469469; 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=RpCjYQGu9v7Uz5w/jl5uHhDYOP0WsPSErLV0p3fOu8w=; b=UnQ9344+YVRoxiHTsrp0+DORB6pw+wXjhh7qGRpJrPqNP73mnyx4scnbuUN6E+axXh wJmq9eXd1W3yOfRMIWA3vm77IYeEW3bDN8uyd7RHrwBzrabobduqKJJV6JqyHWm4XC0m QJE+5MOh3O4OmvhqPCn0r3sxDYkLo8zDzogzE= X-Forwarded-Encrypted: i=1; AJvYcCXxTGBedDOVG2+GUev9vC0YZzpkxbfN8XN0WNzyG6ADbBvC0MSghlRbsQIUzKIO+mvrANSBfxv9GKkNvpk=@vger.kernel.org X-Received: by 2002:a17:903:2f8b:b0:2aa:f798:8c86 with SMTP id d9443c01a7336-2ad74564e09mr80462265ad.47.1771864668816; Mon, 23 Feb 2026 08:37:48 -0800 (PST) X-Received: by 2002:a17:903:2f8b:b0:2aa:f798:8c86 with SMTP id d9443c01a7336-2ad74564e09mr80461865ad.47.1771864668208; Mon, 23 Feb 2026 08:37:48 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ad74e3445fsm96763825ad.13.2026.02.23.08.37.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 08:37:47 -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 , Rahul Gupta , Ajit Kumar Khaparde Subject: [PATCH net-next 5/7] bng_en: add initial support for ethtool stats display Date: Mon, 23 Feb 2026 22:06:39 +0530 Message-ID: <20260223163641.755200-6-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260223163641.755200-1-bhargava.marreddy@broadcom.com> References: <20260223163641.755200-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" Implement ethtool -S callbacks for per-ring RX/TX, TPA, and port-level MAC/extended statistics. Include string names, counts, and DMA-backed memory allocation for port stats via HWRM wrappers. Stats are initially reported as 0; accumulation logic is added in a subsequent patch. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Rahul Gupta Reviewed-by: Ajit Kumar Khaparde --- .../net/ethernet/broadcom/bnge/bnge_ethtool.c | 606 ++++++++++++++++++ .../ethernet/broadcom/bnge/bnge_hwrm_lib.c | 142 ++++ .../ethernet/broadcom/bnge/bnge_hwrm_lib.h | 3 + .../net/ethernet/broadcom/bnge/bnge_netdev.c | 229 ++++++- .../net/ethernet/broadcom/bnge/bnge_netdev.h | 87 ++- 5 files changed, 1056 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c b/drivers/ne= t/ethernet/broadcom/bnge/bnge_ethtool.c index e4d3041db0a..8f8f6789c94 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c @@ -31,6 +31,368 @@ static int bnge_nway_reset(struct net_device *dev) return rc; } =20 +static const char * const bnge_ring_rx_stats_str[] =3D { + "rx_ucast_packets", + "rx_mcast_packets", + "rx_bcast_packets", + "rx_discards", + "rx_errors", + "rx_ucast_bytes", + "rx_mcast_bytes", + "rx_bcast_bytes", +}; + +static const char * const bnge_ring_tx_stats_str[] =3D { + "tx_ucast_packets", + "tx_mcast_packets", + "tx_bcast_packets", + "tx_errors", + "tx_discards", + "tx_ucast_bytes", + "tx_mcast_bytes", + "tx_bcast_bytes", +}; + +static const char * const bnge_ring_tpa_stats_str[] =3D { + "tpa_packets", + "tpa_bytes", + "tpa_events", + "tpa_aborts", +}; + +static const char * const bnge_ring_tpa2_stats_str[] =3D { + "rx_tpa_eligible_pkt", + "rx_tpa_eligible_bytes", + "rx_tpa_pkt", + "rx_tpa_bytes", + "rx_tpa_errors", + "rx_tpa_events", +}; + +static const char * const bnge_rx_sw_stats_str[] =3D { + "rx_l4_csum_errors", + "rx_resets", + "rx_buf_errors", +}; + +#define BNGE_RX_STATS_ENTRY(counter) \ + { BNGE_RX_STATS_OFFSET(counter), __stringify(counter) } + +#define BNGE_TX_STATS_ENTRY(counter) \ + { BNGE_TX_STATS_OFFSET(counter), __stringify(counter) } + +#define BNGE_RX_STATS_EXT_ENTRY(counter) \ + { BNGE_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } + +#define BNGE_TX_STATS_EXT_ENTRY(counter) \ + { BNGE_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } + +#define BNGE_RX_STATS_EXT_PFC_ENTRY(n) \ + BNGE_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ + BNGE_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) + +#define BNGE_TX_STATS_EXT_PFC_ENTRY(n) \ + BNGE_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ + BNGE_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) + +#define BNGE_RX_STATS_EXT_PFC_ENTRIES \ + BNGE_RX_STATS_EXT_PFC_ENTRY(0), \ + BNGE_RX_STATS_EXT_PFC_ENTRY(1), \ + BNGE_RX_STATS_EXT_PFC_ENTRY(2), \ + BNGE_RX_STATS_EXT_PFC_ENTRY(3), \ + BNGE_RX_STATS_EXT_PFC_ENTRY(4), \ + BNGE_RX_STATS_EXT_PFC_ENTRY(5), \ + BNGE_RX_STATS_EXT_PFC_ENTRY(6), \ + BNGE_RX_STATS_EXT_PFC_ENTRY(7) + +#define BNGE_TX_STATS_EXT_PFC_ENTRIES \ + BNGE_TX_STATS_EXT_PFC_ENTRY(0), \ + BNGE_TX_STATS_EXT_PFC_ENTRY(1), \ + BNGE_TX_STATS_EXT_PFC_ENTRY(2), \ + BNGE_TX_STATS_EXT_PFC_ENTRY(3), \ + BNGE_TX_STATS_EXT_PFC_ENTRY(4), \ + BNGE_TX_STATS_EXT_PFC_ENTRY(5), \ + BNGE_TX_STATS_EXT_PFC_ENTRY(6), \ + BNGE_TX_STATS_EXT_PFC_ENTRY(7) + +#define BNGE_RX_STATS_EXT_COS_ENTRY(n) \ + BNGE_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ + BNGE_RX_STATS_EXT_ENTRY(rx_packets_cos##n) + +#define BNGE_TX_STATS_EXT_COS_ENTRY(n) \ + BNGE_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ + BNGE_TX_STATS_EXT_ENTRY(tx_packets_cos##n) + +#define BNGE_RX_STATS_EXT_COS_ENTRIES \ + BNGE_RX_STATS_EXT_COS_ENTRY(0), \ + BNGE_RX_STATS_EXT_COS_ENTRY(1), \ + BNGE_RX_STATS_EXT_COS_ENTRY(2), \ + BNGE_RX_STATS_EXT_COS_ENTRY(3), \ + BNGE_RX_STATS_EXT_COS_ENTRY(4), \ + BNGE_RX_STATS_EXT_COS_ENTRY(5), \ + BNGE_RX_STATS_EXT_COS_ENTRY(6), \ + BNGE_RX_STATS_EXT_COS_ENTRY(7) \ + +#define BNGE_TX_STATS_EXT_COS_ENTRIES \ + BNGE_TX_STATS_EXT_COS_ENTRY(0), \ + BNGE_TX_STATS_EXT_COS_ENTRY(1), \ + BNGE_TX_STATS_EXT_COS_ENTRY(2), \ + BNGE_TX_STATS_EXT_COS_ENTRY(3), \ + BNGE_TX_STATS_EXT_COS_ENTRY(4), \ + BNGE_TX_STATS_EXT_COS_ENTRY(5), \ + BNGE_TX_STATS_EXT_COS_ENTRY(6), \ + BNGE_TX_STATS_EXT_COS_ENTRY(7) \ + +#define BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \ + BNGE_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \ + BNGE_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n) + +#define BNGE_RX_STATS_EXT_DISCARD_COS_ENTRIES \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \ + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRY(7) + +#define BNGE_RX_STATS_PRI_ENTRY(counter, n) \ + { BNGE_RX_STATS_EXT_OFFSET(counter##_cos0), \ + __stringify(counter##_pri##n) } + +#define BNGE_TX_STATS_PRI_ENTRY(counter, n) \ + { BNGE_TX_STATS_EXT_OFFSET(counter##_cos0), \ + __stringify(counter##_pri##n) } + +#define BNGE_RX_STATS_PRI_ENTRIES(counter) \ + BNGE_RX_STATS_PRI_ENTRY(counter, 0), \ + BNGE_RX_STATS_PRI_ENTRY(counter, 1), \ + BNGE_RX_STATS_PRI_ENTRY(counter, 2), \ + BNGE_RX_STATS_PRI_ENTRY(counter, 3), \ + BNGE_RX_STATS_PRI_ENTRY(counter, 4), \ + BNGE_RX_STATS_PRI_ENTRY(counter, 5), \ + BNGE_RX_STATS_PRI_ENTRY(counter, 6), \ + BNGE_RX_STATS_PRI_ENTRY(counter, 7) + +#define BNGE_TX_STATS_PRI_ENTRIES(counter) \ + BNGE_TX_STATS_PRI_ENTRY(counter, 0), \ + BNGE_TX_STATS_PRI_ENTRY(counter, 1), \ + BNGE_TX_STATS_PRI_ENTRY(counter, 2), \ + BNGE_TX_STATS_PRI_ENTRY(counter, 3), \ + BNGE_TX_STATS_PRI_ENTRY(counter, 4), \ + BNGE_TX_STATS_PRI_ENTRY(counter, 5), \ + BNGE_TX_STATS_PRI_ENTRY(counter, 6), \ + BNGE_TX_STATS_PRI_ENTRY(counter, 7) + +static const char *const bnge_ring_err_stats_arr[] =3D { + "rx_total_l4_csum_errors", + "rx_total_resets", + "rx_total_buf_errors", + "rx_total_oom_discards", + "rx_total_netpoll_discards", + "rx_total_ring_discards", + "tx_total_resets", + "tx_total_ring_discards", +}; + +#define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnge_rx_sw_stats_str) +#define NUM_RING_RX_HW_STATS ARRAY_SIZE(bnge_ring_rx_stats_str) +#define NUM_RING_TX_HW_STATS ARRAY_SIZE(bnge_ring_tx_stats_str) + +static const struct { + long offset; + char string[ETH_GSTRING_LEN]; +} bnge_tx_port_stats_ext_arr[] =3D { + BNGE_TX_STATS_EXT_COS_ENTRIES, + BNGE_TX_STATS_EXT_PFC_ENTRIES, +}; + +static const struct { + long base_off; + char string[ETH_GSTRING_LEN]; +} bnge_rx_bytes_pri_arr[] =3D { + BNGE_RX_STATS_PRI_ENTRIES(rx_bytes), +}; + +static const struct { + long base_off; + char string[ETH_GSTRING_LEN]; +} bnge_rx_pkts_pri_arr[] =3D { + BNGE_RX_STATS_PRI_ENTRIES(rx_packets), +}; + +static const struct { + long base_off; + char string[ETH_GSTRING_LEN]; +} bnge_tx_bytes_pri_arr[] =3D { + BNGE_TX_STATS_PRI_ENTRIES(tx_bytes), +}; + +static const struct { + long base_off; + char string[ETH_GSTRING_LEN]; +} bnge_tx_pkts_pri_arr[] =3D { + BNGE_TX_STATS_PRI_ENTRIES(tx_packets), +}; + +static const struct { + long offset; + char string[ETH_GSTRING_LEN]; +} bnge_port_stats_arr[] =3D { + BNGE_RX_STATS_ENTRY(rx_64b_frames), + BNGE_RX_STATS_ENTRY(rx_65b_127b_frames), + BNGE_RX_STATS_ENTRY(rx_128b_255b_frames), + BNGE_RX_STATS_ENTRY(rx_256b_511b_frames), + BNGE_RX_STATS_ENTRY(rx_512b_1023b_frames), + BNGE_RX_STATS_ENTRY(rx_1024b_1518b_frames), + BNGE_RX_STATS_ENTRY(rx_good_vlan_frames), + BNGE_RX_STATS_ENTRY(rx_1519b_2047b_frames), + BNGE_RX_STATS_ENTRY(rx_2048b_4095b_frames), + BNGE_RX_STATS_ENTRY(rx_4096b_9216b_frames), + BNGE_RX_STATS_ENTRY(rx_9217b_16383b_frames), + BNGE_RX_STATS_ENTRY(rx_total_frames), + BNGE_RX_STATS_ENTRY(rx_ucast_frames), + BNGE_RX_STATS_ENTRY(rx_mcast_frames), + BNGE_RX_STATS_ENTRY(rx_bcast_frames), + BNGE_RX_STATS_ENTRY(rx_fcs_err_frames), + BNGE_RX_STATS_ENTRY(rx_ctrl_frames), + BNGE_RX_STATS_ENTRY(rx_pause_frames), + BNGE_RX_STATS_ENTRY(rx_pfc_frames), + BNGE_RX_STATS_ENTRY(rx_align_err_frames), + BNGE_RX_STATS_ENTRY(rx_ovrsz_frames), + BNGE_RX_STATS_ENTRY(rx_jbr_frames), + BNGE_RX_STATS_ENTRY(rx_mtu_err_frames), + BNGE_RX_STATS_ENTRY(rx_tagged_frames), + BNGE_RX_STATS_ENTRY(rx_double_tagged_frames), + BNGE_RX_STATS_ENTRY(rx_good_frames), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6), + BNGE_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7), + BNGE_RX_STATS_ENTRY(rx_undrsz_frames), + BNGE_RX_STATS_ENTRY(rx_eee_lpi_events), + BNGE_RX_STATS_ENTRY(rx_eee_lpi_duration), + BNGE_RX_STATS_ENTRY(rx_bytes), + BNGE_RX_STATS_ENTRY(rx_runt_bytes), + BNGE_RX_STATS_ENTRY(rx_runt_frames), + BNGE_RX_STATS_ENTRY(rx_stat_discard), + BNGE_RX_STATS_ENTRY(rx_stat_err), + + BNGE_TX_STATS_ENTRY(tx_64b_frames), + BNGE_TX_STATS_ENTRY(tx_65b_127b_frames), + BNGE_TX_STATS_ENTRY(tx_128b_255b_frames), + BNGE_TX_STATS_ENTRY(tx_256b_511b_frames), + BNGE_TX_STATS_ENTRY(tx_512b_1023b_frames), + BNGE_TX_STATS_ENTRY(tx_1024b_1518b_frames), + BNGE_TX_STATS_ENTRY(tx_good_vlan_frames), + BNGE_TX_STATS_ENTRY(tx_1519b_2047b_frames), + BNGE_TX_STATS_ENTRY(tx_2048b_4095b_frames), + BNGE_TX_STATS_ENTRY(tx_4096b_9216b_frames), + BNGE_TX_STATS_ENTRY(tx_9217b_16383b_frames), + BNGE_TX_STATS_ENTRY(tx_good_frames), + BNGE_TX_STATS_ENTRY(tx_total_frames), + BNGE_TX_STATS_ENTRY(tx_ucast_frames), + BNGE_TX_STATS_ENTRY(tx_mcast_frames), + BNGE_TX_STATS_ENTRY(tx_bcast_frames), + BNGE_TX_STATS_ENTRY(tx_pause_frames), + BNGE_TX_STATS_ENTRY(tx_pfc_frames), + BNGE_TX_STATS_ENTRY(tx_jabber_frames), + BNGE_TX_STATS_ENTRY(tx_fcs_err_frames), + BNGE_TX_STATS_ENTRY(tx_err), + BNGE_TX_STATS_ENTRY(tx_fifo_underruns), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6), + BNGE_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7), + BNGE_TX_STATS_ENTRY(tx_eee_lpi_events), + BNGE_TX_STATS_ENTRY(tx_eee_lpi_duration), + BNGE_TX_STATS_ENTRY(tx_total_collisions), + BNGE_TX_STATS_ENTRY(tx_bytes), + BNGE_TX_STATS_ENTRY(tx_xthol_frames), + BNGE_TX_STATS_ENTRY(tx_stat_discard), + BNGE_TX_STATS_ENTRY(tx_stat_error), +}; + +static const struct { + long offset; + char string[ETH_GSTRING_LEN]; +} bnge_port_stats_ext_arr[] =3D { + BNGE_RX_STATS_EXT_ENTRY(link_down_events), + BNGE_RX_STATS_EXT_ENTRY(continuous_pause_events), + BNGE_RX_STATS_EXT_ENTRY(resume_pause_events), + BNGE_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), + BNGE_RX_STATS_EXT_ENTRY(resume_roce_pause_events), + BNGE_RX_STATS_EXT_COS_ENTRIES, + BNGE_RX_STATS_EXT_PFC_ENTRIES, + BNGE_RX_STATS_EXT_ENTRY(rx_bits), + BNGE_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold), + BNGE_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err), + BNGE_RX_STATS_EXT_ENTRY(rx_corrected_bits), + BNGE_RX_STATS_EXT_DISCARD_COS_ENTRIES, + BNGE_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks), + BNGE_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks), + BNGE_RX_STATS_EXT_ENTRY(rx_filter_miss), +}; + +static int bnge_get_num_tpa_ring_stats(struct bnge_dev *bd) +{ + if (BNGE_SUPPORTS_TPA(bd)) + return BNGE_NUM_TPA_RING_STATS; + return 0; +} + +#define BNGE_NUM_RING_ERR_STATS ARRAY_SIZE(bnge_ring_err_stats_arr) +#define BNGE_NUM_PORT_STATS ARRAY_SIZE(bnge_port_stats_arr) +#define BNGE_NUM_STATS_PRI \ + (ARRAY_SIZE(bnge_rx_bytes_pri_arr) + \ + ARRAY_SIZE(bnge_rx_pkts_pri_arr) + \ + ARRAY_SIZE(bnge_tx_bytes_pri_arr) + \ + ARRAY_SIZE(bnge_tx_pkts_pri_arr)) + +static int bnge_get_num_ring_stats(struct bnge_dev *bd) +{ + int rx, tx; + + rx =3D NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS + + bnge_get_num_tpa_ring_stats(bd); + tx =3D NUM_RING_TX_HW_STATS; + return rx * bd->rx_nr_rings + + tx * bd->tx_nr_rings_per_tc; +} + +static int bnge_get_num_stats(struct bnge_net *bn) +{ + int num_stats =3D bnge_get_num_ring_stats(bn->bd); + int len; + + num_stats +=3D BNGE_NUM_RING_ERR_STATS; + + if (bn->flags & BNGE_FLAG_PORT_STATS) + num_stats +=3D BNGE_NUM_PORT_STATS; + + if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) { + len =3D min_t(int, bn->fw_rx_stats_ext_size, + ARRAY_SIZE(bnge_port_stats_ext_arr)); + num_stats +=3D len; + len =3D min_t(int, bn->fw_tx_stats_ext_size, + ARRAY_SIZE(bnge_tx_port_stats_ext_arr)); + num_stats +=3D len; + if (bn->pri2cos_valid) + num_stats +=3D BNGE_NUM_STATS_PRI; + } + + return num_stats; +} + static void bnge_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -40,6 +402,247 @@ static void bnge_get_drvinfo(struct net_device *dev, strscpy(info->driver, DRV_NAME, sizeof(info->driver)); strscpy(info->fw_version, bd->fw_ver_str, sizeof(info->fw_version)); strscpy(info->bus_info, pci_name(bd->pdev), sizeof(info->bus_info)); + info->n_stats =3D bnge_get_num_stats(bn); +} + +static int bnge_get_sset_count(struct net_device *dev, int sset) +{ + struct bnge_net *bn =3D netdev_priv(dev); + + switch (sset) { + case ETH_SS_STATS: + return bnge_get_num_stats(bn); + default: + return -EOPNOTSUPP; + } +} + +static bool is_rx_ring(struct bnge_dev *bd, u16 ring_num) +{ + return ring_num < bd->rx_nr_rings; +} + +static bool is_tx_ring(struct bnge_dev *bd, u16 ring_num) +{ + u16 tx_base =3D 0; + + if (!(bd->flags & BNGE_EN_SHARED_CHNL)) + tx_base =3D bd->rx_nr_rings; + + if (ring_num >=3D tx_base && ring_num < (tx_base + bd->tx_nr_rings)) + return true; + return false; +} + +static void bnge_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *buf) +{ + struct bnge_total_ring_err_stats ring_err_stats =3D {}; + struct bnge_net *bn =3D netdev_priv(dev); + struct bnge_dev *bd =3D bn->bd; + u64 *curr, *prev; + u32 tpa_stats; + u32 i, j =3D 0; + + if (!bn->bnapi) { + j +=3D bnge_get_num_ring_stats(bd); + goto skip_ring_stats; + } + + tpa_stats =3D bnge_get_num_tpa_ring_stats(bd); + for (i =3D 0; i < bd->nq_nr_rings; i++) { + struct bnge_napi *bnapi =3D bn->bnapi[i]; + struct bnge_nq_ring_info *nqr =3D &bnapi->nq_ring; + u64 *sw_stats =3D nqr->stats.sw_stats; + u64 *sw; + int k; + + if (is_rx_ring(bd, i)) { + for (k =3D 0; k < NUM_RING_RX_HW_STATS; j++, k++) + buf[j] =3D sw_stats[k]; + } + if (is_tx_ring(bd, i)) { + k =3D NUM_RING_RX_HW_STATS; + for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; + j++, k++) + buf[j] =3D sw_stats[k]; + } + if (!tpa_stats || !is_rx_ring(bd, i)) + goto skip_tpa_ring_stats; + + k =3D NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; + for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS + + tpa_stats; j++, k++) + buf[j] =3D sw_stats[k]; + +skip_tpa_ring_stats: + sw =3D (u64 *)&nqr->sw_stats->rx; + if (is_rx_ring(bd, i)) { + for (k =3D 0; k < NUM_RING_RX_SW_STATS; j++, k++) + buf[j] =3D sw[k]; + } + } + + bnge_get_ring_err_stats(bn, &ring_err_stats); + +skip_ring_stats: + curr =3D &ring_err_stats.rx_total_l4_csum_errors; + prev =3D &bn->ring_err_stats_prev.rx_total_l4_csum_errors; + for (i =3D 0; i < BNGE_NUM_RING_ERR_STATS; i++, j++, curr++, prev++) + buf[j] =3D *curr + *prev; + + if (bn->flags & BNGE_FLAG_PORT_STATS) { + u64 *port_stats =3D bn->port_stats.sw_stats; + + for (i =3D 0; i < BNGE_NUM_PORT_STATS; i++, j++) + buf[j] =3D *(port_stats + bnge_port_stats_arr[i].offset); + } + if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) { + u64 *rx_port_stats_ext =3D bn->rx_port_stats_ext.sw_stats; + u64 *tx_port_stats_ext =3D bn->tx_port_stats_ext.sw_stats; + u32 len; + + len =3D min_t(u32, bn->fw_rx_stats_ext_size, + ARRAY_SIZE(bnge_port_stats_ext_arr)); + for (i =3D 0; i < len; i++, j++) { + buf[j] =3D *(rx_port_stats_ext + + bnge_port_stats_ext_arr[i].offset); + } + len =3D min_t(u32, bn->fw_tx_stats_ext_size, + ARRAY_SIZE(bnge_tx_port_stats_ext_arr)); + for (i =3D 0; i < len; i++, j++) { + buf[j] =3D *(tx_port_stats_ext + + bnge_tx_port_stats_ext_arr[i].offset); + } + if (bn->pri2cos_valid) { + for (i =3D 0; i < 8; i++, j++) { + long n =3D bnge_rx_bytes_pri_arr[i].base_off + + bn->pri2cos_idx[i]; + + buf[j] =3D *(rx_port_stats_ext + n); + } + for (i =3D 0; i < 8; i++, j++) { + long n =3D bnge_rx_pkts_pri_arr[i].base_off + + bn->pri2cos_idx[i]; + + buf[j] =3D *(rx_port_stats_ext + n); + } + for (i =3D 0; i < 8; i++, j++) { + long n =3D bnge_tx_bytes_pri_arr[i].base_off + + bn->pri2cos_idx[i]; + + buf[j] =3D *(tx_port_stats_ext + n); + } + for (i =3D 0; i < 8; i++, j++) { + long n =3D bnge_tx_pkts_pri_arr[i].base_off + + bn->pri2cos_idx[i]; + + buf[j] =3D *(tx_port_stats_ext + n); + } + } + } +} + +static void bnge_get_strings(struct net_device *dev, u32 stringset, u8 *bu= f) +{ + struct bnge_net *bn =3D netdev_priv(dev); + struct bnge_dev *bd =3D bn->bd; + u32 i, j, num_str; + const char *str; + + switch (stringset) { + case ETH_SS_STATS: + for (i =3D 0; i < bd->nq_nr_rings; i++) { + if (is_rx_ring(bd, i)) + for (j =3D 0; j < NUM_RING_RX_HW_STATS; j++) { + str =3D bnge_ring_rx_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } + if (is_tx_ring(bd, i)) + for (j =3D 0; j < NUM_RING_TX_HW_STATS; j++) { + str =3D bnge_ring_tx_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } + num_str =3D bnge_get_num_tpa_ring_stats(bd); + if (!num_str || !is_rx_ring(bd, i)) + goto skip_tpa_stats; + + if (bd->max_tpa_v2) + for (j =3D 0; j < num_str; j++) { + str =3D bnge_ring_tpa2_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } + else + for (j =3D 0; j < num_str; j++) { + str =3D bnge_ring_tpa_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } +skip_tpa_stats: + if (is_rx_ring(bd, i)) + for (j =3D 0; j < NUM_RING_RX_SW_STATS; j++) { + str =3D bnge_rx_sw_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } + } + for (i =3D 0; i < BNGE_NUM_RING_ERR_STATS; i++) + ethtool_puts(&buf, bnge_ring_err_stats_arr[i]); + + if (bn->flags & BNGE_FLAG_PORT_STATS) + for (i =3D 0; i < BNGE_NUM_PORT_STATS; i++) { + str =3D bnge_port_stats_arr[i].string; + ethtool_puts(&buf, str); + } + + if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) { + u32 len; + + len =3D min_t(u32, bn->fw_rx_stats_ext_size, + ARRAY_SIZE(bnge_port_stats_ext_arr)); + for (i =3D 0; i < len; i++) { + str =3D bnge_port_stats_ext_arr[i].string; + ethtool_puts(&buf, str); + } + + len =3D min_t(u32, bn->fw_tx_stats_ext_size, + ARRAY_SIZE(bnge_tx_port_stats_ext_arr)); + for (i =3D 0; i < len; i++) { + str =3D bnge_tx_port_stats_ext_arr[i].string; + ethtool_puts(&buf, str); + } + + if (bn->pri2cos_valid) { + for (i =3D 0; i < 8; i++) { + str =3D bnge_rx_bytes_pri_arr[i].string; + ethtool_puts(&buf, str); + } + + for (i =3D 0; i < 8; i++) { + str =3D bnge_rx_pkts_pri_arr[i].string; + ethtool_puts(&buf, str); + } + + for (i =3D 0; i < 8; i++) { + str =3D bnge_tx_bytes_pri_arr[i].string; + ethtool_puts(&buf, str); + } + + for (i =3D 0; i < 8; i++) { + str =3D bnge_tx_pkts_pri_arr[i].string; + ethtool_puts(&buf, str); + } + } + } + break; + default: + netdev_err(bd->netdev, "%s invalid request %x\n", + __func__, stringset); + break; + } } =20 static const struct ethtool_ops bnge_ethtool_ops =3D { @@ -49,6 +652,9 @@ static const struct ethtool_ops bnge_ethtool_ops =3D { .get_drvinfo =3D bnge_get_drvinfo, .get_link =3D bnge_get_link, .nway_reset =3D bnge_nway_reset, + .get_sset_count =3D bnge_get_sset_count, + .get_strings =3D bnge_get_strings, + .get_ethtool_stats =3D bnge_get_ethtool_stats, }; =20 void bnge_set_ethtool_ops(struct net_device *dev) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c b/drivers/n= et/ethernet/broadcom/bnge/bnge_hwrm_lib.c index 43d5ba15728..139fc7c2f73 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c @@ -14,6 +14,7 @@ #include "bnge_hwrm_lib.h" #include "bnge_rmem.h" #include "bnge_resc.h" +#include "bnge_netdev.h" =20 static const u16 bnge_async_events_arr[] =3D { ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE, @@ -610,6 +611,8 @@ int bnge_hwrm_func_qcaps(struct bnge_dev *bd) bd->flags |=3D BNGE_EN_ROCE_V1; if (flags & FUNC_QCAPS_RESP_FLAGS_ROCE_V2_SUPPORTED) bd->flags |=3D BNGE_EN_ROCE_V2; + if (flags & FUNC_QCAPS_RESP_FLAGS_EXT_STATS_SUPPORTED) + bd->fw_cap |=3D BNGE_FW_CAP_EXT_STATS_SUPPORTED; =20 pf->fw_fid =3D le16_to_cpu(resp->fid); pf->port_id =3D le16_to_cpu(resp->port_id); @@ -1488,3 +1491,142 @@ int bnge_hwrm_vnic_set_tpa(struct bnge_dev *bd, str= uct bnge_vnic_info *vnic, =20 return bnge_hwrm_req_send(bd, req); } + +int bnge_hwrm_func_qstat_ext(struct bnge_dev *bd, struct bnge_stats_mem *s= tats) +{ + struct hwrm_func_qstats_ext_output *resp; + struct hwrm_func_qstats_ext_input *req; + __le64 *hw_masks; + int rc; + + rc =3D bnge_hwrm_req_init(bd, req, HWRM_FUNC_QSTATS_EXT); + if (rc) + return rc; + + req->fid =3D cpu_to_le16(0xffff); + req->flags =3D FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK; + + resp =3D bnge_hwrm_req_hold(bd, req); + rc =3D bnge_hwrm_req_send(bd, req); + if (!rc) { + hw_masks =3D &resp->rx_ucast_pkts; + bnge_copy_hw_masks(stats->hw_masks, hw_masks, stats->len / 8); + } + bnge_hwrm_req_drop(bd, req); + return rc; +} + +int bnge_hwrm_port_qstats_ext(struct bnge_dev *bd, u8 flags) +{ + struct hwrm_queue_pri2cos_qcfg_output *resp_qc; + struct bnge_net *bn =3D netdev_priv(bd->netdev); + struct hwrm_queue_pri2cos_qcfg_input *req_qc; + struct hwrm_port_qstats_ext_output *resp_qs; + struct hwrm_port_qstats_ext_input *req_qs; + struct bnge_pf_info *pf =3D &bd->pf; + u32 tx_stat_size; + int rc; + + if (!(bn->flags & BNGE_FLAG_PORT_STATS_EXT)) + return 0; + + if (flags && !(bd->fw_cap & BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED)) + return -EOPNOTSUPP; + + rc =3D bnge_hwrm_req_init(bd, req_qs, HWRM_PORT_QSTATS_EXT); + if (rc) + return rc; + + req_qs->flags =3D flags; + req_qs->port_id =3D cpu_to_le16(pf->port_id); + req_qs->rx_stat_size =3D cpu_to_le16(sizeof(struct rx_port_stats_ext)); + req_qs->rx_stat_host_addr =3D + cpu_to_le64(bn->rx_port_stats_ext.hw_stats_map); + tx_stat_size =3D bn->tx_port_stats_ext.hw_stats ? + sizeof(struct tx_port_stats_ext) : 0; + req_qs->tx_stat_size =3D cpu_to_le16(tx_stat_size); + req_qs->tx_stat_host_addr =3D + cpu_to_le64(bn->tx_port_stats_ext.hw_stats_map); + resp_qs =3D bnge_hwrm_req_hold(bd, req_qs); + rc =3D bnge_hwrm_req_send(bd, req_qs); + if (!rc) { + bn->fw_rx_stats_ext_size =3D + le16_to_cpu(resp_qs->rx_stat_size) / 8; + bn->fw_tx_stats_ext_size =3D tx_stat_size ? + le16_to_cpu(resp_qs->tx_stat_size) / 8 : 0; + } else { + bn->fw_rx_stats_ext_size =3D 0; + bn->fw_tx_stats_ext_size =3D 0; + } + bnge_hwrm_req_drop(bd, req_qs); + + if (flags) + return rc; + + if (bn->fw_tx_stats_ext_size <=3D + offsetof(struct tx_port_stats_ext, pfc_pri0_tx_duration_us) / 8) { + bn->pri2cos_valid =3D false; + return rc; + } + + rc =3D bnge_hwrm_req_init(bd, req_qc, HWRM_QUEUE_PRI2COS_QCFG); + if (rc) + return rc; + + req_qc->flags =3D cpu_to_le32(QUEUE_PRI2COS_QCFG_REQ_FLAGS_IVLAN); + + resp_qc =3D bnge_hwrm_req_hold(bd, req_qc); + rc =3D bnge_hwrm_req_send(bd, req_qc); + if (!rc) { + u8 *pri2cos; + int i, j; + + pri2cos =3D &resp_qc->pri0_cos_queue_id; + for (i =3D 0; i < 8; i++) { + u8 queue_id =3D pri2cos[i]; + u8 queue_idx; + + /* Per port queue IDs start from 0, 10, 20, etc */ + queue_idx =3D queue_id % 10; + if (queue_idx > BNGE_MAX_QUEUE) { + bn->pri2cos_valid =3D false; + bnge_hwrm_req_drop(bd, req_qc); + return rc; + } + for (j =3D 0; j < bd->max_q; j++) { + if (bd->q_ids[j] =3D=3D queue_id) + bn->pri2cos_idx[i] =3D queue_idx; + } + } + bn->pri2cos_valid =3D true; + } + bnge_hwrm_req_drop(bd, req_qc); + + return rc; +} + +int bnge_hwrm_port_qstats(struct bnge_dev *bd, u8 flags) +{ + struct bnge_net *bn =3D netdev_priv(bd->netdev); + struct hwrm_port_qstats_input *req; + struct bnge_pf_info *pf =3D &bd->pf; + int rc; + + if (!(bn->flags & BNGE_FLAG_PORT_STATS)) + return 0; + + if (flags && !(bd->fw_cap & BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED)) + return -EOPNOTSUPP; + + rc =3D bnge_hwrm_req_init(bd, req, HWRM_PORT_QSTATS); + if (rc) + return rc; + + req->flags =3D flags; + req->port_id =3D cpu_to_le16(pf->port_id); + req->tx_stat_host_addr =3D cpu_to_le64(bn->port_stats.hw_stats_map + + BNGE_TX_PORT_STATS_BYTE_OFFSET); + req->rx_stat_host_addr =3D cpu_to_le64(bn->port_stats.hw_stats_map); + + return bnge_hwrm_req_send(bd, req); +} diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h b/drivers/n= et/ethernet/broadcom/bnge/bnge_hwrm_lib.h index 86ca3ac2244..3501de7a89b 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h @@ -62,4 +62,7 @@ int bnge_hwrm_phy_qcaps(struct bnge_dev *bd); int bnge_hwrm_set_link_setting(struct bnge_net *bn, bool set_pause); int bnge_hwrm_set_pause(struct bnge_net *bn); int bnge_hwrm_shutdown_link(struct bnge_dev *bd); +int bnge_hwrm_port_qstats(struct bnge_dev *bd, u8 flags); +int bnge_hwrm_port_qstats_ext(struct bnge_dev *bd, u8 flags); +int bnge_hwrm_func_qstat_ext(struct bnge_dev *bd, struct bnge_stats_mem *s= tats); #endif /* _BNGE_HWRM_LIB_H_ */ diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.c index 4909727547e..6589fbdb47f 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -39,6 +39,10 @@ static void bnge_free_stats_mem(struct bnge_net *bn, { struct bnge_dev *bd =3D bn->bd; =20 + kfree(stats->hw_masks); + stats->hw_masks =3D NULL; + kfree(stats->sw_stats); + stats->sw_stats =3D NULL; if (stats->hw_stats) { dma_free_coherent(bd->dev, stats->len, stats->hw_stats, stats->hw_stats_map); @@ -47,7 +51,7 @@ static void bnge_free_stats_mem(struct bnge_net *bn, } =20 static int bnge_alloc_stats_mem(struct bnge_net *bn, - struct bnge_stats_mem *stats) + struct bnge_stats_mem *stats, bool alloc_masks) { struct bnge_dev *bd =3D bn->bd; =20 @@ -56,7 +60,20 @@ static int bnge_alloc_stats_mem(struct bnge_net *bn, if (!stats->hw_stats) return -ENOMEM; =20 + stats->sw_stats =3D kzalloc(stats->len, GFP_KERNEL); + if (!stats->sw_stats) + goto stats_mem_err; + + if (alloc_masks) { + stats->hw_masks =3D kzalloc(stats->len, GFP_KERNEL); + if (!stats->hw_masks) + goto stats_mem_err; + } return 0; + +stats_mem_err: + bnge_free_stats_mem(bn, stats); + return -ENOMEM; } =20 static void bnge_free_ring_stats(struct bnge_net *bn) @@ -72,7 +89,111 @@ static void bnge_free_ring_stats(struct bnge_net *bn) struct bnge_nq_ring_info *nqr =3D &bnapi->nq_ring; =20 bnge_free_stats_mem(bn, &nqr->stats); + + kfree(nqr->sw_stats); + nqr->sw_stats =3D NULL; + } +} + +static void bnge_fill_masks(u64 *mask_arr, u64 mask, int count) +{ + int i; + + for (i =3D 0; i < count; i++) + mask_arr[i] =3D mask; +} + +void bnge_copy_hw_masks(u64 *mask_arr, __le64 *hw_mask_arr, int count) +{ + int i; + + for (i =3D 0; i < count; i++) + mask_arr[i] =3D le64_to_cpu(hw_mask_arr[i]); +} + +static void bnge_init_stats(struct bnge_net *bn) +{ + struct bnge_napi *bnapi =3D bn->bnapi[0]; + struct bnge_nq_ring_info *nqr; + struct bnge_stats_mem *stats; + struct bnge_dev *bd =3D bn->bd; + __le64 *rx_stats, *tx_stats; + int rc, rx_count, tx_count; + u64 *rx_masks, *tx_masks; + u8 flags; + + nqr =3D &bnapi->nq_ring; + stats =3D &nqr->stats; + rc =3D bnge_hwrm_func_qstat_ext(bd, stats); + if (rc) { + u64 mask =3D (1ULL << 48) - 1; + + bnge_fill_masks(stats->hw_masks, mask, stats->len / 8); } + + if (bn->flags & BNGE_FLAG_PORT_STATS) { + stats =3D &bn->port_stats; + rx_stats =3D stats->hw_stats; + rx_masks =3D stats->hw_masks; + rx_count =3D sizeof(struct rx_port_stats) / 8; + tx_stats =3D rx_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + tx_masks =3D rx_masks + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + tx_count =3D sizeof(struct tx_port_stats) / 8; + + flags =3D PORT_QSTATS_REQ_FLAGS_COUNTER_MASK; + rc =3D bnge_hwrm_port_qstats(bd, flags); + if (rc) { + u64 mask =3D (1ULL << 40) - 1; + + bnge_fill_masks(rx_masks, mask, rx_count); + bnge_fill_masks(tx_masks, mask, tx_count); + } else { + bnge_copy_hw_masks(rx_masks, rx_stats, rx_count); + bnge_copy_hw_masks(tx_masks, tx_stats, tx_count); + bnge_hwrm_port_qstats(bd, 0); + } + } + + if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) { + stats =3D &bn->rx_port_stats_ext; + rx_stats =3D stats->hw_stats; + rx_masks =3D stats->hw_masks; + rx_count =3D sizeof(struct rx_port_stats_ext) / 8; + stats =3D &bn->tx_port_stats_ext; + tx_stats =3D stats->hw_stats; + tx_masks =3D stats->hw_masks; + tx_count =3D sizeof(struct tx_port_stats_ext) / 8; + + flags =3D PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK; + rc =3D bnge_hwrm_port_qstats_ext(bd, flags); + if (rc) { + u64 mask =3D (1ULL << 40) - 1; + + bnge_fill_masks(rx_masks, mask, rx_count); + if (tx_stats) + bnge_fill_masks(tx_masks, mask, tx_count); + } else { + bnge_copy_hw_masks(rx_masks, rx_stats, rx_count); + if (tx_stats) + bnge_copy_hw_masks(tx_masks, tx_stats, + tx_count); + bnge_hwrm_port_qstats_ext(bd, 0); + } + } +} + +static void bnge_free_port_ext_stats(struct bnge_net *bn) +{ + bn->flags &=3D ~BNGE_FLAG_PORT_STATS_EXT; + bnge_free_stats_mem(bn, &bn->rx_port_stats_ext); + bnge_free_stats_mem(bn, &bn->tx_port_stats_ext); +} + +static void bnge_free_port_stats(struct bnge_net *bn) +{ + bn->flags &=3D ~BNGE_FLAG_PORT_STATS; + bnge_free_stats_mem(bn, &bn->port_stats); + bnge_free_port_ext_stats(bn); } =20 static int bnge_alloc_ring_stats(struct bnge_net *bn) @@ -87,13 +208,84 @@ static int bnge_alloc_ring_stats(struct bnge_net *bn) struct bnge_napi *bnapi =3D bn->bnapi[i]; struct bnge_nq_ring_info *nqr =3D &bnapi->nq_ring; =20 + nqr->sw_stats =3D kzalloc(sizeof(*nqr->sw_stats), GFP_KERNEL); + if (!nqr->sw_stats) { + rc =3D -ENOMEM; + goto err_free_ring_stats; + } + nqr->stats.len =3D size; - rc =3D bnge_alloc_stats_mem(bn, &nqr->stats); + rc =3D bnge_alloc_stats_mem(bn, &nqr->stats, !i); if (rc) goto err_free_ring_stats; =20 nqr->hw_stats_ctx_id =3D INVALID_STATS_CTX_ID; } + + return 0; + +err_free_ring_stats: + bnge_free_ring_stats(bn); + return rc; +} + +static void bnge_alloc_port_ext_stats(struct bnge_net *bn) +{ + struct bnge_dev *bd =3D bn->bd; + int rc; + + if (!(bd->fw_cap & BNGE_FW_CAP_EXT_STATS_SUPPORTED)) + return; + + if (!bn->rx_port_stats_ext.hw_stats) { + bn->rx_port_stats_ext.len =3D sizeof(struct rx_port_stats_ext); + rc =3D bnge_alloc_stats_mem(bn, &bn->rx_port_stats_ext, true); + /* Extended stats are optional */ + if (rc) + return; + } + + if (!bn->tx_port_stats_ext.hw_stats) { + bn->tx_port_stats_ext.len =3D sizeof(struct tx_port_stats_ext); + rc =3D bnge_alloc_stats_mem(bn, &bn->tx_port_stats_ext, true); + /* Extended stats are optional */ + if (rc) { + bnge_free_port_ext_stats(bn); + return; + } + } + bn->flags |=3D BNGE_FLAG_PORT_STATS_EXT; +} + +static int bnge_alloc_port_stats(struct bnge_net *bn) +{ + int rc; + + if (!bn->port_stats.hw_stats) { + bn->port_stats.len =3D BNGE_PORT_STATS_SIZE; + rc =3D bnge_alloc_stats_mem(bn, &bn->port_stats, true); + if (rc) + return rc; + + bn->flags |=3D BNGE_FLAG_PORT_STATS; + } + + bnge_alloc_port_ext_stats(bn); + return 0; +} + +static int bnge_alloc_stats(struct bnge_net *bn) +{ + int rc; + + rc =3D bnge_alloc_ring_stats(bn); + if (rc) + return rc; + + rc =3D bnge_alloc_port_stats(bn); + if (rc) + goto err_free_ring_stats; + return 0; =20 err_free_ring_stats: @@ -952,6 +1144,7 @@ static void bnge_free_core(struct bnge_net *bn) bnge_free_nq_tree(bn); bnge_free_nq_arrays(bn); bnge_free_ring_stats(bn); + bnge_free_port_stats(bn); bnge_free_ring_grps(bn); bnge_free_vnics(bn); kfree(bn->tx_ring_map); @@ -1040,10 +1233,12 @@ static int bnge_alloc_core(struct bnge_net *bn) txr->bnapi =3D bnapi2; } =20 - rc =3D bnge_alloc_ring_stats(bn); + rc =3D bnge_alloc_stats(bn); if (rc) goto err_free_core; =20 + bnge_init_stats(bn); + rc =3D bnge_alloc_vnics(bn); if (rc) goto err_free_core; @@ -2686,6 +2881,34 @@ static int bnge_close(struct net_device *dev) return 0; } =20 +static void bnge_get_one_ring_err_stats(struct bnge_total_ring_err_stats *= stats, + struct bnge_nq_ring_info *nqr) +{ + struct bnge_sw_stats *sw_stats =3D nqr->sw_stats; + u64 *hw_stats =3D nqr->stats.sw_stats; + + stats->rx_total_l4_csum_errors +=3D sw_stats->rx.rx_l4_csum_errors; + stats->rx_total_resets +=3D sw_stats->rx.rx_resets; + stats->rx_total_buf_errors +=3D sw_stats->rx.rx_buf_errors; + stats->rx_total_oom_discards +=3D sw_stats->rx.rx_oom_discards; + stats->rx_total_netpoll_discards +=3D sw_stats->rx.rx_netpoll_discards; + stats->rx_total_ring_discards +=3D + BNGE_GET_RING_STATS64(hw_stats, rx_discard_pkts); + stats->tx_total_resets +=3D sw_stats->tx.tx_resets; + stats->tx_total_ring_discards +=3D + BNGE_GET_RING_STATS64(hw_stats, tx_discard_pkts); +} + +void bnge_get_ring_err_stats(struct bnge_net *bn, + struct bnge_total_ring_err_stats *stats) +{ + int i; + + for (i =3D 0; i < bn->bd->nq_nr_rings; i++) + bnge_get_one_ring_err_stats(stats, + &bn->bnapi[i]->nq_ring); +} + static const struct net_device_ops bnge_netdev_ops =3D { .ndo_open =3D bnge_open, .ndo_stop =3D bnge_close, diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.h index 041ef5792f6..65cbdcc9d30 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -224,6 +224,63 @@ struct bnge_tpa_info { #define BNGE_NQ_HDL_IDX(hdl) ((hdl) & BNGE_NQ_HDL_IDX_MASK) #define BNGE_NQ_HDL_TYPE(hdl) (((hdl) & BNGE_NQ_HDL_TYPE_MASK) >> \ BNGE_NQ_HDL_TYPE_SHIFT) +#define BNGE_GET_RING_STATS64(sw, counter) \ + (*((sw) + offsetof(struct ctx_hw_stats, counter) / 8)) + +#define BNGE_PORT_STATS_SIZE \ + (sizeof(struct rx_port_stats) + sizeof(struct tx_port_stats) + 1024) + +#define BNGE_TX_PORT_STATS_BYTE_OFFSET \ + (sizeof(struct rx_port_stats) + 512) + +#define BNGE_RX_STATS_OFFSET(counter) \ + (offsetof(struct rx_port_stats, counter) / 8) + +#define BNGE_TX_STATS_OFFSET(counter) \ + ((offsetof(struct tx_port_stats, counter) + \ + BNGE_TX_PORT_STATS_BYTE_OFFSET) / 8) + +#define BNGE_RX_STATS_EXT_OFFSET(counter) \ + (offsetof(struct rx_port_stats_ext, counter) / 8) + +#define BNGE_TX_STATS_EXT_OFFSET(counter) \ + (offsetof(struct tx_port_stats_ext, counter) / 8) + +struct bnge_total_ring_err_stats { + u64 rx_total_l4_csum_errors; + u64 rx_total_resets; + u64 rx_total_buf_errors; + u64 rx_total_oom_discards; + u64 rx_total_netpoll_discards; + u64 rx_total_ring_discards; + u64 tx_total_resets; + u64 tx_total_ring_discards; +}; + +struct bnge_rx_sw_stats { + u64 rx_l4_csum_errors; + u64 rx_resets; + u64 rx_buf_errors; + u64 rx_oom_discards; + u64 rx_netpoll_discards; +}; + +struct bnge_tx_sw_stats { + u64 tx_resets; +}; + +struct bnge_stats_mem { + u64 *sw_stats; + u64 *hw_masks; + void *hw_stats; + dma_addr_t hw_stats_map; + int len; +}; + +struct bnge_sw_stats { + struct bnge_rx_sw_stats rx; + struct bnge_tx_sw_stats tx; +}; =20 enum bnge_net_state { BNGE_STATE_NAPI_DISABLED, @@ -232,6 +289,11 @@ enum bnge_net_state { =20 #define BNGE_TIMER_INTERVAL HZ =20 +enum bnge_net_flag { + BNGE_FLAG_PORT_STATS =3D BIT(0), + BNGE_FLAG_PORT_STATS_EXT =3D BIT(1), +}; + enum bnge_sp_event { BNGE_LINK_CHNG_SP_EVENT, BNGE_LINK_SPEED_CHNG_SP_EVENT, @@ -311,6 +373,19 @@ struct bnge_net { unsigned long sp_event; =20 struct bnge_ethtool_link_info eth_link_info; + + u64 flags; + + struct bnge_total_ring_err_stats ring_err_stats_prev; + + struct bnge_stats_mem port_stats; + struct bnge_stats_mem rx_port_stats_ext; + struct bnge_stats_mem tx_port_stats_ext; + u16 fw_rx_stats_ext_size; + u16 fw_tx_stats_ext_size; + + u8 pri2cos_idx[8]; + bool pri2cos_valid; }; =20 #define BNGE_DEFAULT_RX_RING_SIZE 511 @@ -376,14 +451,6 @@ void bnge_set_ring_params(struct bnge_dev *bd); bnge_writeq(bd, (db)->db_key64 | DBR_TYPE_NQ_ARM | \ DB_RING_IDX(db, idx), (db)->doorbell) =20 -struct bnge_stats_mem { - u64 *sw_stats; - u64 *hw_masks; - void *hw_stats; - dma_addr_t hw_stats_map; - int len; -}; - struct nqe_cn { __le16 type; #define NQ_CN_TYPE_MASK 0x3fUL @@ -427,6 +494,7 @@ struct bnge_nq_ring_info { struct bnge_db_info nq_db; =20 struct bnge_stats_mem stats; + struct bnge_sw_stats *sw_stats; u32 hw_stats_ctx_id; bool has_more_work; =20 @@ -595,4 +663,7 @@ u8 *__bnge_alloc_rx_frag(struct bnge_net *bn, dma_addr_= t *mapping, int bnge_alloc_rx_netmem(struct bnge_net *bn, struct bnge_rx_ring_info *rx= r, u16 prod, gfp_t gfp); void __bnge_queue_sp_work(struct bnge_net *bn); +void bnge_get_ring_err_stats(struct bnge_net *bn, + struct bnge_total_ring_err_stats *stats); +void bnge_copy_hw_masks(u64 *mask_arr, __le64 *hw_mask_arr, int count); #endif /* _BNGE_NETDEV_H_ */ --=20 2.47.3 From nobody Sun Apr 5 18:20:21 2026 Received: from mail-pf1-f227.google.com (mail-pf1-f227.google.com [209.85.210.227]) (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 1C6E93271EA for ; Mon, 23 Feb 2026 16:37:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.227 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864677; cv=none; b=fjXTpVbxaSg1kx36s+SD7TYSPAyUj/eByXYsV4ooR0BhIxcfMSXCRj4SZTNphsL/s/lKdnDAFVqsNv5WhJbAVrYZf/+SEvpHwvbvde4a39RmOf5MJTKytrr9SF0oYFB+wxmF43hvp6yce0GtmfHy69gq0gQ/YBTyCTUEoFQ8U+M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864677; c=relaxed/simple; bh=AdKt8wrJmv4nluSRJ1kG2mGHhXNw88ryp6gQeexchcs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lKIXVlplY7WJyzs27+xZBMEIuuz+WTSPuNpuPL+w4gDqCA4mkPAdgLJ6gZ9qiBl22GUJGYkN4rrNi8I0KuqeZ36h0ky78nE/VD87NQZw1LQJlKmnFCxhC1Hz3/E9lgO1UyysWQBIfLbHZ3c0qDS8/praaNpStpZAzrm+wHin1Fs= 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=aCGcL5YH; arc=none smtp.client-ip=209.85.210.227 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="aCGcL5YH" Received: by mail-pf1-f227.google.com with SMTP id d2e1a72fcca58-824b05d2786so3407333b3a.2 for ; Mon, 23 Feb 2026 08:37:55 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771864675; x=1772469475; 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=mi7jWd0C81kE5nB7PeuEALk1pyyWsZNcqCAZ39HdnzE=; b=iFoXnABt3iXyjtLwTkVi4+mVcMFintcgNsRR1/ccl6vEhY4Go4JxFif4JLX8bX1vU6 2Meb9IeVMpZMoRfAPYtgleJpOA0BYtd+GzEzA+qsfAu+L1gNOnYnPXtxsuxYVfp7SfGt qGiAGSfElt8reWDUsb4YFF4PQxcuLDyRO3NqIyCurbcB6y90p7epiM9A28nXwzSv8mkR KOb5ANs/rUIaQlSVHz6f5SIoaWpl8LY5ii26jSH33KOcLR6+XjlNUSUQGJgkR7xdc0jB MbwWQOXSWDtkeQAbuanqkMSCwrp/ui6qHjOP3szFtd6+wPkW3btQWLsrIK0RqzD47KE0 CVYQ== X-Forwarded-Encrypted: i=1; AJvYcCXxLxGzyO19lt7F0c87iDQXcUlzfH0FoVS1TLMIvNDSsII0k5uWwrsuCntyNWfieIf1URs7pggtwJ7J1Kc=@vger.kernel.org X-Gm-Message-State: AOJu0YyN92nNOxUa29s1LUjtOKQ0xCxVP9CQ0ocUEgzIr+pzLjE9wUTk uK7ppCSWVe4/GgaxqN6OgFmQg6Dp9ZnSB3c7pJiDmHKgSTWeFV3bwBDLvGBWeUePZOjPLjfNCFH MCccrGeCp6E7IeEwTlB8VBFJsOBJv9ZvZfxC7a6gkzdbOSC19B/y+K+ltXe1iBsoXl/ExRXWxgK 8WIZ0XvFChEcnYt+vOt1vPdJvl1VcOiUSQ2lBsISUqSVrQ/em8O63lHXmLtoXf1O2lsMQqCGgKw ooEoVGSJHJy6mHHlLbH6T2Atg== X-Gm-Gg: AZuq6aIrF5iLGXgBpVgxaNCT7X5RiprJa9GBEo+eSNDIO3lVDsyOz0kFhKjYukTy3Gn B18nKJu3aPvpZx6rAgOy5N6sfCmYEWKkUvFwe29ujpr4ZjZG9pWvnz66f/+Uwr2j5wWdfmn8ZRb Ix83stt4eM/78l5l04KnJ6zTG7AFNqV7E8iie33KVc7zjellUAT1zcbk0O5gXnKk/xLXzI5ohjO ngiwWsOFm41eEd7sdHsI1ZuNS91JU46JZTSHifE5sqtQdyRNl3oJmTtN4P3M7YTFtek5RuI/3Hf 9DlGZ5e81h5xEOfv6Atcwjt8VdMIk4KoSSvJqsgIqSyVxgeFfmndxc2077CjoLc/ss+nzCZ/6sb j0l75VzHVuqFhy2RrKx6p237EDvw43dADAPn+o6OnM9DUx90unPuWZbvxcGpzcHKbEqIe6pilTR 06xi+yhUKE2AFGeEw026An/FQBK5muHg5/0d8OJA1F+ywAatHi5xZQex4UKINN2P8bDA== X-Received: by 2002:aa7:8892:0:b0:81a:b183:44fc with SMTP id d2e1a72fcca58-826da906ffcmr7576321b3a.23.1771864675342; Mon, 23 Feb 2026 08:37:55 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-103.dlp.protect.broadcom.com. [144.49.247.103]) by smtp-relay.gmail.com with ESMTPS id d2e1a72fcca58-826dd875617sm972341b3a.9.2026.02.23.08.37.54 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2026 08:37:55 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-2a7b7f04a11so332879115ad.3 for ; Mon, 23 Feb 2026 08:37:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1771864673; x=1772469473; 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=mi7jWd0C81kE5nB7PeuEALk1pyyWsZNcqCAZ39HdnzE=; b=aCGcL5YHUPBxa4M3U4+iDHT1t1DcLe3M6J7lN8zZ4Ll906NLg/fyWKwieqlI8Pxdgy 2dynVHEsGRXYe5K3qM9jyFbRWbbhr5AdlF2LshgC3H0y1ctULuIlLZoueAyJURrTew/L 9J4khxRkDSPydWk0vJ0sDDG6XayrTgNsXZERs= X-Forwarded-Encrypted: i=1; AJvYcCWYSbQKaHQEszWbR+PiR9qFrlAT1I0VJ9wzTWXbkKoo0gkaGSIX2dKHP24bPCbkAU26AVo7RYzBsrQY/eo=@vger.kernel.org X-Received: by 2002:a17:903:f87:b0:2a0:8be7:e3d7 with SMTP id d9443c01a7336-2ad7456f999mr66521005ad.57.1771864673457; Mon, 23 Feb 2026 08:37:53 -0800 (PST) X-Received: by 2002:a17:903:f87:b0:2a0:8be7:e3d7 with SMTP id d9443c01a7336-2ad7456f999mr66520845ad.57.1771864673038; Mon, 23 Feb 2026 08:37:53 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ad74e3445fsm96763825ad.13.2026.02.23.08.37.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 08:37:52 -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 , Rahul Gupta , Ajit Kumar Khaparde Subject: [PATCH net-next 6/7] bng_en: periodically fetch and accumulate hardware statistics Date: Mon, 23 Feb 2026 22:06:40 +0530 Message-ID: <20260223163641.755200-7-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260223163641.755200-1-bhargava.marreddy@broadcom.com> References: <20260223163641.755200-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" Use the timer to schedule periodic stats collection via the workqueue when the link is up. Fetch fresh counters from hardware via DMA and accumulate them into 64-bit software shadows, handling wrap-around for counters narrower than 64 bits. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Rahul Gupta Reviewed-by: Ajit Kumar Khaparde --- .../net/ethernet/broadcom/bnge/bnge_netdev.c | 90 +++++++++++++++++++ .../net/ethernet/broadcom/bnge/bnge_netdev.h | 1 + 2 files changed, 91 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.c index 6589fbdb47f..e2715419b6f 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -325,10 +325,94 @@ static void bnge_timer(struct timer_list *t) } } =20 + if (BNGE_LINK_IS_UP(bd) && bn->stats_coal_ticks) + bnge_queue_sp_work(bn, BNGE_PERIODIC_STATS_SP_EVENT); + bnge_restart_timer: mod_timer(&bn->timer, jiffies + bn->current_interval); } =20 +static void bnge_add_one_ctr(u64 hw, u64 *sw, u64 mask) +{ + u64 sw_tmp, sw_val; + + hw &=3D mask; + sw_val =3D READ_ONCE(*sw); + sw_tmp =3D (sw_val & ~mask) | hw; + if (hw < (sw_val & mask)) + sw_tmp +=3D mask + 1; + WRITE_ONCE(*sw, sw_tmp); +} + +static void __bnge_accumulate_stats(__le64 *hw_stats, u64 *sw_stats, u64 *= masks, + int count) +{ + int i; + + for (i =3D 0; i < count; i++) { + u64 hw =3D le64_to_cpu(READ_ONCE(hw_stats[i])); + + if (masks[i] =3D=3D -1ULL) + sw_stats[i] =3D hw; + else + bnge_add_one_ctr(hw, &sw_stats[i], masks[i]); + } +} + +static void bnge_accumulate_stats(struct bnge_stats_mem *stats) +{ + if (!stats->hw_stats) + return; + + __bnge_accumulate_stats(stats->hw_stats, stats->sw_stats, + stats->hw_masks, stats->len / 8); +} + +static void bnge_accumulate_all_stats(struct bnge_dev *bd) +{ + struct bnge_net *bn =3D netdev_priv(bd->netdev); + struct bnge_stats_mem *ring0_stats =3D NULL; + int i; + + for (i =3D 0; i < bd->nq_nr_rings; i++) { + struct bnge_napi *bnapi =3D bn->bnapi[i]; + struct bnge_nq_ring_info *nqr; + struct bnge_stats_mem *stats; + + nqr =3D &bnapi->nq_ring; + stats =3D &nqr->stats; + + if (!ring0_stats) + ring0_stats =3D &bn->bnapi[0]->nq_ring.stats; + + __bnge_accumulate_stats(stats->hw_stats, stats->sw_stats, + ring0_stats->hw_masks, + ring0_stats->len / 8); + } + + if (bn->flags & BNGE_FLAG_PORT_STATS) { + struct bnge_stats_mem *stats =3D &bn->port_stats; + __le64 *hw_stats =3D stats->hw_stats; + u64 *sw_stats =3D stats->sw_stats; + u64 *masks =3D stats->hw_masks; + int cnt; + + cnt =3D sizeof(struct rx_port_stats) / 8; + __bnge_accumulate_stats(hw_stats, sw_stats, masks, cnt); + + hw_stats +=3D BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + sw_stats +=3D BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + masks +=3D BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + cnt =3D sizeof(struct tx_port_stats) / 8; + __bnge_accumulate_stats(hw_stats, sw_stats, masks, cnt); + } + + if (bn->flags & BNGE_FLAG_PORT_STATS_EXT) { + bnge_accumulate_stats(&bn->rx_port_stats_ext); + bnge_accumulate_stats(&bn->tx_port_stats_ext); + } +} + static void bnge_sp_task(struct work_struct *work) { struct bnge_net *bn =3D container_of(work, struct bnge_net, sp_task); @@ -342,6 +426,12 @@ static void bnge_sp_task(struct work_struct *work) return; } =20 + if (test_and_clear_bit(BNGE_PERIODIC_STATS_SP_EVENT, &bn->sp_event)) { + bnge_hwrm_port_qstats(bd, 0); + bnge_hwrm_port_qstats_ext(bd, 0); + bnge_accumulate_all_stats(bd); + } + if (test_and_clear_bit(BNGE_UPDATE_PHY_SP_EVENT, &bn->sp_event)) { int rc; =20 diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.h index 65cbdcc9d30..107c8a69c93 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -299,6 +299,7 @@ enum bnge_sp_event { BNGE_LINK_SPEED_CHNG_SP_EVENT, BNGE_LINK_CFG_CHANGE_SP_EVENT, BNGE_UPDATE_PHY_SP_EVENT, + BNGE_PERIODIC_STATS_SP_EVENT, }; =20 struct bnge_net { --=20 2.47.3 From nobody Sun Apr 5 18:20:21 2026 Received: from mail-dl1-f98.google.com (mail-dl1-f98.google.com [74.125.82.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 E06A3313E29 for ; Mon, 23 Feb 2026 16:38:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.98 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864682; cv=none; b=NQRC0EYmomFjrfHcjkBtW+IbIm4huoRGElE/rXtvzSuSry54y6KUOJ3/CeZjkwFUOsE5tGsRWVlnutf6jIufIH2KJqroY7UrVKOWauBpJxojwJxwDvgZjyuu2pFAewx2MGyrmCdnDq5RSVAHOEzuUUMewa8jAfC7/A2/8HM8nRc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771864682; c=relaxed/simple; bh=EDNg3P30qp6TpoJ+LaUb8hlMM2SdRTBe0QhS1deiRbE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BMYhSxMMZNh8ZNdzoL8UNbZZE8ugoVLQRWGDYVIOQRY8wWAwQBBXTy1iwpEQZ314hAmBPsTeY033zYM5hIU9h+LDgU0mBK2EZbEkcsqOoX4bt/C0IV8YkytGL3Pph5W2/pS5GMw7Y5QMnWQb2a8yCiAO+j8y6b3epGQWD8b3Vnc= 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=GaIvDxCf; arc=none smtp.client-ip=74.125.82.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="GaIvDxCf" Received: by mail-dl1-f98.google.com with SMTP id a92af1059eb24-1270ac5d3efso4041937c88.1 for ; Mon, 23 Feb 2026 08:38:00 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771864680; x=1772469480; 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=moTkq8uSx6FpuB82+cTHGTek2ppzwZXDRC3f5Mlpkf4=; b=s83xfrHbeA/g7wFkaw+6FJZG9WWa51kzYYuorPJvIyT4RZi0glBAoeTb7i5xDtiF40 TLOxtNN8HFJpCc0SCyF8US9UGyV3vtd0X9Afa5RB0GmEo4Um2gBpTKUsYos4G9k+UbTm GRb0QjoJ6602ws9JNgduMX4dXJJm4FfJxDfhSwKfCOM3L3rJHEVGl29j3Gjl1fQLXAJB yD3G/ISjn+91/g4E2xwF9N7/Sdg6Z7vB+SBXsmvqw61itHIFpt+bRNw3dey2Icwunvps jS/z/R/13t42obrzRUCt9ECQqlN/TB6EU0QyLKrmrfrA6lPhEhyNOJjzH7M33e41XHm0 hkEQ== X-Forwarded-Encrypted: i=1; AJvYcCW01exG45QIvHWCFxqgRd+Clod6yznXEotAOzhw7i/K5YESoJojOGSmQvD8B6js3cha21soSPyuNvwkgGg=@vger.kernel.org X-Gm-Message-State: AOJu0YxVwo9dZvaTYp+erHHmTqnc+Sezg6OcdqTxLhQpkXlr3Nz2r//6 6P7cE4c5N7PVHkgq7ebWn8EYDISv3gu6elt4+uO+F5UpuioVRf4nNK75Jk4FzhLZGHXa9whdf9q /enSfU9WLTW1XR7hvZVzTt/tgkSsU/JFNT54+aJJZhKj9rSUPHqPCQkqp3IMheFF3KOWou5rQZC txhJwsAcXWrS2hFaLQTLha6eTFBuRd4SuCdmbbH4bgNW6qJZEwFiXj56fRj+lWdUDHRoTreav64 9PIicRjJdilUWqEiaIhWh0BqA== X-Gm-Gg: ATEYQzztcHypp9G3kE/ZzsEh8ezIzkXnQ5cLmzNslORSGlQcvTCOXSdHbPzAnR4e3Z1 5C1MrrFW47JAyvlUDx+FqZ7sdFp/5s+2Y0/QFLsVN0idjBZacUeYzcve04GIi3NpWqjmfHieRIZ lajzFa/QBEuZHCZAK6w31+X36GTjWD5zCwoGtqzAEQJDgsNmQVM/7vx6PQkbQC8nRKlIzWGMbwB AjD0GIGgkuNRibs6jLzTlarUOBGTVGeD8EARh16yVdqg+3Te7D05WYMIdQ5q5rTlysusLJrv9IC v1otTlrmP/v4xGMvJpW5uGdE1dOhN0gN876qDymOF+a+NtZ4OA6j+U7aHnMenCVpocI3G412+kO mkiyt6e4oN0SVeesEjgnMQ46uAZPQ6qfpb5+uZJJSZp1672AGMc0LfOLh6nzxcHe0kRUpzHyxRr +qWqGTsmXdU0DhDq9JrhT0S/9j+ehX53h6Vohf7IImmTTiS5RgJYg41m0CTlLaiCA= X-Received: by 2002:a05:7301:418b:b0:2ba:7f8c:6754 with SMTP id 5a478bee46e88-2bd7bd99977mr3003205eec.37.1771864679730; Mon, 23 Feb 2026 08:37:59 -0800 (PST) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-25.dlp.protect.broadcom.com. [144.49.247.25]) by smtp-relay.gmail.com with ESMTPS id 5a478bee46e88-2bd7da826fbsm818081eec.3.2026.02.23.08.37.59 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2026 08:37:59 -0800 (PST) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2aaf2f3bef6so47362455ad.0 for ; Mon, 23 Feb 2026 08:37:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1771864678; x=1772469478; 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=moTkq8uSx6FpuB82+cTHGTek2ppzwZXDRC3f5Mlpkf4=; b=GaIvDxCfKS2/FzTqjq8lsPZwewVI1IAz6wPNlzqvLzCDmnNXcRoTuCJ0FdOHqwNZS7 W9pWLh7NcO0VC30lgIPHEqRFk0vRdp7XUscmjYFcmPljk41g310Q6PS7JhfhRBwPZgH1 3/I0AUgnfyyyFDSNmbjVQT889YmlL+qS9e/Mc= X-Forwarded-Encrypted: i=1; AJvYcCUJUE33CoDFWjaaFsqH09dlSFYyiyNbOMLoOQy2tKTTWeNktpyydEx5B4I8bPeiw/v2ktaIleTADkxpRCo=@vger.kernel.org X-Received: by 2002:a17:903:3bcc:b0:2a9:4369:940c with SMTP id d9443c01a7336-2ad745a8ce1mr89168545ad.53.1771864677965; Mon, 23 Feb 2026 08:37:57 -0800 (PST) X-Received: by 2002:a17:903:3bcc:b0:2a9:4369:940c with SMTP id d9443c01a7336-2ad745a8ce1mr89168325ad.53.1771864677495; Mon, 23 Feb 2026 08:37:57 -0800 (PST) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ad74e3445fsm96763825ad.13.2026.02.23.08.37.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 08:37:57 -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 , Ajit Kumar Khaparde Subject: [PATCH net-next 7/7] bng_en: implement ndo_get_stats64 Date: Mon, 23 Feb 2026 22:06:41 +0530 Message-ID: <20260223163641.755200-8-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260223163641.755200-1-bhargava.marreddy@broadcom.com> References: <20260223163641.755200-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" Implement the ndo_get_stats64 callback to report aggregate network statistics. The driver gathers these by accumulating the per-ring counters into the provided rtnl_link_stats64 structure. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta Reviewed-by: Ajit Kumar Khaparde --- .../net/ethernet/broadcom/bnge/bnge_netdev.c | 108 ++++++++++++++++++ .../net/ethernet/broadcom/bnge/bnge_netdev.h | 11 +- 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.c index e2715419b6f..c6079b4c949 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -2939,6 +2939,106 @@ static int bnge_shutdown_nic(struct bnge_net *bn) return 0; } =20 +static void bnge_get_ring_stats(struct bnge_dev *bd, + struct rtnl_link_stats64 *stats) +{ + struct bnge_net *bn =3D netdev_priv(bd->netdev); + int i; + + for (i =3D 0; i < bd->nq_nr_rings; i++) { + struct bnge_napi *bnapi =3D bn->bnapi[i]; + struct bnge_nq_ring_info *nqr =3D &bnapi->nq_ring; + u64 *sw =3D nqr->stats.sw_stats; + + stats->rx_packets +=3D BNGE_GET_RING_STATS64(sw, rx_ucast_pkts); + stats->rx_packets +=3D BNGE_GET_RING_STATS64(sw, rx_mcast_pkts); + stats->rx_packets +=3D BNGE_GET_RING_STATS64(sw, rx_bcast_pkts); + + stats->tx_packets +=3D BNGE_GET_RING_STATS64(sw, tx_ucast_pkts); + stats->tx_packets +=3D BNGE_GET_RING_STATS64(sw, tx_mcast_pkts); + stats->tx_packets +=3D BNGE_GET_RING_STATS64(sw, tx_bcast_pkts); + + stats->rx_bytes +=3D BNGE_GET_RING_STATS64(sw, rx_ucast_bytes); + stats->rx_bytes +=3D BNGE_GET_RING_STATS64(sw, rx_mcast_bytes); + stats->rx_bytes +=3D BNGE_GET_RING_STATS64(sw, rx_bcast_bytes); + + stats->tx_bytes +=3D BNGE_GET_RING_STATS64(sw, tx_ucast_bytes); + stats->tx_bytes +=3D BNGE_GET_RING_STATS64(sw, tx_mcast_bytes); + stats->tx_bytes +=3D BNGE_GET_RING_STATS64(sw, tx_bcast_bytes); + + stats->rx_missed_errors +=3D + BNGE_GET_RING_STATS64(sw, rx_discard_pkts); + + stats->multicast +=3D BNGE_GET_RING_STATS64(sw, rx_mcast_pkts); + + stats->tx_dropped +=3D BNGE_GET_RING_STATS64(sw, tx_error_pkts); + + stats->rx_dropped +=3D + nqr->sw_stats->rx.rx_netpoll_discards + + nqr->sw_stats->rx.rx_oom_discards; + } +} + +static void bnge_add_prev_stats(struct bnge_net *bn, + struct rtnl_link_stats64 *stats) +{ + struct rtnl_link_stats64 *prev_stats =3D &bn->net_stats_prev; + + stats->rx_packets +=3D prev_stats->rx_packets; + stats->tx_packets +=3D prev_stats->tx_packets; + stats->rx_bytes +=3D prev_stats->rx_bytes; + stats->tx_bytes +=3D prev_stats->tx_bytes; + stats->rx_missed_errors +=3D prev_stats->rx_missed_errors; + stats->multicast +=3D prev_stats->multicast; + stats->rx_dropped +=3D prev_stats->rx_dropped; + stats->tx_dropped +=3D prev_stats->tx_dropped; +} + +static void bnge_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + struct bnge_net *bn =3D netdev_priv(dev); + struct bnge_dev *bd =3D bn->bd; + + set_bit(BNGE_STATE_READ_STATS, &bn->state); + /* Make sure bnge_close_core() sees that we are reading stats before + * we check the BNGE_STATE_OPEN flag. + */ + smp_mb__after_atomic(); + if (!test_bit(BNGE_STATE_OPEN, &bd->state)) { + clear_bit(BNGE_STATE_READ_STATS, &bn->state); + *stats =3D bn->net_stats_prev; + return; + } + + bnge_get_ring_stats(bd, stats); + bnge_add_prev_stats(bn, stats); + + if (bn->flags & BNGE_FLAG_PORT_STATS) { + u64 *rx =3D bn->port_stats.sw_stats; + u64 *tx =3D bn->port_stats.sw_stats + + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + + stats->rx_crc_errors =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); + stats->rx_frame_errors =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_align_err_frames); + stats->rx_length_errors =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_undrsz_frames) + + BNGE_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames) + + BNGE_GET_RX_PORT_STATS64(rx, rx_runt_frames); + stats->rx_errors =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_false_carrier_frames) + + BNGE_GET_RX_PORT_STATS64(rx, rx_jbr_frames); + stats->collisions =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_total_collisions); + stats->tx_fifo_errors =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_fifo_underruns); + stats->tx_errors =3D BNGE_GET_TX_PORT_STATS64(tx, tx_err); + } + clear_bit(BNGE_STATE_READ_STATS, &bn->state); +} + static void bnge_close_core(struct bnge_net *bn) { struct bnge_dev *bd =3D bn->bd; @@ -2954,6 +3054,13 @@ static void bnge_close_core(struct bnge_net *bn) bnge_shutdown_nic(bn); bnge_disable_napi(bn); timer_delete_sync(&bn->timer); + + /* Save ring stats before shutdown */ + if (bn->bnapi) { + bnge_get_ring_stats(bd, &bn->net_stats_prev); + bnge_get_ring_err_stats(bn, &bn->ring_err_stats_prev); + } + bnge_free_all_rings_bufs(bn); bnge_free_irq(bn); bnge_del_napi(bn); @@ -3003,6 +3110,7 @@ static const struct net_device_ops bnge_netdev_ops = =3D { .ndo_open =3D bnge_open, .ndo_stop =3D bnge_close, .ndo_start_xmit =3D bnge_start_xmit, + .ndo_get_stats64 =3D bnge_get_stats64, .ndo_features_check =3D bnge_features_check, }; =20 diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.h index 107c8a69c93..4b68a8ed229 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -227,6 +227,12 @@ struct bnge_tpa_info { #define BNGE_GET_RING_STATS64(sw, counter) \ (*((sw) + offsetof(struct ctx_hw_stats, counter) / 8)) =20 +#define BNGE_GET_RX_PORT_STATS64(sw, counter) \ + (*((sw) + offsetof(struct rx_port_stats, counter) / 8)) + +#define BNGE_GET_TX_PORT_STATS64(sw, counter) \ + (*((sw) + offsetof(struct tx_port_stats, counter) / 8)) + #define BNGE_PORT_STATS_SIZE \ (sizeof(struct rx_port_stats) + sizeof(struct tx_port_stats) + 1024) =20 @@ -285,6 +291,7 @@ struct bnge_sw_stats { enum bnge_net_state { BNGE_STATE_NAPI_DISABLED, BNGE_STATE_IN_SP_TASK, + BNGE_STATE_READ_STATS, }; =20 #define BNGE_TIMER_INTERVAL HZ @@ -377,6 +384,7 @@ struct bnge_net { =20 u64 flags; =20 + struct rtnl_link_stats64 net_stats_prev; struct bnge_total_ring_err_stats ring_err_stats_prev; =20 struct bnge_stats_mem port_stats; @@ -650,7 +658,8 @@ struct bnge_l2_filter { =20 static inline bool bnge_drv_busy(struct bnge_net *bn) { - return test_bit(BNGE_STATE_IN_SP_TASK, &bn->state); + return test_bit(BNGE_STATE_IN_SP_TASK, &bn->state) || + test_bit(BNGE_STATE_READ_STATS, &bn->state); } =20 u16 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr); --=20 2.47.3