From nobody Sun Apr 5 18:19:06 2026 Received: from mail-pj1-f99.google.com (mail-pj1-f99.google.com [209.85.216.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 C953033067C for ; Tue, 24 Mar 2026 20:08:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774382933; cv=none; b=aBH/NxVlWT3a5aOxlb3t+kib9lJN2pdm+A3B8g3XsjbGGOqer/cfSRsD+m8htUjsH+Hf/pGuWibrxK3++d+FB2DyNMWfIa6Ak37DPD2QmfO4UsRM7vMmeAsofr/XLcNhXGp0Ub45mzI++ii6UftKfXxyQjtA3BB8qxtwAEGcYt4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774382933; c=relaxed/simple; bh=7xGYqdifVkbN0mJApyIRgISyQ3x25IBB2zwyjHrLZ/s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XY8s3WbBcoYhBkwNggNg8umazU7HxhxJ6MXzWvESotCep6rLP+RVxjjGCZyB8jqB+Yzk8VOvvuKom1g01ZegGggjrQiimty+n4Ano2vjlwDdmcQ+S/NiXGi00aIWY/Ha9y4lZprRgzGeygR6DT9wET0eRx9Ml2pMjnwaZZWu+z4= 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=NWnM3Bel; arc=none smtp.client-ip=209.85.216.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="NWnM3Bel" Received: by mail-pj1-f99.google.com with SMTP id 98e67ed59e1d1-35bb9070644so2702398a91.2 for ; Tue, 24 Mar 2026 13:08:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774382924; x=1774987724; 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=7HslyX0vS4Emf8IAyVFTSWEiBbhWfuOSyl/0aoU/T0o=; b=kjxObSNclDpX/coessRma/AE1ysHHLldZKjo6LPFSNfaYc6FGlNnem2yXUJKG2SHLo XSXwwhwok08t8lfj1GvwyGgZilaPKaFKGFYV9X5qWjFH4SBwLS0+qLVodpwMjXxiRSPF tJdKgSoor+sk2DfVzPyQR2hivwkzTa6NOTjVJw4L6ljrCNI1VpbC1Md5O7CYu4yEzVwP nYY1pXZp9iM5f9U95HyyiT1UdHmWpxdiZtXcwO3vOlhoRSKbWniqd3LdbGW9O3aePua9 AubjJ4ZJDhkFaKujDhpIEdgyXeCyVBOf+gsqEnq1SB6d2ZYADi+QRGsMSGu3rEXOVbCA dngQ== X-Forwarded-Encrypted: i=1; AJvYcCVMU6XjUovLOtADB1wcOu325TkRXkrXxtv/eoDPLaUMujXhjc8iz7EcDKYleVEUEU2s5Q51EGnXhBUEEG4=@vger.kernel.org X-Gm-Message-State: AOJu0Yw4+ib7Jm6suoBqC0kUsxFlnfQ5AqyuzSerMvoJddI6skSlHLUk IkbSVRz+LhyC154Fzuz+r84HPz3IUVrUqODxt6jg5Kslc8zSOIrUiHWzB5+2Q76aKj0cNmjeM5+ +jr6nHDXeB0V681qIxybpKuMd1SIzorMj05iYIwOnE8a4rBwzOsUpACum/KibvXA5gXGSn/UNeP WbhSs9oKEba0K46l/28yGhZm776sfiRdyo7TqiusauGY/K+MKD3DW/FwD9kmOlIPYRF16k+6y5q K13g77xcqE+XCTeBYvNHXXkmQ== X-Gm-Gg: ATEYQzyA0NLdpVYUACBtLNA9e2TqyfFMgMa6pWkvjtDPbwDC5MJv9fBf5C7u/X/Z2ut Fkx8gFvLkY3Jtoxyp0KrbuE9QUmtYoG9KEVlOpWC1uotyYjfM8hV/Pk0pDTInn+VWeTDerMBH7H kXvwkPjYwS/mphltPagj0HWmRzizn/OpVhCzq8PI4t7kWq+5uWyF3H/ow7ZU9/BeW7j9OqZN6Bh ekspKjkTXvDVG9A4jVFDtXQilVRnAE0KlXsLqtqDVvF8P6s7T4E9749QGbspmJYuEO9Yy94ztkm 0CJ2UJvCe10ixDt+GlaRb7dHYFc5ytuasVJJIe2BYBIB0/6of+AtMxAcA0SaPHzMcjLRLXv8Qdg G8Pjn8gIpr2fZajQsuTSUXD39MpwIle0QXx5+XsfN/Yu+FugZLJGoFjmmoxIeozkj1ATEZWjEpc lUgZTqmb4cpJFZf/ULwx/HNpg81LN/gRrinXdW3HQvforfOBWVUMId1vshjozjDrHuaw== X-Received: by 2002:a17:90b:3d8d:b0:35b:e52a:6fe5 with SMTP id 98e67ed59e1d1-35c0dc8422cmr548723a91.5.1774382923587; Tue, 24 Mar 2026 13:08:43 -0700 (PDT) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-121.dlp.protect.broadcom.com. [144.49.247.121]) by smtp-relay.gmail.com with ESMTPS id 98e67ed59e1d1-35c0313ea1fsm312462a91.4.2026.03.24.13.08.43 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 24 Mar 2026 13:08:43 -0700 (PDT) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-35ba237d2e0so5275287a91.2 for ; Tue, 24 Mar 2026 13:08:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1774382922; x=1774987722; 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=7HslyX0vS4Emf8IAyVFTSWEiBbhWfuOSyl/0aoU/T0o=; b=NWnM3BelxaDE6WeBjVXLC0vZFWAzS05S5mBAjCTB10grfue1+y5x+DL0qU3kYePswu noXGlkPe5SqJpQm8WniOVYTNmaRhIxwv/0v6gR58a4puUhxkIfSW47BjqPUSrlYET+9A VbzBUen52FZE5RWHCfdjtRcrKfJ5tyT+Hk3pw= X-Forwarded-Encrypted: i=1; AJvYcCWrccRqCUNEYHmWHRhVKVYymhStDrQE1F1f+JrzXd1pbAT3s1eooRgv2VfN7mvyzKOiX6uqmueVmZD6S9Q=@vger.kernel.org X-Received: by 2002:a05:6a21:32a2:b0:398:7d4a:c2c4 with SMTP id adf61e73a8af0-39c4ada7557mr963826637.48.1774382921233; Tue, 24 Mar 2026 13:08:41 -0700 (PDT) X-Received: by 2002:a05:6a21:32a2:b0:398:7d4a:c2c4 with SMTP id adf61e73a8af0-39c4ada7557mr963798637.48.1774382920627; Tue, 24 Mar 2026 13:08:40 -0700 (PDT) Received: from localhost.localdomain ([192.19.203.250]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c743a80163bsm9930057a12.1.2026.03.24.13.08.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 24 Mar 2026 13:08:40 -0700 (PDT) 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 Subject: [PATCH net-next v9 06/10] bng_en: add HW stats infra and structured ethtool ops Date: Wed, 25 Mar 2026 01:37:36 +0530 Message-ID: <20260324200740.346029-7-bhargava.marreddy@broadcom.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260324200740.346029-1-bhargava.marreddy@broadcom.com> References: <20260324200740.346029-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 hardware-level statistics foundation and modern structured ethtool operations. 1. Infrastructure: Add HWRM firmware wrappers (FUNC_QSTATS_EXT, PORT_QSTATS_EXT, and PORT_QSTATS) to query ring and port counters. 2. Structured ops: Implement .get_eth_phy_stats, .get_eth_mac_stats, .get_eth_ctrl_stats, .get_pause_stats, and .get_rmon_stats. Stats are initially reported as 0; accumulation logic is added in a subsequent patch. Signed-off-by: Bhargava Marreddy Reviewed-by: Vikas Gupta --- .../net/ethernet/broadcom/bnge/bnge_ethtool.c | 160 +++++++++++++++ .../ethernet/broadcom/bnge/bnge_hwrm_lib.c | 151 +++++++++++++- .../ethernet/broadcom/bnge/bnge_hwrm_lib.h | 3 + .../net/ethernet/broadcom/bnge/bnge_netdev.c | 192 +++++++++++++++++- .../net/ethernet/broadcom/bnge/bnge_netdev.h | 60 +++++- 5 files changed, 554 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c b/drivers/ne= t/ethernet/broadcom/bnge/bnge_ethtool.c index 424bf2d6721c..87226d5bf15c 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c @@ -46,6 +46,161 @@ static void bnge_get_drvinfo(struct net_device *dev, strscpy(info->bus_info, pci_name(bd->pdev), sizeof(info->bus_info)); } =20 +static void bnge_get_eth_phy_stats(struct net_device *dev, + struct ethtool_eth_phy_stats *phy_stats) +{ + struct bnge_net *bn =3D netdev_priv(dev); + u64 *rx; + + if (!(bn->flags & BNGE_FLAG_PORT_STATS_EXT)) + return; + + rx =3D bn->rx_port_stats_ext.sw_stats; + phy_stats->SymbolErrorDuringCarrier =3D + *(rx + BNGE_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); +} + +static void bnge_get_eth_mac_stats(struct net_device *dev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct bnge_net *bn =3D netdev_priv(dev); + u64 *rx, *tx; + + if (!(bn->flags & BNGE_FLAG_PORT_STATS)) + return; + + rx =3D bn->port_stats.sw_stats; + tx =3D bn->port_stats.sw_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + + mac_stats->FramesReceivedOK =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_good_frames); + mac_stats->FramesTransmittedOK =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_good_frames); + mac_stats->FrameCheckSequenceErrors =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); + mac_stats->AlignmentErrors =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_align_err_frames); + mac_stats->OutOfRangeLengthField =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); + mac_stats->OctetsReceivedOK =3D BNGE_GET_RX_PORT_STATS64(rx, rx_bytes); + mac_stats->OctetsTransmittedOK =3D BNGE_GET_TX_PORT_STATS64(tx, tx_bytes); + mac_stats->MulticastFramesReceivedOK =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_mcast_frames); + mac_stats->BroadcastFramesReceivedOK =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_bcast_frames); + mac_stats->MulticastFramesXmittedOK =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_mcast_frames); + mac_stats->BroadcastFramesXmittedOK =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_bcast_frames); + mac_stats->FrameTooLongErrors =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); +} + +static void bnge_get_eth_ctrl_stats(struct net_device *dev, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct bnge_net *bn =3D netdev_priv(dev); + u64 *rx; + + if (!(bn->flags & BNGE_FLAG_PORT_STATS)) + return; + + rx =3D bn->port_stats.sw_stats; + ctrl_stats->MACControlFramesReceived =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); +} + +static void bnge_get_pause_stats(struct net_device *dev, + struct ethtool_pause_stats *pause_stats) +{ + struct bnge_net *bn =3D netdev_priv(dev); + u64 *rx, *tx; + + if (!(bn->flags & BNGE_FLAG_PORT_STATS)) + return; + + rx =3D bn->port_stats.sw_stats; + tx =3D bn->port_stats.sw_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + + pause_stats->rx_pause_frames =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_pause_frames); + pause_stats->tx_pause_frames =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_pause_frames); +} + +static const struct ethtool_rmon_hist_range bnge_rmon_ranges[] =3D { + { 0, 64 }, + { 65, 127 }, + { 128, 255 }, + { 256, 511 }, + { 512, 1023 }, + { 1024, 1518 }, + { 1519, 2047 }, + { 2048, 4095 }, + { 4096, 9216 }, + { 9217, 16383 }, + {} +}; + +static void bnge_get_rmon_stats(struct net_device *dev, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct bnge_net *bn =3D netdev_priv(dev); + u64 *rx, *tx; + + if (!(bn->flags & BNGE_FLAG_PORT_STATS)) + return; + + rx =3D bn->port_stats.sw_stats; + tx =3D bn->port_stats.sw_stats + BNGE_TX_PORT_STATS_BYTE_OFFSET / 8; + + rmon_stats->jabbers =3D BNGE_GET_RX_PORT_STATS64(rx, rx_jbr_frames); + rmon_stats->oversize_pkts =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); + rmon_stats->undersize_pkts =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); + + rmon_stats->hist[0] =3D BNGE_GET_RX_PORT_STATS64(rx, rx_64b_frames); + rmon_stats->hist[1] =3D BNGE_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); + rmon_stats->hist[2] =3D BNGE_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); + rmon_stats->hist[3] =3D BNGE_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); + rmon_stats->hist[4] =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); + rmon_stats->hist[5] =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); + rmon_stats->hist[6] =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); + rmon_stats->hist[7] =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); + rmon_stats->hist[8] =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); + rmon_stats->hist[9] =3D + BNGE_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); + + rmon_stats->hist_tx[0] =3D BNGE_GET_TX_PORT_STATS64(tx, tx_64b_frames); + rmon_stats->hist_tx[1] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); + rmon_stats->hist_tx[2] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); + rmon_stats->hist_tx[3] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); + rmon_stats->hist_tx[4] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); + rmon_stats->hist_tx[5] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); + rmon_stats->hist_tx[6] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); + rmon_stats->hist_tx[7] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); + rmon_stats->hist_tx[8] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); + rmon_stats->hist_tx[9] =3D + BNGE_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); + + *ranges =3D bnge_rmon_ranges; +} + static void bnge_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { @@ -116,6 +271,11 @@ static const struct ethtool_ops bnge_ethtool_ops =3D { .nway_reset =3D bnge_nway_reset, .get_pauseparam =3D bnge_get_pauseparam, .set_pauseparam =3D bnge_set_pauseparam, + .get_eth_phy_stats =3D bnge_get_eth_phy_stats, + .get_eth_mac_stats =3D bnge_get_eth_mac_stats, + .get_eth_ctrl_stats =3D bnge_get_eth_ctrl_stats, + .get_pause_stats =3D bnge_get_pause_stats, + .get_rmon_stats =3D bnge_get_rmon_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 523b8963b6dc..ba1c1f18e12e 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, @@ -594,7 +595,7 @@ int bnge_hwrm_func_qcaps(struct bnge_dev *bd) struct hwrm_func_qcaps_output *resp; struct hwrm_func_qcaps_input *req; struct bnge_pf_info *pf =3D &bd->pf; - u32 flags; + u32 flags, flags_ext; int rc; =20 rc =3D bnge_hwrm_req_init(bd, req, HWRM_FUNC_QCAPS); @@ -612,6 +613,12 @@ 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; + + flags_ext =3D le32_to_cpu(resp->flags_ext); + if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_EXT_HW_STATS_SUPPORTED) + bd->fw_cap |=3D BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED; =20 pf->fw_fid =3D le16_to_cpu(resp->fid); pf->port_id =3D le16_to_cpu(resp->port_id); @@ -1492,3 +1499,145 @@ 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; + + if (!(bd->fw_cap & BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED)) + return -EOPNOTSUPP; + + 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 >=3D BNGE_MAX_QUEUE) { + bn->pri2cos_valid =3D false; + rc =3D -EINVAL; + goto drop_req; + } + 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; + } +drop_req: + 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 86ca3ac2244b..3501de7a89b9 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 4ad08a5a933b..b03a9f186b97 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) @@ -75,6 +92,107 @@ static void bnge_free_ring_stats(struct bnge_net *bn) } } =20 +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); +} + static int bnge_alloc_ring_stats(struct bnge_net *bn) { struct bnge_dev *bd =3D bn->bd; @@ -88,12 +206,77 @@ static int bnge_alloc_ring_stats(struct bnge_net *bn) struct bnge_nq_ring_info *nqr =3D &bnapi->nq_ring; =20 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: @@ -940,6 +1123,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); @@ -1024,10 +1208,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; diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net= /ethernet/broadcom/bnge/bnge_netdev.h index 5636eb371e24..74b08d492c53 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -224,6 +224,41 @@ 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_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) + +#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_stats_mem { + u64 *sw_stats; + u64 *hw_masks; + void *hw_stats; + dma_addr_t hw_stats_map; + u32 len; +}; =20 enum bnge_net_state { BNGE_STATE_NAPI_DISABLED, @@ -231,6 +266,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, @@ -309,6 +349,17 @@ struct bnge_net { unsigned long sp_event; =20 struct bnge_ethtool_link_info eth_link_info; + + u64 flags; + + 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 @@ -374,14 +425,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 @@ -588,4 +631,5 @@ 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_copy_hw_masks(u64 *mask_arr, __le64 *hw_mask_arr, int count); #endif /* _BNGE_NETDEV_H_ */ --=20 2.47.3