From nobody Mon Sep 28 21:52:15 2026 Received: from canpmsgout09.his.huawei.com (canpmsgout09.his.huawei.com [113.46.200.224]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 405CE175A6D; Mon, 17 Aug 2026 02:04:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.224 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786932281; cv=none; b=n//DKzXPrm3r+TZBtFO/Npe7FxOgaDaWj1tE0MupBRCRapMKw5U6kHiF0ncQgLoABhbVuuLWr63QJECQZoC9CSwo2Fx++f5+w7m/AyDy8Mnp8LfOvojCHABV3KKxI29lTTPTwb5Kq+vijA9+qWqfQMGzlVve2uPKViDP/9zlIA4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786932281; c=relaxed/simple; bh=WxYxfz3OJ5y/WItiTh4mb7O+UvDsH3SBXtooDdn2T9A=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=g9LY8CKS2/6FVX8/336We+ntJlQTGJpkdawLCWN8E0pnz8PW0MDbax2H3kiadN22+HU+2HJXsST8+rBro4tnjNiUVPOe0I/FNLUjQnvv0BNOFc33JwPXOUBsAR2ycIsH+tDRtU9PtrGAUAwfvKn/pJ3lCoktawjU4IB+iobHl9w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=Pvkt6jsP; arc=none smtp.client-ip=113.46.200.224 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="Pvkt6jsP" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=q1Lhu7Ot64Mi6lXWgd4Rx74X4CdJK+guphmBjA65ciE=; b=Pvkt6jsPCiLOIhAakHQYLNScA7Z9gRFL/YYOk0bt+25/83zWBD2uzTjE2O3MIDQ/peS8hYbWX QHnlDvKZNDp6l3AymqItT9Q3N9pa7tb7wMhIXZdK9+tqEluicEkdQy55WbRr7BKDvetmv1GJOCj f/w6pNt/OLnVeoLltgyQvV4= Received: from mail.maildlp.com (unknown [172.19.163.200]) by canpmsgout09.his.huawei.com (SkyGuard) with ESMTPS id 4hNbTt0yLNz1cyTS; Mon, 17 Aug 2026 09:53:54 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 4278C4055B; Mon, 17 Aug 2026 10:04:33 +0800 (CST) Received: from DESKTOP-62GVMTR.china.huawei.com (10.174.189.124) by kwepemf100013.china.huawei.com (7.202.181.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Mon, 17 Aug 2026 10:04:31 +0800 From: Fan Gong To: Fan Gong , Wu Di , Teng Peisen , , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrew Lunn , Ioana Ciornei , Mohsin Bashir , Dimitri Daskalakis , Harshitha Ramamurthy , Larysa Zaremba CC: , , Chen Anwen , He Wei , luosifu , Xin Guo , Zhou Shuai , Wu Like , Shi Jing , Zheng Jiezhen , Maxime Chevallier Subject: [PATCH net-next v13 1/3] hinic3: Add ethtool statistic ops Date: Mon, 17 Aug 2026 10:04:00 +0800 Message-ID: X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: References: 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-ClientProxiedBy: kwepems200001.china.huawei.com (7.221.188.67) To kwepemf100013.china.huawei.com (7.202.181.12) Content-Type: text/plain; charset="utf-8" Add PF/VF statistics functions in TX and RX processing. Implement following ethtool callback function: .get_sset_count .get_ethtool_stats .get_strings .get_eth_phy_stats .get_eth_mac_stats .get_eth_ctrl_stats .get_rmon_stats .get_pause_stats These callbacks allow users to utilize ethtool for detailed TX and RX netdev stats monitoring. Add mgmt_msg_params_init_in_out() to support management commands that require separate input and output buffers. This is needed for retrieving the expanded PF/VF MAC statistics from HW, which no longer fit in the input buffer used by the existing path. Remove unused stats "restore_drop_sge" in struct hinic3_rxq_stats. Remove unused stats "frag_len_overflow" and "frag_size_err" in struct hinic3_txq_stats. Co-developed-by: Wu Di Signed-off-by: Wu Di Co-developed-by: Teng Peisen Signed-off-by: Teng Peisen Signed-off-by: Fan Gong --- .../ethernet/huawei/hinic3/hinic3_ethtool.c | 476 ++++++++++++++++++ .../ethernet/huawei/hinic3/hinic3_hw_intf.h | 11 + .../huawei/hinic3/hinic3_mgmt_interface.h | 37 ++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 64 +++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 109 ++++ .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_rx.c | 73 ++- .../net/ethernet/huawei/hinic3/hinic3_rx.h | 15 +- .../net/ethernet/huawei/hinic3/hinic3_tx.c | 68 ++- .../net/ethernet/huawei/hinic3/hinic3_tx.h | 4 +- 10 files changed, 844 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_ethtool.c index 90fc16288de9..e1d1f1ff4b6c 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c @@ -409,6 +409,474 @@ hinic3_get_link_ksettings(struct net_device *netdev, return 0; } =20 +struct hinic3_stats { + char name[ETH_GSTRING_LEN]; + int offset; +}; + +#define HINIC3_STAT_SIZE_CHECK(type, member) \ + BUILD_BUG_ON_ZERO(sizeof_field(type, member) !=3D sizeof(u64)) + +#define HINIC3_RXQ_STAT(_stat_item) { \ + .name =3D "rxq%d_"#_stat_item, \ + .offset =3D offsetof(struct hinic3_rxq_stats, _stat_item) \ + + 0 * HINIC3_STAT_SIZE_CHECK(struct hinic3_rxq_stats, \ + _stat_item) \ +} + +#define HINIC3_TXQ_STAT(_stat_item) { \ + .name =3D "txq%d_"#_stat_item, \ + .offset =3D offsetof(struct hinic3_txq_stats, _stat_item) \ + + 0 * HINIC3_STAT_SIZE_CHECK(struct hinic3_txq_stats, \ + _stat_item) \ +} + +static struct hinic3_stats hinic3_rx_queue_stats[] =3D { + HINIC3_RXQ_STAT(csum_errors), + HINIC3_RXQ_STAT(other_errors), + HINIC3_RXQ_STAT(rx_buf_empty), + HINIC3_RXQ_STAT(alloc_skb_err), + HINIC3_RXQ_STAT(alloc_rx_buf_err), +}; + +static struct hinic3_stats hinic3_tx_queue_stats[] =3D { + HINIC3_TXQ_STAT(busy), + HINIC3_TXQ_STAT(skb_pad_err), + HINIC3_TXQ_STAT(offload_cow_skb_err), + HINIC3_TXQ_STAT(map_frag_err), + HINIC3_TXQ_STAT(unknown_tunnel_pkt), +}; + +#define HINIC3_FUNC_STAT(_stat_item) { \ + .name =3D #_stat_item, \ + .offset =3D offsetof(struct l2nic_vport_stats, _stat_item) \ + + 0 * HINIC3_STAT_SIZE_CHECK(struct l2nic_vport_stats, \ + _stat_item) \ +} + +static struct hinic3_stats hinic3_function_stats[] =3D { + HINIC3_FUNC_STAT(tx_unicast_pkts_vport), + HINIC3_FUNC_STAT(tx_unicast_bytes_vport), + HINIC3_FUNC_STAT(tx_multicast_pkts_vport), + HINIC3_FUNC_STAT(tx_multicast_bytes_vport), + HINIC3_FUNC_STAT(tx_broadcast_pkts_vport), + HINIC3_FUNC_STAT(tx_broadcast_bytes_vport), + + HINIC3_FUNC_STAT(rx_unicast_pkts_vport), + HINIC3_FUNC_STAT(rx_unicast_bytes_vport), + HINIC3_FUNC_STAT(rx_multicast_pkts_vport), + HINIC3_FUNC_STAT(rx_multicast_bytes_vport), + HINIC3_FUNC_STAT(rx_broadcast_pkts_vport), + HINIC3_FUNC_STAT(rx_broadcast_bytes_vport), + + HINIC3_FUNC_STAT(tx_discard_vport), + HINIC3_FUNC_STAT(rx_discard_vport), + HINIC3_FUNC_STAT(tx_err_vport), + HINIC3_FUNC_STAT(rx_err_vport), +}; + +#define HINIC3_PORT_STAT(_stat_item) { \ + .name =3D #_stat_item, \ + .offset =3D offsetof(struct mag_cmd_port_stats, _stat_item) \ + + 0 * HINIC3_STAT_SIZE_CHECK(struct mag_cmd_port_stats, \ + _stat_item) \ +} + +static struct hinic3_stats hinic3_port_stats[] =3D { + HINIC3_PORT_STAT(mac_tx_fragment_pkt_num), + HINIC3_PORT_STAT(mac_tx_undersize_pkt_num), + HINIC3_PORT_STAT(mac_tx_undermin_pkt_num), + HINIC3_PORT_STAT(mac_tx_1519_max_bad_pkt_num), + HINIC3_PORT_STAT(mac_tx_1519_max_good_pkt_num), + HINIC3_PORT_STAT(mac_tx_oversize_pkt_num), + HINIC3_PORT_STAT(mac_tx_jabber_pkt_num), + HINIC3_PORT_STAT(mac_tx_bad_pkt_num), + HINIC3_PORT_STAT(mac_tx_bad_oct_num), + HINIC3_PORT_STAT(mac_tx_total_pkt_num), + HINIC3_PORT_STAT(mac_tx_uni_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri0_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri1_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri2_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri3_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri4_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri5_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri6_pkt_num), + HINIC3_PORT_STAT(mac_tx_pfc_pri7_pkt_num), + HINIC3_PORT_STAT(mac_tx_err_all_pkt_num), + HINIC3_PORT_STAT(mac_tx_from_app_good_pkt_num), + HINIC3_PORT_STAT(mac_tx_from_app_bad_pkt_num), + + HINIC3_PORT_STAT(mac_rx_undermin_pkt_num), + HINIC3_PORT_STAT(mac_rx_1519_max_bad_pkt_num), + HINIC3_PORT_STAT(mac_rx_1519_max_good_pkt_num), + HINIC3_PORT_STAT(mac_rx_bad_pkt_num), + HINIC3_PORT_STAT(mac_rx_bad_oct_num), + HINIC3_PORT_STAT(mac_rx_total_pkt_num), + HINIC3_PORT_STAT(mac_rx_uni_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri0_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri1_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri2_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri3_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri4_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri5_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri6_pkt_num), + HINIC3_PORT_STAT(mac_rx_pfc_pri7_pkt_num), + HINIC3_PORT_STAT(mac_rx_send_app_good_pkt_num), + HINIC3_PORT_STAT(mac_rx_send_app_bad_pkt_num), + HINIC3_PORT_STAT(mac_rx_unfilter_pkt_num), +}; + +static int hinic3_get_sset_count(struct net_device *netdev, int sset) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + int count, q_num; + + switch (sset) { + case ETH_SS_STATS: + q_num =3D nic_dev->q_params.num_qps; + count =3D ARRAY_SIZE(hinic3_function_stats) + + (ARRAY_SIZE(hinic3_tx_queue_stats) + + ARRAY_SIZE(hinic3_rx_queue_stats)) * + q_num; + + if (!HINIC3_IS_VF(nic_dev->hwdev)) + count +=3D ARRAY_SIZE(hinic3_port_stats); + + return count; + default: + return -EOPNOTSUPP; + } +} + +static void hinic3_get_drv_queue_stats(struct net_device *netdev, u64 *dat= a) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_txq_stats txq_stats =3D {}; + struct hinic3_rxq_stats rxq_stats =3D {}; + u16 i =3D 0, j, qid; + char *p; + + for (qid =3D 0; qid < nic_dev->q_params.num_qps; qid++) { + if (!nic_dev->txqs) + break; + + hinic3_txq_get_stats(&nic_dev->txqs[qid], &txq_stats); + for (j =3D 0; j < ARRAY_SIZE(hinic3_tx_queue_stats); j++, i++) { + p =3D (char *)&txq_stats + + hinic3_tx_queue_stats[j].offset; + data[i] =3D *(u64 *)p; + } + } + + i =3D nic_dev->q_params.num_qps * ARRAY_SIZE(hinic3_tx_queue_stats); + for (qid =3D 0; qid < nic_dev->q_params.num_qps; qid++) { + if (!nic_dev->rxqs) + break; + + hinic3_rxq_get_stats(&nic_dev->rxqs[qid], &rxq_stats); + for (j =3D 0; j < ARRAY_SIZE(hinic3_rx_queue_stats); j++, i++) { + p =3D (char *)&rxq_stats + + hinic3_rx_queue_stats[j].offset; + data[i] =3D *(u64 *)p; + } + } +} + +static u16 hinic3_get_ethtool_port_stats(struct net_device *netdev, u64 *d= ata) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct mag_cmd_port_stats *ps; + u16 i =3D 0, j; + char *p; + int err; + + ps =3D kmalloc_obj(*ps); + if (!ps) + goto err_zero_stats; + + err =3D hinic3_get_phy_port_stats(nic_dev->hwdev, ps); + if (err) { + kfree(ps); + netdev_err(netdev, "Failed to get port stats from fw\n"); + goto err_zero_stats; + } + + for (j =3D 0; j < ARRAY_SIZE(hinic3_port_stats); j++, i++) { + p =3D (char *)ps + hinic3_port_stats[j].offset; + data[i] =3D *(u64 *)p; + } + + kfree(ps); + + return i; + +err_zero_stats: + memset(&data[i], 0, ARRAY_SIZE(hinic3_port_stats) * sizeof(*data)); + + return i + ARRAY_SIZE(hinic3_port_stats); +} + +static void hinic3_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct l2nic_vport_stats vport_stats =3D {}; + u16 i =3D 0, j; + char *p; + int err; + + err =3D hinic3_get_vport_stats(nic_dev->hwdev, + hinic3_global_func_id(nic_dev->hwdev), + &vport_stats); + if (err) + netdev_err(netdev, "Failed to get function stats from fw\n"); + + for (j =3D 0; j < ARRAY_SIZE(hinic3_function_stats); j++, i++) { + p =3D (char *)&vport_stats + hinic3_function_stats[j].offset; + data[i] =3D *(u64 *)p; + } + + if (!HINIC3_IS_VF(nic_dev->hwdev)) + i +=3D hinic3_get_ethtool_port_stats(netdev, data + i); + + hinic3_get_drv_queue_stats(netdev, data + i); +} + +static u16 hinic3_get_hw_stats_strings(struct net_device *netdev, char *p) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + u16 i, cnt =3D 0; + + for (i =3D 0; i < ARRAY_SIZE(hinic3_function_stats); i++) { + memcpy(p, hinic3_function_stats[i].name, ETH_GSTRING_LEN); + p +=3D ETH_GSTRING_LEN; + cnt++; + } + + if (!HINIC3_IS_VF(nic_dev->hwdev)) { + for (i =3D 0; i < ARRAY_SIZE(hinic3_port_stats); i++) { + memcpy(p, hinic3_port_stats[i].name, ETH_GSTRING_LEN); + p +=3D ETH_GSTRING_LEN; + cnt++; + } + } + + return cnt; +} + +static void hinic3_get_qp_stats_strings(struct net_device *netdev, char *p) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + u8 *data =3D p; + u16 i, j; + + for (i =3D 0; i < nic_dev->q_params.num_qps; i++) { + for (j =3D 0; j < ARRAY_SIZE(hinic3_tx_queue_stats); j++) + ethtool_sprintf(&data, + hinic3_tx_queue_stats[j].name, i); + } + + for (i =3D 0; i < nic_dev->q_params.num_qps; i++) { + for (j =3D 0; j < ARRAY_SIZE(hinic3_rx_queue_stats); j++) + ethtool_sprintf(&data, + hinic3_rx_queue_stats[j].name, i); + } +} + +static void hinic3_get_strings(struct net_device *netdev, + u32 stringset, u8 *data) +{ + char *p =3D (char *)data; + u16 offset; + + switch (stringset) { + case ETH_SS_STATS: + offset =3D hinic3_get_hw_stats_strings(netdev, p); + hinic3_get_qp_stats_strings(netdev, + p + offset * ETH_GSTRING_LEN); + + return; + default: + netdev_err(netdev, "Invalid string set %u.\n", stringset); + return; + } +} + +static void hinic3_get_eth_phy_stats(struct net_device *netdev, + struct ethtool_eth_phy_stats *phy_stats) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct mag_cmd_port_stats *ps; + int err; + + if (HINIC3_IS_VF(nic_dev->hwdev)) + return; + + ps =3D kmalloc_obj(*ps); + if (!ps) + return; + + err =3D hinic3_get_phy_port_stats(nic_dev->hwdev, ps); + if (err) { + kfree(ps); + netdev_err(netdev, "Failed to get eth phy stats from fw\n"); + return; + } + + phy_stats->SymbolErrorDuringCarrier =3D ps->mac_rx_sym_err_pkt_num; + + kfree(ps); +} + +static void hinic3_get_eth_mac_stats(struct net_device *netdev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct mag_cmd_port_stats *ps; + int err; + + ps =3D kmalloc_obj(*ps); + if (!ps) + return; + + err =3D hinic3_get_phy_port_stats(nic_dev->hwdev, ps); + if (err) { + kfree(ps); + netdev_err(netdev, "Failed to get eth mac stats from fw\n"); + return; + } + + mac_stats->FramesTransmittedOK =3D ps->mac_tx_good_pkt_num; + mac_stats->FramesReceivedOK =3D ps->mac_rx_good_pkt_num; + mac_stats->FrameCheckSequenceErrors =3D ps->mac_rx_fcs_err_pkt_num; + mac_stats->OctetsTransmittedOK =3D ps->mac_tx_good_oct_num; + mac_stats->OctetsReceivedOK =3D ps->mac_rx_good_oct_num; + mac_stats->MulticastFramesXmittedOK =3D ps->mac_tx_multi_pkt_num; + mac_stats->BroadcastFramesXmittedOK =3D ps->mac_tx_broad_pkt_num; + mac_stats->MulticastFramesReceivedOK =3D ps->mac_rx_multi_pkt_num; + mac_stats->BroadcastFramesReceivedOK =3D ps->mac_rx_broad_pkt_num; + + kfree(ps); +} + +static void hinic3_get_eth_ctrl_stats(struct net_device *netdev, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct mag_cmd_port_stats *ps; + int err; + + ps =3D kmalloc_obj(*ps); + if (!ps) + return; + + err =3D hinic3_get_phy_port_stats(nic_dev->hwdev, ps); + if (err) { + kfree(ps); + netdev_err(netdev, "Failed to get eth ctrl stats from fw\n"); + return; + } + + ctrl_stats->MACControlFramesTransmitted =3D ps->mac_tx_control_pkt_num; + ctrl_stats->MACControlFramesReceived =3D ps->mac_rx_control_pkt_num; + + kfree(ps); +} + +static const struct ethtool_rmon_hist_range hinic3_rmon_ranges[] =3D { + { 0, 64 }, + { 65, 127 }, + { 128, 255 }, + { 256, 511 }, + { 512, 1023 }, + { 1024, 1518 }, + { 1519, 2047 }, + { 2048, 4095 }, + { 4096, 8191 }, + { 8192, 9216 }, + { 9217, 12287 }, + {} +}; + +static void hinic3_get_rmon_stats(struct net_device *netdev, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct mag_cmd_port_stats *ps; + int err; + + ps =3D kmalloc_obj(*ps); + if (!ps) + return; + + err =3D hinic3_get_phy_port_stats(nic_dev->hwdev, ps); + if (err) { + kfree(ps); + netdev_err(netdev, "Failed to get eth rmon stats from fw\n"); + return; + } + + rmon_stats->undersize_pkts =3D ps->mac_rx_undersize_pkt_num; + rmon_stats->oversize_pkts =3D ps->mac_rx_oversize_pkt_num; + rmon_stats->fragments =3D ps->mac_rx_fragment_pkt_num; + rmon_stats->jabbers =3D ps->mac_rx_jabber_pkt_num; + + rmon_stats->hist[0] =3D ps->mac_rx_64_oct_pkt_num; + rmon_stats->hist[1] =3D ps->mac_rx_65_127_oct_pkt_num; + rmon_stats->hist[2] =3D ps->mac_rx_128_255_oct_pkt_num; + rmon_stats->hist[3] =3D ps->mac_rx_256_511_oct_pkt_num; + rmon_stats->hist[4] =3D ps->mac_rx_512_1023_oct_pkt_num; + rmon_stats->hist[5] =3D ps->mac_rx_1024_1518_oct_pkt_num; + rmon_stats->hist[6] =3D ps->mac_rx_1519_2047_oct_pkt_num; + rmon_stats->hist[7] =3D ps->mac_rx_2048_4095_oct_pkt_num; + rmon_stats->hist[8] =3D ps->mac_rx_4096_8191_oct_pkt_num; + rmon_stats->hist[9] =3D ps->mac_rx_8192_9216_oct_pkt_num; + rmon_stats->hist[10] =3D ps->mac_rx_9217_12287_oct_pkt_num; + + rmon_stats->hist_tx[0] =3D ps->mac_tx_64_oct_pkt_num; + rmon_stats->hist_tx[1] =3D ps->mac_tx_65_127_oct_pkt_num; + rmon_stats->hist_tx[2] =3D ps->mac_tx_128_255_oct_pkt_num; + rmon_stats->hist_tx[3] =3D ps->mac_tx_256_511_oct_pkt_num; + rmon_stats->hist_tx[4] =3D ps->mac_tx_512_1023_oct_pkt_num; + rmon_stats->hist_tx[5] =3D ps->mac_tx_1024_1518_oct_pkt_num; + rmon_stats->hist_tx[6] =3D ps->mac_tx_1519_2047_oct_pkt_num; + rmon_stats->hist_tx[7] =3D ps->mac_tx_2048_4095_oct_pkt_num; + rmon_stats->hist_tx[8] =3D ps->mac_tx_4096_8191_oct_pkt_num; + rmon_stats->hist_tx[9] =3D ps->mac_tx_8192_9216_oct_pkt_num; + rmon_stats->hist_tx[10] =3D ps->mac_tx_9217_12287_oct_pkt_num; + + *ranges =3D hinic3_rmon_ranges; + + kfree(ps); +} + +static void hinic3_get_pause_stats(struct net_device *netdev, + struct ethtool_pause_stats *pause_stats) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct mag_cmd_port_stats *ps; + int err; + + ps =3D kmalloc_obj(*ps); + if (!ps) + return; + + err =3D hinic3_get_phy_port_stats(nic_dev->hwdev, ps); + if (err) { + kfree(ps); + netdev_err(netdev, "Failed to get eth pause stats from fw\n"); + return; + } + + pause_stats->tx_pause_frames =3D ps->mac_tx_pause_num; + pause_stats->rx_pause_frames =3D ps->mac_rx_pause_num; + + kfree(ps); +} + static const struct ethtool_ops hinic3_ethtool_ops =3D { .supported_coalesce_params =3D ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_PKT_RATE_RX_USECS, @@ -417,6 +885,14 @@ static const struct ethtool_ops hinic3_ethtool_ops =3D= { .get_msglevel =3D hinic3_get_msglevel, .set_msglevel =3D hinic3_set_msglevel, .get_link =3D ethtool_op_get_link, + .get_sset_count =3D hinic3_get_sset_count, + .get_ethtool_stats =3D hinic3_get_ethtool_stats, + .get_strings =3D hinic3_get_strings, + .get_eth_phy_stats =3D hinic3_get_eth_phy_stats, + .get_eth_mac_stats =3D hinic3_get_eth_mac_stats, + .get_eth_ctrl_stats =3D hinic3_get_eth_ctrl_stats, + .get_rmon_stats =3D hinic3_get_rmon_stats, + .get_pause_stats =3D hinic3_get_pause_stats, }; =20 void hinic3_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_intf.h index cfc9daa3034f..6b0f486ba590 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h @@ -53,6 +53,17 @@ static inline void mgmt_msg_params_init_default(struct m= gmt_msg_params *msg_para msg_params->timeout_ms =3D 0; } =20 +static inline void +mgmt_msg_params_init_in_out(struct mgmt_msg_params *msg_params, void *in_b= uf, + void *out_buf, u32 in_buf_size, u32 out_buf_size) +{ + msg_params->buf_in =3D in_buf; + msg_params->buf_out =3D out_buf; + msg_params->in_size =3D in_buf_size; + msg_params->expected_out_size =3D out_buf_size; + msg_params->timeout_ms =3D 0; +} + enum cfg_cmd { CFG_CMD_GET_DEV_CAP =3D 0, }; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/d= rivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index c5bca3c4af96..76c691f82703 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -143,6 +143,41 @@ struct l2nic_cmd_set_dcb_state { u8 rsvd[7]; }; =20 +struct l2nic_port_stats_info { + struct mgmt_msg_head msg_head; + u16 func_id; + u16 rsvd1; +}; + +struct l2nic_vport_stats { + u64 tx_unicast_pkts_vport; + u64 tx_unicast_bytes_vport; + u64 tx_multicast_pkts_vport; + u64 tx_multicast_bytes_vport; + u64 tx_broadcast_pkts_vport; + u64 tx_broadcast_bytes_vport; + + u64 rx_unicast_pkts_vport; + u64 rx_unicast_bytes_vport; + u64 rx_multicast_pkts_vport; + u64 rx_multicast_bytes_vport; + u64 rx_broadcast_pkts_vport; + u64 rx_broadcast_bytes_vport; + + u64 tx_discard_vport; + u64 rx_discard_vport; + u64 tx_err_vport; + u64 rx_err_vport; +}; + +struct l2nic_cmd_vport_stats { + struct mgmt_msg_head msg_head; + u32 stats_size; + u32 rsvd1; + struct l2nic_vport_stats stats; + u64 rsvd2[6]; +}; + struct l2nic_cmd_lro_config { struct mgmt_msg_head msg_head; u16 func_id; @@ -234,6 +269,7 @@ enum l2nic_cmd { L2NIC_CMD_SET_VPORT_ENABLE =3D 6, L2NIC_CMD_SET_RX_MODE =3D 7, L2NIC_CMD_SET_SQ_CI_ATTR =3D 8, + L2NIC_CMD_GET_VPORT_STAT =3D 9, L2NIC_CMD_CLEAR_QP_RESOURCE =3D 11, L2NIC_CMD_CFG_RX_LRO =3D 13, L2NIC_CMD_CFG_LRO_TIMER =3D 14, @@ -272,6 +308,7 @@ enum mag_cmd { MAG_CMD_SET_PORT_ENABLE =3D 6, MAG_CMD_GET_LINK_STATUS =3D 7, =20 + MAG_CMD_GET_PORT_STAT =3D 151, MAG_CMD_GET_PORT_INFO =3D 153, }; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index de5a7984d2cb..1b14dc824ce1 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -639,6 +639,42 @@ int hinic3_get_link_status(struct hinic3_hwdev *hwdev,= bool *link_status_up) return 0; } =20 +int hinic3_get_phy_port_stats(struct hinic3_hwdev *hwdev, + struct mag_cmd_port_stats *stats) +{ + struct mag_cmd_port_stats_info stats_info =3D {}; + struct mag_cmd_get_port_stat *ps; + struct mgmt_msg_params msg_params =3D {}; + int err; + + ps =3D kzalloc_obj(*ps); + if (!ps) + return -ENOMEM; + + stats_info.port_id =3D hinic3_physical_port_id(hwdev); + + mgmt_msg_params_init_in_out(&msg_params, &stats_info, ps, + sizeof(stats_info), sizeof(*ps)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_HILINK, + MAG_CMD_GET_PORT_STAT, &msg_params); + + if (err || ps->head.status) { + dev_err(hwdev->dev, + "Failed to get port statistics, err: %d, status: 0x%x\n", + err, ps->head.status); + err =3D -EFAULT; + goto out; + } + + memcpy(stats, &ps->counter, sizeof(*stats)); + +out: + kfree(ps); + + return err; +} + int hinic3_get_port_info(struct hinic3_hwdev *hwdev, struct hinic3_nic_port_info *port_info) { @@ -738,3 +774,31 @@ int hinic3_get_pause_info(struct hinic3_nic_dev *nic_d= ev, return hinic3_cfg_hw_pause(nic_dev->hwdev, MGMT_MSG_CMD_OP_GET, nic_pause); } + +int hinic3_get_vport_stats(struct hinic3_hwdev *hwdev, u16 func_id, + struct l2nic_vport_stats *stats) +{ + struct l2nic_cmd_vport_stats vport_stats =3D {}; + struct l2nic_port_stats_info stats_info =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + stats_info.func_id =3D func_id; + + mgmt_msg_params_init_in_out(&msg_params, &stats_info, &vport_stats, + sizeof(stats_info), sizeof(vport_stats)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_GET_VPORT_STAT, &msg_params); + + if (err || vport_stats.msg_head.status) { + dev_err(hwdev->dev, + "Failed to get function statistics, err: %d, status: 0x%x\n", + err, vport_stats.msg_head.status); + return -EFAULT; + } + + memcpy(stats, &vport_stats.stats, sizeof(*stats)); + + return 0; +} diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index 5d52202a8d4e..80573c121539 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -129,6 +129,110 @@ struct mag_cmd_get_xsfp_present { u8 rsvd[2]; }; =20 +struct mag_cmd_port_stats { + u64 mac_tx_fragment_pkt_num; + u64 mac_tx_undersize_pkt_num; + u64 mac_tx_undermin_pkt_num; + u64 mac_tx_64_oct_pkt_num; + u64 mac_tx_65_127_oct_pkt_num; + u64 mac_tx_128_255_oct_pkt_num; + u64 mac_tx_256_511_oct_pkt_num; + u64 mac_tx_512_1023_oct_pkt_num; + u64 mac_tx_1024_1518_oct_pkt_num; + u64 mac_tx_1519_2047_oct_pkt_num; + u64 mac_tx_2048_4095_oct_pkt_num; + u64 mac_tx_4096_8191_oct_pkt_num; + u64 mac_tx_8192_9216_oct_pkt_num; + u64 mac_tx_9217_12287_oct_pkt_num; + u64 mac_tx_12288_16383_oct_pkt_num; + u64 mac_tx_1519_max_bad_pkt_num; + u64 mac_tx_1519_max_good_pkt_num; + u64 mac_tx_oversize_pkt_num; + u64 mac_tx_jabber_pkt_num; + u64 mac_tx_bad_pkt_num; + u64 mac_tx_bad_oct_num; + u64 mac_tx_good_pkt_num; + u64 mac_tx_good_oct_num; + u64 mac_tx_total_pkt_num; + u64 mac_tx_total_oct_num; + u64 mac_tx_uni_pkt_num; + u64 mac_tx_multi_pkt_num; + u64 mac_tx_broad_pkt_num; + u64 mac_tx_pause_num; + u64 mac_tx_pfc_pkt_num; + u64 mac_tx_pfc_pri0_pkt_num; + u64 mac_tx_pfc_pri1_pkt_num; + u64 mac_tx_pfc_pri2_pkt_num; + u64 mac_tx_pfc_pri3_pkt_num; + u64 mac_tx_pfc_pri4_pkt_num; + u64 mac_tx_pfc_pri5_pkt_num; + u64 mac_tx_pfc_pri6_pkt_num; + u64 mac_tx_pfc_pri7_pkt_num; + u64 mac_tx_control_pkt_num; + u64 mac_tx_err_all_pkt_num; + u64 mac_tx_from_app_good_pkt_num; + u64 mac_tx_from_app_bad_pkt_num; + + u64 mac_rx_fragment_pkt_num; + u64 mac_rx_undersize_pkt_num; + u64 mac_rx_undermin_pkt_num; + u64 mac_rx_64_oct_pkt_num; + u64 mac_rx_65_127_oct_pkt_num; + u64 mac_rx_128_255_oct_pkt_num; + u64 mac_rx_256_511_oct_pkt_num; + u64 mac_rx_512_1023_oct_pkt_num; + u64 mac_rx_1024_1518_oct_pkt_num; + u64 mac_rx_1519_2047_oct_pkt_num; + u64 mac_rx_2048_4095_oct_pkt_num; + u64 mac_rx_4096_8191_oct_pkt_num; + u64 mac_rx_8192_9216_oct_pkt_num; + u64 mac_rx_9217_12287_oct_pkt_num; + u64 mac_rx_12288_16383_oct_pkt_num; + u64 mac_rx_1519_max_bad_pkt_num; + u64 mac_rx_1519_max_good_pkt_num; + u64 mac_rx_oversize_pkt_num; + u64 mac_rx_jabber_pkt_num; + u64 mac_rx_bad_pkt_num; + u64 mac_rx_bad_oct_num; + u64 mac_rx_good_pkt_num; + u64 mac_rx_good_oct_num; + u64 mac_rx_total_pkt_num; + u64 mac_rx_total_oct_num; + u64 mac_rx_uni_pkt_num; + u64 mac_rx_multi_pkt_num; + u64 mac_rx_broad_pkt_num; + u64 mac_rx_pause_num; + u64 mac_rx_pfc_pkt_num; + u64 mac_rx_pfc_pri0_pkt_num; + u64 mac_rx_pfc_pri1_pkt_num; + u64 mac_rx_pfc_pri2_pkt_num; + u64 mac_rx_pfc_pri3_pkt_num; + u64 mac_rx_pfc_pri4_pkt_num; + u64 mac_rx_pfc_pri5_pkt_num; + u64 mac_rx_pfc_pri6_pkt_num; + u64 mac_rx_pfc_pri7_pkt_num; + u64 mac_rx_control_pkt_num; + u64 mac_rx_sym_err_pkt_num; + u64 mac_rx_fcs_err_pkt_num; + u64 mac_rx_send_app_good_pkt_num; + u64 mac_rx_send_app_bad_pkt_num; + u64 mac_rx_unfilter_pkt_num; +}; + +struct mag_cmd_port_stats_info { + struct mgmt_msg_head head; + + u8 port_id; + u8 rsvd0[3]; +}; + +struct mag_cmd_get_port_stat { + struct mgmt_msg_head head; + + struct mag_cmd_port_stats counter; + u64 rsvd1[15]; +}; + enum link_err_type { LINK_ERR_MODULE_UNRECOGENIZED, LINK_ERR_NUM, @@ -209,6 +313,11 @@ int hinic3_get_port_info(struct hinic3_hwdev *hwdev, struct hinic3_nic_port_info *port_info); int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id, bool enable); +int hinic3_get_phy_port_stats(struct hinic3_hwdev *hwdev, + struct mag_cmd_port_stats *stats); +int hinic3_get_vport_stats(struct hinic3_hwdev *hwdev, u16 func_id, + struct l2nic_vport_stats *stats); + int hinic3_add_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id); int hinic3_del_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id); =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 9502293ff710..7ff699984cee 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -10,6 +10,8 @@ #include "hinic3_hw_cfg.h" #include "hinic3_hwdev.h" #include "hinic3_mgmt_interface.h" +#include "hinic3_rx.h" +#include "hinic3_tx.h" =20 #define HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev) (sizeof(*(nic_dev)->vlan_bi= tmap)) #define HINIC3_VLAN_BITMAP_SIZE(nic_dev) \ diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c b/drivers/net/e= thernet/huawei/hinic3/hinic3_rx.c index 309ab5901379..298fc0817680 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c @@ -28,10 +28,6 @@ =20 #define HINIC3_LRO_PKT_HDR_LEN_IPV4 66 #define HINIC3_LRO_PKT_HDR_LEN_IPV6 86 -#define HINIC3_LRO_PKT_HDR_LEN(cqe) \ - (RQ_CQE_OFFOLAD_TYPE_GET((cqe)->offload_type, IP_TYPE) =3D=3D \ - HINIC3_RX_IPV6_PKT ? HINIC3_LRO_PKT_HDR_LEN_IPV6 : \ - HINIC3_LRO_PKT_HDR_LEN_IPV4) =20 static void hinic3_rxq_clean_stats(struct hinic3_rxq_stats *rxq_stats) { @@ -46,7 +42,6 @@ static void hinic3_rxq_clean_stats(struct hinic3_rxq_stat= s *rxq_stats) =20 rxq_stats->alloc_skb_err =3D 0; rxq_stats->alloc_rx_buf_err =3D 0; - rxq_stats->restore_drop_sge =3D 0; u64_stats_update_end(&rxq_stats->syncp); } =20 @@ -147,6 +142,8 @@ static u32 hinic3_rx_fill_buffers(struct hinic3_rxq *rx= q) { u32 i, free_wqebbs =3D rxq->delta - 1; struct hinic3_rx_info *rx_info; + struct u64_stats_sync *syncp; + unsigned long flags; dma_addr_t dma_addr; int err; =20 @@ -155,8 +152,13 @@ static u32 hinic3_rx_fill_buffers(struct hinic3_rxq *r= xq) =20 err =3D rx_alloc_mapped_page(rxq->page_pool, rx_info, rxq->buf_len); - if (unlikely(err)) + if (unlikely(err)) { + syncp =3D &rxq->rxq_stats.syncp; + flags =3D u64_stats_update_begin_irqsave(syncp); + rxq->rxq_stats.alloc_rx_buf_err++; + u64_stats_update_end_irqrestore(syncp, flags); break; + } =20 dma_addr =3D page_pool_get_dma_addr(rx_info->page) + rx_info->page_offset; @@ -170,6 +172,11 @@ static u32 hinic3_rx_fill_buffers(struct hinic3_rxq *r= xq) rxq->next_to_update << HINIC3_NORMAL_RQ_WQE); rxq->delta -=3D i; rxq->next_to_alloc =3D rxq->next_to_update; + } else if (free_wqebbs =3D=3D rxq->q_depth - 1) { + syncp =3D &rxq->rxq_stats.syncp; + flags =3D u64_stats_update_begin_irqsave(syncp); + rxq->rxq_stats.rx_buf_empty++; + u64_stats_update_end_irqrestore(syncp, flags); } =20 return i; @@ -330,11 +337,24 @@ static void hinic3_rx_csum(struct hinic3_rxq *rxq, u3= 2 offload_type, struct net_device *netdev =3D rxq->netdev; bool l2_tunnel; =20 + /* HW ensures that only 1 bit is set in csum_err. */ + if (unlikely(csum_err =3D=3D HINIC3_RX_CSUM_IPSU_OTHER_ERR)) { + u64_stats_update_begin(&rxq->rxq_stats.syncp); + rxq->rxq_stats.other_errors++; + u64_stats_update_end(&rxq->rxq_stats.syncp); + } + if (!(netdev->features & NETIF_F_RXCSUM)) return; =20 if (unlikely(csum_err)) { /* pkt type is recognized by HW, and csum is wrong */ + if (csum_err !=3D HINIC3_RX_CSUM_HW_CHECK_NONE && + csum_err !=3D HINIC3_RX_CSUM_IPSU_OTHER_ERR) { + u64_stats_update_begin(&rxq->rxq_stats.syncp); + rxq->rxq_stats.csum_errors++; + u64_stats_update_end(&rxq->rxq_stats.syncp); + } skb->ip_summed =3D CHECKSUM_NONE; return; } @@ -387,8 +407,12 @@ static int recv_one_pkt(struct hinic3_rxq *rxq, struct= hinic3_rq_cqe *rx_cqe, u16 num_lro; =20 skb =3D hinic3_fetch_rx_buffer(rxq, pkt_len); - if (unlikely(!skb)) + if (unlikely(!skb)) { + u64_stats_update_begin(&rxq->rxq_stats.syncp); + rxq->rxq_stats.alloc_skb_err++; + u64_stats_update_end(&rxq->rxq_stats.syncp); return -ENOMEM; + } =20 /* place header in linear portion of buffer */ if (skb_is_nonlinear(skb)) @@ -550,11 +574,29 @@ int hinic3_configure_rxqs(struct net_device *netdev, = u16 num_rq, return 0; } =20 +void hinic3_rxq_get_stats(struct hinic3_rxq *rxq, + struct hinic3_rxq_stats *stats) +{ + struct hinic3_rxq_stats *rxq_stats =3D &rxq->rxq_stats; + unsigned int start; + + do { + start =3D u64_stats_fetch_begin(&rxq_stats->syncp); + stats->csum_errors =3D rxq_stats->csum_errors; + stats->other_errors =3D rxq_stats->other_errors; + stats->rx_buf_empty =3D rxq_stats->rx_buf_empty; + stats->alloc_skb_err =3D rxq_stats->alloc_skb_err; + stats->alloc_rx_buf_err =3D rxq_stats->alloc_rx_buf_err; + } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); +} + int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(rxq->netdev); + u32 ip_type, offload_type, pkt_hdr_len; u32 sw_ci, status, pkt_len, vlan_len; struct hinic3_rq_cqe *rx_cqe; + u64 rx_bytes =3D 0; u32 num_wqe =3D 0; int nr_pkts =3D 0; u16 num_lro; @@ -574,10 +616,20 @@ int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget) if (recv_one_pkt(rxq, rx_cqe, pkt_len, vlan_len, status)) break; =20 + rx_bytes +=3D pkt_len; nr_pkts++; num_lro =3D RQ_CQE_STATUS_GET(status, NUM_LRO); - if (num_lro) + if (num_lro) { + offload_type =3D le32_to_cpu(rx_cqe->offload_type); + ip_type =3D RQ_CQE_OFFOLAD_TYPE_GET(offload_type, + IP_TYPE); + pkt_hdr_len =3D ip_type =3D=3D HINIC3_RX_IPV6_PKT ? + HINIC3_LRO_PKT_HDR_LEN_IPV6 : + HINIC3_LRO_PKT_HDR_LEN_IPV4; + + rx_bytes +=3D (num_lro - 1) * pkt_hdr_len; num_wqe +=3D hinic3_get_sge_num(rxq, pkt_len); + } =20 rx_cqe->status =3D 0; =20 @@ -588,5 +640,10 @@ int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget) if (rxq->delta >=3D HINIC3_RX_BUFFER_WRITE) hinic3_rx_fill_buffers(rxq); =20 + u64_stats_update_begin(&rxq->rxq_stats.syncp); + rxq->rxq_stats.packets +=3D (u64)nr_pkts; + rxq->rxq_stats.bytes +=3D rx_bytes; + u64_stats_update_end(&rxq->rxq_stats.syncp); + return nr_pkts; } diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h b/drivers/net/e= thernet/huawei/hinic3/hinic3_rx.h index 06d1b3299e7c..c11d080408a7 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h @@ -8,6 +8,17 @@ #include #include =20 +/* rx cqe checksum err */ +#define HINIC3_RX_CSUM_IP_CSUM_ERR BIT(0) +#define HINIC3_RX_CSUM_TCP_CSUM_ERR BIT(1) +#define HINIC3_RX_CSUM_UDP_CSUM_ERR BIT(2) +#define HINIC3_RX_CSUM_IGMP_CSUM_ERR BIT(3) +#define HINIC3_RX_CSUM_ICMPV4_CSUM_ERR BIT(4) +#define HINIC3_RX_CSUM_ICMPV6_CSUM_ERR BIT(5) +#define HINIC3_RX_CSUM_SCTP_CRC_ERR BIT(6) +#define HINIC3_RX_CSUM_HW_CHECK_NONE BIT(7) +#define HINIC3_RX_CSUM_IPSU_OTHER_ERR BIT(8) + #define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK GENMASK(4, 0) #define RQ_CQE_OFFOLAD_TYPE_IP_TYPE_MASK GENMASK(6, 5) #define RQ_CQE_OFFOLAD_TYPE_TUNNEL_PKT_FORMAT_MASK GENMASK(11, 8) @@ -39,7 +50,6 @@ struct hinic3_rxq_stats { u64 rx_buf_empty; u64 alloc_skb_err; u64 alloc_rx_buf_err; - u64 restore_drop_sge; struct u64_stats_sync syncp; }; =20 @@ -123,6 +133,9 @@ void hinic3_free_rxqs_res(struct net_device *netdev, u1= 6 num_rq, u32 rq_depth, struct hinic3_dyna_rxq_res *rxqs_res); int hinic3_configure_rxqs(struct net_device *netdev, u16 num_rq, u32 rq_depth, struct hinic3_dyna_rxq_res *rxqs_res); + +void hinic3_rxq_get_stats(struct hinic3_rxq *rxq, + struct hinic3_rxq_stats *stats); int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget); =20 #endif diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c b/drivers/net/e= thernet/huawei/hinic3/hinic3_tx.c index 9306bf0020ca..6219cc10918d 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c @@ -25,11 +25,9 @@ static void hinic3_txq_clean_stats(struct hinic3_txq_sta= ts *txq_stats) txq_stats->dropped =3D 0; =20 txq_stats->skb_pad_err =3D 0; - txq_stats->frag_len_overflow =3D 0; txq_stats->offload_cow_skb_err =3D 0; txq_stats->map_frag_err =3D 0; txq_stats->unknown_tunnel_pkt =3D 0; - txq_stats->frag_size_err =3D 0; u64_stats_update_end(&txq_stats->syncp); } =20 @@ -97,8 +95,12 @@ static int hinic3_tx_map_skb(struct net_device *netdev, = struct sk_buff *skb, =20 dma_info[0].dma =3D dma_map_single(&pdev->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - if (dma_mapping_error(&pdev->dev, dma_info[0].dma)) + if (dma_mapping_error(&pdev->dev, dma_info[0].dma)) { + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.map_frag_err++; + u64_stats_update_end(&txq->txq_stats.syncp); return -EFAULT; + } =20 dma_info[0].len =3D skb_headlen(skb); =20 @@ -117,6 +119,9 @@ static int hinic3_tx_map_skb(struct net_device *netdev,= struct sk_buff *skb, skb_frag_size(frag), DMA_TO_DEVICE); if (dma_mapping_error(&pdev->dev, dma_info[idx].dma)) { + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.map_frag_err++; + u64_stats_update_end(&txq->txq_stats.syncp); err =3D -EFAULT; goto err_unmap_page; } @@ -260,6 +265,9 @@ static int hinic3_tx_csum(struct hinic3_txq *txq, struc= t hinic3_sq_task *task, if (l4_proto !=3D IPPROTO_UDP || ((struct udphdr *)skb_transport_header(skb))->dest !=3D VXLAN_OFFLOAD_PORT_LE) { + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.unknown_tunnel_pkt++; + u64_stats_update_end(&txq->txq_stats.syncp); /* Unsupported tunnel packet, disable csum offload */ skb_checksum_help(skb); return 0; @@ -433,6 +441,27 @@ static u32 hinic3_tx_offload(struct sk_buff *skb, stru= ct hinic3_sq_task *task, return offload; } =20 +static void hinic3_get_pkt_stats(struct hinic3_txq *txq, struct sk_buff *s= kb) +{ + u32 hdr_len, tx_bytes; + unsigned short pkts; + + if (skb_is_gso(skb)) { + hdr_len =3D (skb_shinfo(skb)->gso_segs - 1) * + skb_tcp_all_headers(skb); + tx_bytes =3D skb->len + hdr_len; + pkts =3D skb_shinfo(skb)->gso_segs; + } else { + tx_bytes =3D skb->len > ETH_ZLEN ? skb->len : ETH_ZLEN; + pkts =3D 1; + } + + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.bytes +=3D tx_bytes; + txq->txq_stats.packets +=3D pkts; + u64_stats_update_end(&txq->txq_stats.syncp); +} + static u16 hinic3_get_and_update_sq_owner(struct hinic3_io_queue *sq, u16 curr_pi, u16 wqebb_cnt) { @@ -539,8 +568,12 @@ static netdev_tx_t hinic3_send_one_skb(struct sk_buff = *skb, int err; =20 if (unlikely(skb->len < MIN_SKB_LEN)) { - if (skb_pad(skb, MIN_SKB_LEN - skb->len)) + if (skb_pad(skb, MIN_SKB_LEN - skb->len)) { + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.skb_pad_err++; + u64_stats_update_end(&txq->txq_stats.syncp); goto err_out; + } =20 skb->len =3D MIN_SKB_LEN; } @@ -557,11 +590,17 @@ static netdev_tx_t hinic3_send_one_skb(struct sk_buff= *skb, hinic3_wq_free_wqebbs(&txq->sq->wq), txq->tx_start_thrs); =20 + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.busy++; + u64_stats_update_end(&txq->txq_stats.syncp); return NETDEV_TX_BUSY; } =20 offload =3D hinic3_tx_offload(skb, &task, &queue_info, txq); if (unlikely(offload =3D=3D HINIC3_TX_OFFLOAD_INVALID)) { + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.offload_cow_skb_err++; + u64_stats_update_end(&txq->txq_stats.syncp); goto err_drop_pkt; } else if (!offload) { wqebb_cnt -=3D 1; @@ -595,6 +634,7 @@ static netdev_tx_t hinic3_send_one_skb(struct sk_buff *= skb, txq->tx_stop_thrs, txq->tx_start_thrs); =20 + hinic3_get_pkt_stats(txq, skb); hinic3_prepare_sq_ctrl(&wqe_combo, queue_info, num_sge, owner); hinic3_write_db(txq->sq, 0, DB_CFLAG_DP_SQ, hinic3_get_sq_local_pi(txq->sq)); @@ -604,6 +644,10 @@ static netdev_tx_t hinic3_send_one_skb(struct sk_buff = *skb, err_drop_pkt: dev_kfree_skb_any(skb); err_out: + u64_stats_update_begin(&txq->txq_stats.syncp); + txq->txq_stats.dropped++; + u64_stats_update_end(&txq->txq_stats.syncp); + return NETDEV_TX_OK; } =20 @@ -754,6 +798,22 @@ int hinic3_configure_txqs(struct net_device *netdev, u= 16 num_sq, return 0; } =20 +void hinic3_txq_get_stats(struct hinic3_txq *txq, + struct hinic3_txq_stats *stats) +{ + struct hinic3_txq_stats *txq_stats =3D &txq->txq_stats; + unsigned int start; + + do { + start =3D u64_stats_fetch_begin(&txq_stats->syncp); + stats->busy =3D txq_stats->busy; + stats->skb_pad_err =3D txq_stats->skb_pad_err; + stats->offload_cow_skb_err =3D txq_stats->offload_cow_skb_err; + stats->map_frag_err =3D txq_stats->map_frag_err; + stats->unknown_tunnel_pkt =3D txq_stats->unknown_tunnel_pkt; + } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); +} + bool hinic3_tx_poll(struct hinic3_txq *txq, int budget) { struct net_device *netdev =3D txq->netdev; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h b/drivers/net/e= thernet/huawei/hinic3/hinic3_tx.h index 00194f2a1bcc..6abf443cb927 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h @@ -106,11 +106,9 @@ struct hinic3_txq_stats { u64 busy; u64 dropped; u64 skb_pad_err; - u64 frag_len_overflow; u64 offload_cow_skb_err; u64 map_frag_err; u64 unknown_tunnel_pkt; - u64 frag_size_err; struct u64_stats_sync syncp; }; =20 @@ -157,6 +155,8 @@ int hinic3_configure_txqs(struct net_device *netdev, u1= 6 num_sq, u32 sq_depth, struct hinic3_dyna_txq_res *txqs_res); =20 netdev_tx_t hinic3_xmit_frame(struct sk_buff *skb, struct net_device *netd= ev); +void hinic3_txq_get_stats(struct hinic3_txq *txq, + struct hinic3_txq_stats *stats); bool hinic3_tx_poll(struct hinic3_txq *txq, int budget); void hinic3_flush_txqs(struct net_device *netdev); =20 --=20 2.54.0 From nobody Mon Sep 28 21:52:15 2026 Received: from canpmsgout01.his.huawei.com (canpmsgout01.his.huawei.com [113.46.200.216]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A2FEA22FE0E; Mon, 17 Aug 2026 02:04:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.216 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786932286; cv=none; b=mxyAk9zg1G83h1p/pPogSZeD1/gDOwsqUbiZbQ3eRYLke/DlE9Ygzxn+dJuq7Z9NGr1pDo4c1rt8s3BFy5SkgLJjAhkho9kRDs3GrG5iIzy7IcAgkafcqsurY3hTbX1ZZ3J68ndvtjgDgkl4GeY6aiq8dfQO82pcmv0asE2Bx5s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786932286; c=relaxed/simple; bh=yz/pLDWG/EG+2WfoocDdbpYmTAbJnteeQfdaxagrbYw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=U1v/Z3V4Y3xCr0LCZQLBAg5hXGvlpBSmLTnWryRH6qtA2wuHTJsIXTRmNwt3niBTUQKGVGLJv7EWxJnrE/UB8bXtk2shUsIlbHrFuXFnXvYKQrR5Fdoz+uFKl3oYWK82c1VpVe3luXarnmakHwKDBeYt1e6wK4G8ECBt3/NfCwo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=CaJLZf3M; arc=none smtp.client-ip=113.46.200.216 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="CaJLZf3M" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=FLg0KK7dEB2S7YJc3MaBypDUfcxGsaoQDHUJaZiePGI=; b=CaJLZf3MZBWfeR+L4jmzOSOf9Tlp5P3W6/OA29LXndrdQUmUqKAnQj0jmdBkXVi3pDNe9/B6g kEFIOTZatbGX9NfTPE68zILxZJFG1CEkeWQAmjW8JbnV1i82BybpUxNvsQXGvscudsJ9XfxBa/y E6sBikq6Ln9hYliirirUlOE= Received: from mail.maildlp.com (unknown [172.19.163.104]) by canpmsgout01.his.huawei.com (SkyGuard) with ESMTPS id 4hNbVk34dbz1T4fq; Mon, 17 Aug 2026 09:54:38 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 75F6D4058C; Mon, 17 Aug 2026 10:04:35 +0800 (CST) Received: from DESKTOP-62GVMTR.china.huawei.com (10.174.189.124) by kwepemf100013.china.huawei.com (7.202.181.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Mon, 17 Aug 2026 10:04:34 +0800 From: Fan Gong To: Fan Gong , Wu Di , Teng Peisen , , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrew Lunn , Ioana Ciornei , Mohsin Bashir , Dimitri Daskalakis , Harshitha Ramamurthy , Larysa Zaremba CC: , , Chen Anwen , He Wei , luosifu , Xin Guo , Zhou Shuai , Wu Like , Shi Jing , Zheng Jiezhen , Maxime Chevallier Subject: [PATCH net-next v13 2/3] hinic3: Add ethtool coalesce ops Date: Mon, 17 Aug 2026 10:04:01 +0800 Message-ID: <84cdde27faa43486f39068db28dcf5c383ce9ed2.1786774752.git.tengpeisen@huawei.com> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: References: 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-ClientProxiedBy: kwepems200001.china.huawei.com (7.221.188.67) To kwepemf100013.china.huawei.com (7.202.181.12) Content-Type: text/plain; charset="utf-8" Implement following ethtool callback function: .get_coalesce .set_coalesce These callbacks allow users to utilize ethtool for detailed RX coalesce configuration and monitoring. Co-developed-by: Wu Di Signed-off-by: Wu Di Co-developed-by: Teng Peisen Signed-off-by: Teng Peisen Signed-off-by: Fan Gong --- .../ethernet/huawei/hinic3/hinic3_ethtool.c | 310 +++++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_irq.c | 2 +- .../net/ethernet/huawei/hinic3/hinic3_main.c | 4 +- .../huawei/hinic3/hinic3_netdev_ops.c | 4 +- .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 4 +- 5 files changed, 315 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_ethtool.c index e1d1f1ff4b6c..89a7ba211173 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c @@ -17,6 +17,11 @@ #include "hinic3_nic_cfg.h" =20 #define HINIC3_MGMT_VERSION_MAX_LEN 32 +/* Coalesce time properties in microseconds */ +#define COALESCE_PENDING_LIMIT_UNIT 8 +#define COALESCE_TIMER_CFG_UNIT 5 +#define COALESCE_MAX_PENDING_LIMIT (255 * COALESCE_PENDING_LIMIT_UNIT) +#define COALESCE_MAX_TIMER_CFG (255 * COALESCE_TIMER_CFG_UNIT) =20 static void hinic3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) @@ -877,9 +882,308 @@ static void hinic3_get_pause_stats(struct net_device = *netdev, kfree(ps); } =20 +static int hinic3_set_queue_coalesce(struct net_device *netdev, u16 q_id, + struct hinic3_intr_coal_info *coal, + struct netlink_ext_ack *extack) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_intr_coal_info *intr_coal; + struct hinic3_interrupt_info info =3D {}; + bool is_active; + int err; + + mutex_lock(&nic_dev->state_lock); + is_active =3D test_bit(HINIC3_INTF_UP, &nic_dev->flags) && + (q_id < nic_dev->q_params.num_qps); + + if (is_active) { + info.msix_index =3D + nic_dev->q_params.irq_cfg[q_id].msix_entry_idx; + info.resend_timer_cfg =3D + nic_dev->intr_coalesce[q_id].resend_timer_cfg; + } + mutex_unlock(&nic_dev->state_lock); + + if (is_active) { + info.interrupt_coalesc_set =3D 1; + info.coalesc_timer_cfg =3D coal->coalesce_timer_cfg; + info.pending_limit =3D coal->pending_limit; + + err =3D hinic3_set_interrupt_cfg(nic_dev->hwdev, info); + if (err) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Failed to set queue%u coalesce", + q_id); + return err; + } + } + + mutex_lock(&nic_dev->state_lock); + intr_coal =3D &nic_dev->intr_coalesce[q_id]; + intr_coal->coalesce_timer_cfg =3D coal->coalesce_timer_cfg; + intr_coal->pending_limit =3D coal->pending_limit; + intr_coal->rx_pending_limit_low =3D coal->rx_pending_limit_low; + intr_coal->rx_pending_limit_high =3D coal->rx_pending_limit_high; + mutex_unlock(&nic_dev->state_lock); + + return 0; +} + +static int is_coalesce_exceed_limit(const struct ethtool_coalesce *coal, + struct netlink_ext_ack *extack) +{ + const struct { + const char *name; + u32 value; + u32 limit; + } coalesce_limits[] =3D { + {"rx_coalesce_usecs", + coal->rx_coalesce_usecs, + COALESCE_MAX_TIMER_CFG}, + {"rx_max_coalesced_frames", + coal->rx_max_coalesced_frames, + COALESCE_MAX_PENDING_LIMIT}, + {"rx_max_coalesced_frames_low", + coal->rx_max_coalesced_frames_low, + COALESCE_MAX_PENDING_LIMIT}, + {"rx_max_coalesced_frames_high", + coal->rx_max_coalesced_frames_high, + COALESCE_MAX_PENDING_LIMIT}, + }; + + for (int i =3D 0; i < ARRAY_SIZE(coalesce_limits); i++) { + if (coalesce_limits[i].value > coalesce_limits[i].limit) { + NL_SET_ERR_MSG_FMT_MOD(extack, "%s out of range %d-%d", + coalesce_limits[i].name, 0, + coalesce_limits[i].limit); + return -ERANGE; + } + } + return 0; +} + +static int hinic3_validate_coalesce(const struct ethtool_coalesce *coal, + struct netlink_ext_ack *extack) +{ + int err; + + err =3D is_coalesce_exceed_limit(coal, extack); + if (err) + return err; + + if (coal->rx_max_coalesced_frames_low > + coal->rx_max_coalesced_frames_high) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "invalid coalesce frame high %u, low %u", + coal->rx_max_coalesced_frames_high, + coal->rx_max_coalesced_frames_low); + return -ERANGE; + } + + return 0; +} + +static void check_coalesce_align(struct net_device *netdev, + u32 item, u32 unit, const char *str) +{ + if (item % unit) + netdev_warn(netdev, "%s in %u units, change to %u\n", + str, unit, item - item % unit); +} + +#define CHECK_COALESCE_ALIGN(member, unit) \ + check_coalesce_align(netdev, member, unit, #member) + +static void check_coalesce_changed(struct net_device *netdev, + u32 item, u32 unit, u32 ori_val, + const char *obj_str, const char *str) +{ + if ((item / unit) !=3D ori_val) + netdev_dbg(netdev, "Change %s from %u to %u %s\n", + str, ori_val * unit, item - item % unit, obj_str); +} + +#define CHECK_COALESCE_CHANGED(member, unit, ori_val, obj_str) \ + check_coalesce_changed(netdev, member, unit, ori_val, obj_str, #member) + +static int hinic3_set_hw_coal_param(struct net_device *netdev, + struct hinic3_intr_coal_info *intr_coal, + struct netlink_ext_ack *extack) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_intr_coal_info *old_coal; + u16 i, j; + int err; + + old_coal =3D kcalloc(nic_dev->max_qps, sizeof(*old_coal), GFP_KERNEL); + if (!old_coal) + return -ENOMEM; + + mutex_lock(&nic_dev->state_lock); + for (i =3D 0; i < nic_dev->max_qps; i++) + old_coal[i] =3D nic_dev->intr_coalesce[i]; + mutex_unlock(&nic_dev->state_lock); + + for (i =3D 0; i < nic_dev->max_qps; i++) { + err =3D hinic3_set_queue_coalesce(netdev, i, intr_coal, extack); + if (err) + goto rollback; + } + + kfree(old_coal); + return 0; + +rollback: + for (j =3D 0; j < i; j++) + hinic3_set_queue_coalesce(netdev, j, &old_coal[j], NULL); + + kfree(old_coal); + return err; +} + +static int hinic3_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_intr_coal_info *interrupt_info; + + mutex_lock(&nic_dev->state_lock); + + interrupt_info =3D &nic_dev->intr_coalesce[0]; + + coal->use_adaptive_rx_coalesce =3D READ_ONCE(nic_dev->adaptive_rx_coal); + + coal->rx_max_coalesced_frames_low =3D + interrupt_info->rx_pending_limit_low * + COALESCE_PENDING_LIMIT_UNIT; + + coal->rx_max_coalesced_frames_high =3D + interrupt_info->rx_pending_limit_high * + COALESCE_PENDING_LIMIT_UNIT; + + /* TX/RX uses the same interrupt. + * So we only declare RX ethtool_coalesce parameters. + */ + coal->rx_coalesce_usecs =3D interrupt_info->coalesce_timer_cfg * + COALESCE_TIMER_CFG_UNIT; + + coal->rx_max_coalesced_frames =3D interrupt_info->pending_limit * + COALESCE_PENDING_LIMIT_UNIT; + + mutex_unlock(&nic_dev->state_lock); + + return 0; +} + +static int hinic3_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_intr_coal_info *ori_intr_coal; + struct hinic3_intr_coal_info intr_coal =3D {}; + const char *obj_str =3D "for netdev"; + bool old_adaptive, new_adaptive; + struct hinic3_rxq *rxq =3D NULL; + int err; + int i; + + err =3D hinic3_validate_coalesce(coal, extack); + if (err) + return err; + + CHECK_COALESCE_ALIGN(coal->rx_coalesce_usecs, COALESCE_TIMER_CFG_UNIT); + CHECK_COALESCE_ALIGN(coal->rx_max_coalesced_frames, + COALESCE_PENDING_LIMIT_UNIT); + CHECK_COALESCE_ALIGN(coal->rx_max_coalesced_frames_high, + COALESCE_PENDING_LIMIT_UNIT); + CHECK_COALESCE_ALIGN(coal->rx_max_coalesced_frames_low, + COALESCE_PENDING_LIMIT_UNIT); + + mutex_lock(&nic_dev->state_lock); + ori_intr_coal =3D &nic_dev->intr_coalesce[0]; + + CHECK_COALESCE_CHANGED(coal->rx_coalesce_usecs, COALESCE_TIMER_CFG_UNIT, + ori_intr_coal->coalesce_timer_cfg, obj_str); + CHECK_COALESCE_CHANGED(coal->rx_max_coalesced_frames, + COALESCE_PENDING_LIMIT_UNIT, + ori_intr_coal->pending_limit, obj_str); + CHECK_COALESCE_CHANGED(coal->rx_max_coalesced_frames_high, + COALESCE_PENDING_LIMIT_UNIT, + ori_intr_coal->rx_pending_limit_high, obj_str); + CHECK_COALESCE_CHANGED(coal->rx_max_coalesced_frames_low, + COALESCE_PENDING_LIMIT_UNIT, + ori_intr_coal->rx_pending_limit_low, obj_str); + mutex_unlock(&nic_dev->state_lock); + + old_adaptive =3D READ_ONCE(nic_dev->adaptive_rx_coal); + new_adaptive =3D !!coal->use_adaptive_rx_coalesce; + + if (old_adaptive) { + bool is_up; + + WRITE_ONCE(nic_dev->adaptive_rx_coal, false); + + synchronize_net(); + + mutex_lock(&nic_dev->state_lock); + is_up =3D test_bit(HINIC3_INTF_UP, &nic_dev->flags); + mutex_unlock(&nic_dev->state_lock); + + if (is_up) { + for (i =3D 0; i < nic_dev->q_params.num_qps; i++) { + rxq =3D nic_dev->q_params.irq_cfg[i].rxq; + if (!rxq) + continue; + + net_dim_work_cancel(&rxq->dim); + rxq->dim.state =3D DIM_START_MEASURE; + } + } + } + + intr_coal.coalesce_timer_cfg =3D + (u8)(coal->rx_coalesce_usecs / COALESCE_TIMER_CFG_UNIT); + + intr_coal.pending_limit =3D + (u8)(coal->rx_max_coalesced_frames / + COALESCE_PENDING_LIMIT_UNIT); + + intr_coal.rx_pending_limit_high =3D + (u8)(coal->rx_max_coalesced_frames_high / + COALESCE_PENDING_LIMIT_UNIT); + + intr_coal.rx_pending_limit_low =3D + (u8)(coal->rx_max_coalesced_frames_low / + COALESCE_PENDING_LIMIT_UNIT); + + /* coalesce timer or pending set to zero will disable coalesce */ + if (!new_adaptive && + (!intr_coal.coalesce_timer_cfg || !intr_coal.pending_limit)) + netdev_info(netdev, "Coalesce will be disabled\n"); + + err =3D hinic3_set_hw_coal_param(netdev, &intr_coal, extack); + if (err) { + if (old_adaptive) + WRITE_ONCE(nic_dev->adaptive_rx_coal, old_adaptive); + + return err; + } + + WRITE_ONCE(nic_dev->adaptive_rx_coal, new_adaptive); + + return 0; +} + static const struct ethtool_ops hinic3_ethtool_ops =3D { - .supported_coalesce_params =3D ETHTOOL_COALESCE_USECS | - ETHTOOL_COALESCE_PKT_RATE_RX_USECS, + .supported_coalesce_params =3D ETHTOOL_COALESCE_RX_USECS | + ETHTOOL_COALESCE_RX_MAX_FRAMES | + ETHTOOL_COALESCE_USE_ADAPTIVE_RX | + ETHTOOL_COALESCE_RX_MAX_FRAMES_LOW | + ETHTOOL_COALESCE_RX_MAX_FRAMES_HIGH, .get_link_ksettings =3D hinic3_get_link_ksettings, .get_drvinfo =3D hinic3_get_drvinfo, .get_msglevel =3D hinic3_get_msglevel, @@ -893,6 +1197,8 @@ static const struct ethtool_ops hinic3_ethtool_ops =3D= { .get_eth_ctrl_stats =3D hinic3_get_eth_ctrl_stats, .get_rmon_stats =3D hinic3_get_rmon_stats, .get_pause_stats =3D hinic3_get_pause_stats, + .get_coalesce =3D hinic3_get_coalesce, + .set_coalesce =3D hinic3_set_coalesce, }; =20 void hinic3_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/= ethernet/huawei/hinic3/hinic3_irq.c index e7d6c2033b45..b4e58d4c8ba8 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c @@ -20,7 +20,7 @@ static void hinic3_net_dim(struct hinic3_nic_dev *nic_dev, struct dim_sample sample =3D {}; =20 if (!test_bit(HINIC3_INTF_UP, &nic_dev->flags) || - !nic_dev->adaptive_rx_coal) + !READ_ONCE(nic_dev->adaptive_rx_coal)) return; =20 dim_update_sample(irq_cfg->total_events, rxq->rxq_stats.packets, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 0a888fe4c975..8c7492e15409 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -51,7 +51,7 @@ static void init_intr_coal_param(struct net_device *netde= v) info->rx_pending_limit_low =3D HINIC3_RX_PENDING_LIMIT_LOW; } =20 - nic_dev->adaptive_rx_coal =3D 1; + WRITE_ONCE(nic_dev->adaptive_rx_coal, 1); } =20 static int hinic3_init_intr_coalesce(struct net_device *netdev) @@ -178,7 +178,7 @@ static int hinic3_sw_init(struct net_device *netdev) u8 mac_addr[ETH_ALEN]; int err; =20 - mutex_init(&nic_dev->port_state_mutex); + mutex_init(&nic_dev->state_lock); =20 nic_dev->q_params.sq_depth =3D HINIC3_SQ_DEPTH; nic_dev->q_params.rq_depth =3D HINIC3_RQ_DEPTH; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index da73811641a9..ed4810fa9852 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -341,9 +341,9 @@ static int hinic3_maybe_set_port_state(struct net_devic= e *netdev, bool enable) struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); int err; =20 - mutex_lock(&nic_dev->port_state_mutex); + mutex_lock(&nic_dev->state_lock); err =3D hinic3_set_port_enable(nic_dev->hwdev, enable); - mutex_unlock(&nic_dev->port_state_mutex); + mutex_unlock(&nic_dev->state_lock); =20 return err; } diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 7ff699984cee..94a2bab52564 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -129,8 +129,8 @@ struct hinic3_nic_dev { struct workqueue_struct *workq; struct delayed_work periodic_work; struct work_struct rx_mode_work; - /* lock for enable/disable port */ - struct mutex port_state_mutex; + /* Protects interface state */ + struct mutex state_lock; =20 struct list_head uc_filter_list; struct list_head mc_filter_list; --=20 2.54.0 From nobody Mon Sep 28 21:52:15 2026 Received: from canpmsgout01.his.huawei.com (canpmsgout01.his.huawei.com [113.46.200.216]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7543557C9F; Mon, 17 Aug 2026 02:04:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.216 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786932288; cv=none; b=sGNqCIez6TJ3vF6oOqpQkEqFmNrxdUOhVZbcS6kbZvjxKBO78q4Dl1h1hoL5UoGZU9V2fGnBQH4x8YLIdQvC3EkVbh0pUzTaN3ITNyoXTDy24q16JM6HY4Ol40ghToTSrSQfr7fFfdUEly5UKCpbBrdYa7bfEcB55CxN3TqeK3Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786932288; c=relaxed/simple; bh=N2ZXMLX30Z4mxn+wsdekdIKFOTr4tZhs8nbu6i5rm34=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Uf/1KIzmf2HmCQFFk5wak5yIeDwZVJD7OQZ78+BEtYJHQFbLdvSbEBz4F9Rmx7TQS94rdrrGsgq9OXjcaeU4P7uUKnPKaVSs9xODPkNi7lVg3faTjmpUp7GN01iEaE310MvvjC5GPqdbLjtuMb3lbjKhN3BCg9+EJqNEUR3faiY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=1MqI3LEm; arc=none smtp.client-ip=113.46.200.216 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="1MqI3LEm" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=49tzuzhfAo2epbciTB/mccS2DapHrAmAXWk7pTYbPMA=; b=1MqI3LEmv/p6/WKcEFDbb/kQwqvYMDxrElTU84JTymvSYEW9rqLDZgb5VNAN0GO6p/KT3ZhgS IZT+u55VLI/lu4hTbc/7iMV8lrtienKowUCKfRjIi7anGjufCjMSI1g5q/PJkBqovwt7dUa8iVU 2HiYjYKQvWE187VAYCFclKc= Received: from mail.maildlp.com (unknown [172.19.163.104]) by canpmsgout01.his.huawei.com (SkyGuard) with ESMTPS id 4hNbVm433Kz1T4JN; Mon, 17 Aug 2026 09:54:40 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 9CBB54058C; Mon, 17 Aug 2026 10:04:37 +0800 (CST) Received: from DESKTOP-62GVMTR.china.huawei.com (10.174.189.124) by kwepemf100013.china.huawei.com (7.202.181.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Mon, 17 Aug 2026 10:04:36 +0800 From: Fan Gong To: Fan Gong , Wu Di , Teng Peisen , , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrew Lunn , Ioana Ciornei , Mohsin Bashir , Dimitri Daskalakis , Harshitha Ramamurthy , Larysa Zaremba CC: , , Chen Anwen , He Wei , luosifu , Xin Guo , Zhou Shuai , Wu Like , Shi Jing , Zheng Jiezhen , Maxime Chevallier Subject: [PATCH net-next v13 3/3] hinic3: Remove unneeded coalesce parameters Date: Mon, 17 Aug 2026 10:04:02 +0800 Message-ID: <7aa7c46128cf62e9a95d88944983b4ec0d9a5060.1786774752.git.tengpeisen@huawei.com> X-Mailer: git-send-email 2.50.1.windows.1 In-Reply-To: References: 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-ClientProxiedBy: kwepems200001.china.huawei.com (7.221.188.67) To kwepemf100013.china.huawei.com (7.202.181.12) Content-Type: text/plain; charset="utf-8" Remove unneeded coalesce parameters in irq handling. Co-developed-by: Wu Di Signed-off-by: Wu Di Co-developed-by: Teng Peisen Signed-off-by: Teng Peisen Signed-off-by: Fan Gong --- drivers/net/ethernet/huawei/hinic3/hinic3_irq.c | 6 +----- drivers/net/ethernet/huawei/hinic3/hinic3_rx.h | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/= ethernet/huawei/hinic3/hinic3_irq.c index b4e58d4c8ba8..f6645385c552 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c @@ -148,13 +148,9 @@ static int hinic3_set_interrupt_moder(struct net_devic= e *netdev, u16 q_id, nic_dev->intr_coalesce[q_id].resend_timer_cfg; =20 err =3D hinic3_set_interrupt_cfg(nic_dev->hwdev, info); - if (err) { + if (err) netdev_err(netdev, "Failed to modify moderation for Queue: %u\n", q_id); - } else { - nic_dev->rxqs[q_id].last_coalesc_timer_cfg =3D coalesc_timer_cfg; - nic_dev->rxqs[q_id].last_pending_limit =3D pending_limit; - } =20 return err; } diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h b/drivers/net/e= thernet/huawei/hinic3/hinic3_rx.h index c11d080408a7..2ab691ed11a9 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h @@ -111,9 +111,6 @@ struct hinic3_rxq { dma_addr_t cqe_start_paddr; =20 struct dim dim; - - u8 last_coalesc_timer_cfg; - u8 last_pending_limit; } ____cacheline_aligned; =20 struct hinic3_dyna_rxq_res { --=20 2.54.0