From: Vikas Gupta <vikas.gupta@broadcom.com>
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,
bhargava.marreddy@broadcom.com, rahul-rg.gupta@broadcom.com,
vsrama-krishna.nemani@broadcom.com,
rajashekar.hudumula@broadcom.com, dharmender.garg@broadcom.com,
ajit.khaparde@broadcom.com,
Vikas Gupta <vikas.gupta@broadcom.com>
Subject: [PATCH net-next 05/11] bnge: add RXFH ethtool support
Date: Fri, 14 Aug 2026 06:44:29 +0530 [thread overview]
Message-ID: <20260814011435.194631-6-vikas.gupta@broadcom.com> (raw)
In-Reply-To: <20260814011435.194631-1-vikas.gupta@broadcom.com>
Introduce ethtool RXFH operations including get/set_rxfh for
reading and programming the RSS hash key and indirection table.
Signed-off-by: Vikas Gupta <vikas.gupta@broadcom.com>
Reviewed-by: Bhargava Chenna Marreddy <bhargava.marreddy@broadcom.com>
Reviewed-by: Dharmender Garg <dharmender.garg@broadcom.com>
---
drivers/net/ethernet/broadcom/bnge/bnge.h | 1 +
.../net/ethernet/broadcom/bnge/bnge_ethtool.c | 284 ++++++++++++++++++
.../ethernet/broadcom/bnge/bnge_hwrm_lib.c | 2 +
.../net/ethernet/broadcom/bnge/bnge_netdev.c | 4 +-
.../net/ethernet/broadcom/bnge/bnge_netdev.h | 2 +
.../net/ethernet/broadcom/bnge/bnge_vnic.h | 1 +
6 files changed, 292 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethernet/broadcom/bnge/bnge.h
index d43c67232a86..d058737fe2b0 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge.h
@@ -88,6 +88,7 @@ enum {
BNGE_RSS_CAP_AH_V6_RSS_CAP = BIT(5),
BNGE_RSS_CAP_ESP_V4_RSS_CAP = BIT(6),
BNGE_RSS_CAP_ESP_V6_RSS_CAP = BIT(7),
+ BNGE_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP = BIT(8),
};
#define BNGE_MAX_QUEUE 8
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c b/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c
index 2467e44de291..c6f564045647 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_ethtool.c
@@ -10,6 +10,9 @@
#include <linux/ethtool_netlink.h>
#include "bnge.h"
+#include "bnge_netdev.h"
+#include "bnge_vnic.h"
+#include "bnge_resc.h"
#include "bnge_ethtool.h"
#include "bnge_hwrm_lib.h"
@@ -740,6 +743,275 @@ static int bnge_set_pauseparam(struct net_device *dev,
return rc;
}
+static u64 bnge_get_ethtool_ipv4_rss(struct bnge_dev *bd)
+{
+ if (bd->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4)
+ return RXH_IP_SRC | RXH_IP_DST;
+ return 0;
+}
+
+static u64 bnge_get_ethtool_ipv6_rss(struct bnge_dev *bd)
+{
+ if (bd->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
+ return RXH_IP_SRC | RXH_IP_DST;
+ if (bd->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL)
+ return RXH_IP_SRC | RXH_IP_DST | RXH_IP6_FL;
+ return 0;
+}
+
+static int bnge_get_rxfh_fields(struct net_device *dev,
+ struct ethtool_rxfh_fields *cmd)
+{
+ struct bnge_net *bn = netdev_priv(dev);
+ struct bnge_dev *bd = bn->bd;
+
+ cmd->data = 0;
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ if (bd->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4)
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ cmd->data |= bnge_get_ethtool_ipv4_rss(bd);
+ break;
+ case UDP_V4_FLOW:
+ if (bd->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ fallthrough;
+ case AH_ESP_V4_FLOW:
+ if (bd->rss_hash_cfg &
+ (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
+ VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4))
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ fallthrough;
+ case SCTP_V4_FLOW:
+ case AH_V4_FLOW:
+ case ESP_V4_FLOW:
+ case IPV4_FLOW:
+ cmd->data |= bnge_get_ethtool_ipv4_rss(bd);
+ break;
+ case TCP_V6_FLOW:
+ if (bd->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6)
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ cmd->data |= bnge_get_ethtool_ipv6_rss(bd);
+ break;
+ case UDP_V6_FLOW:
+ if (bd->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ fallthrough;
+ case AH_ESP_V6_FLOW:
+ if (bd->rss_hash_cfg &
+ (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
+ VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6))
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ fallthrough;
+ case SCTP_V6_FLOW:
+ case AH_V6_FLOW:
+ case ESP_V6_FLOW:
+ case IPV6_FLOW:
+ cmd->data |= bnge_get_ethtool_ipv6_rss(bd);
+ break;
+ }
+ return 0;
+}
+
+#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
+#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST)
+
+static int bnge_set_rxfh_fields(struct net_device *dev,
+ const struct ethtool_rxfh_fields *cmd,
+ struct netlink_ext_ack *extack)
+{
+ struct bnge_net *bn = netdev_priv(dev);
+ struct bnge_dev *bd = bn->bd;
+ int tuple, rc = 0;
+ u32 rss_hash_cfg;
+
+ rss_hash_cfg = bd->rss_hash_cfg;
+
+ if (cmd->data == RXH_4TUPLE)
+ tuple = 4;
+ else if (cmd->data == RXH_2TUPLE ||
+ cmd->data == (RXH_2TUPLE | RXH_IP6_FL))
+ tuple = 2;
+ else if (!cmd->data)
+ tuple = 0;
+ else
+ return -EINVAL;
+
+ if (cmd->data & RXH_IP6_FL &&
+ !(bd->rss_cap & BNGE_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP))
+ return -EINVAL;
+
+ if (cmd->flow_type == TCP_V4_FLOW) {
+ rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
+ if (tuple == 4)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
+ } else if (cmd->flow_type == UDP_V4_FLOW) {
+ rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
+ if (tuple == 4)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
+ } else if (cmd->flow_type == TCP_V6_FLOW) {
+ rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
+ if (tuple == 4)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
+ } else if (cmd->flow_type == UDP_V6_FLOW) {
+ rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
+ if (tuple == 4)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
+ } else if (cmd->flow_type == AH_ESP_V4_FLOW) {
+ if (tuple == 4 &&
+ (!(bd->rss_cap & BNGE_RSS_CAP_AH_V4_RSS_CAP) ||
+ !(bd->rss_cap & BNGE_RSS_CAP_ESP_V4_RSS_CAP)))
+ return -EINVAL;
+ rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
+ VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4);
+ if (tuple == 4)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
+ VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4;
+ } else if (cmd->flow_type == AH_ESP_V6_FLOW) {
+ if (tuple == 4 &&
+ (!(bd->rss_cap & BNGE_RSS_CAP_AH_V6_RSS_CAP) ||
+ !(bd->rss_cap & BNGE_RSS_CAP_ESP_V6_RSS_CAP)))
+ return -EINVAL;
+ rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
+ VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6);
+ if (tuple == 4)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
+ VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6;
+ } else if (tuple == 4) {
+ return -EINVAL;
+ }
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ case AH_ESP_V4_FLOW:
+ case AH_V4_FLOW:
+ case ESP_V4_FLOW:
+ case IPV4_FLOW:
+ if (tuple == 2)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
+ else if (!tuple)
+ rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
+ break;
+
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ case AH_ESP_V6_FLOW:
+ case AH_V6_FLOW:
+ case ESP_V6_FLOW:
+ case IPV6_FLOW:
+ rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
+ VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL);
+ if (!tuple)
+ break;
+ if (cmd->data & RXH_IP6_FL)
+ rss_hash_cfg |=
+ VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL;
+ else if (tuple == 2)
+ rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
+ break;
+ }
+
+ if (bd->rss_hash_cfg == rss_hash_cfg)
+ return 0;
+
+ bd->rss_hash_cfg = rss_hash_cfg;
+ if (netif_running(bn->netdev)) {
+ bnge_close_core(bn);
+ rc = bnge_open_core(bn);
+ }
+ return rc;
+}
+
+static u32 bnge_get_rxfh_indir_size_eth(struct net_device *dev)
+{
+ struct bnge_net *bn = netdev_priv(dev);
+ struct bnge_dev *bd = bn->bd;
+
+ return bnge_get_rxfh_indir_size(bd);
+}
+
+static u32 bnge_get_rxfh_key_size(struct net_device *dev)
+{
+ return HW_HASH_KEY_SIZE;
+}
+
+static int bnge_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
+{
+ struct bnge_net *bn = netdev_priv(dev);
+ struct bnge_rss_ctx *rss_ctx = NULL;
+ struct bnge_dev *bd = bn->bd;
+ struct bnge_vnic_info *vnic;
+ u32 i, tbl_size;
+ u32 *indir_tbl;
+
+ indir_tbl = bd->rss_indir_tbl;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+
+ if (!bn->vnic_info)
+ return 0;
+
+ vnic = &bn->vnic_info[BNGE_VNIC_DEFAULT];
+ if (rxfh->rss_context) {
+ struct ethtool_rxfh_context *ctx;
+
+ ctx = xa_load(&bn->netdev->ethtool->rss_ctx,
+ rxfh->rss_context);
+ if (!ctx)
+ return -EINVAL;
+ indir_tbl = ethtool_rxfh_context_indir(ctx);
+ rss_ctx = ethtool_rxfh_context_priv(ctx);
+ vnic = &rss_ctx->vnic;
+ }
+
+ if (rxfh->indir && indir_tbl) {
+ tbl_size = bnge_get_rxfh_indir_size(bd);
+ for (i = 0; i < tbl_size; i++)
+ rxfh->indir[i] = indir_tbl[i];
+ }
+
+ if (rxfh->key && vnic->rss_hash_key)
+ memcpy(rxfh->key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);
+
+ return 0;
+}
+
+static int bnge_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
+{
+ struct bnge_net *bn = netdev_priv(dev);
+ int rc = 0;
+
+ if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP)
+ return -EOPNOTSUPP;
+
+ bnge_modify_rss(bn, NULL, NULL, rxfh);
+
+ if (netif_running(bn->netdev)) {
+ bnge_close_core(bn);
+ rc = bnge_open_core(bn);
+ }
+ return rc;
+}
+
+static u32 bnge_get_rx_ring_count(struct net_device *dev)
+{
+ struct bnge_net *bn = netdev_priv(dev);
+ struct bnge_dev *bd = bn->bd;
+
+ return bd->rx_nr_rings;
+}
+
static const struct ethtool_ops bnge_ethtool_ops = {
.cap_link_lanes_supported = 1,
.get_link_ksettings = bnge_get_link_ksettings,
@@ -757,6 +1029,18 @@ static const struct ethtool_ops bnge_ethtool_ops = {
.get_eth_ctrl_stats = bnge_get_eth_ctrl_stats,
.get_pause_stats = bnge_get_pause_stats,
.get_rmon_stats = bnge_get_rmon_stats,
+ /* RXFH */
+ .rxfh_per_ctx_key = 1,
+ .rxfh_max_num_contexts = BNGE_MAX_ETH_RSS_CTX + 1,
+ .rxfh_indir_space = BNGE_MAX_RSS_TABLE_ENTRIES,
+ .rxfh_priv_size = sizeof(struct bnge_rss_ctx),
+ .get_rx_ring_count = bnge_get_rx_ring_count,
+ .get_rxfh_indir_size = bnge_get_rxfh_indir_size_eth,
+ .get_rxfh_key_size = bnge_get_rxfh_key_size,
+ .get_rxfh = bnge_get_rxfh,
+ .set_rxfh = bnge_set_rxfh,
+ .get_rxfh_fields = bnge_get_rxfh_fields,
+ .set_rxfh_fields = bnge_set_rxfh_fields,
};
void bnge_set_ethtool_ops(struct net_device *dev)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c
index dd48c60aeef4..68a93d9f8d64 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c
@@ -676,6 +676,8 @@ int bnge_hwrm_vnic_qcaps(struct bnge_dev *bd)
bd->rss_cap |= BNGE_RSS_CAP_ESP_V4_RSS_CAP;
if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP)
bd->rss_cap |= BNGE_RSS_CAP_ESP_V6_RSS_CAP;
+ if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPV6_FLOW_LABEL_CAP)
+ bd->rss_cap |= BNGE_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP;
}
bnge_hwrm_req_drop(bd, req);
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
index 0f5e46937828..1a55c2fe4532 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
@@ -2723,7 +2723,7 @@ static int bnge_hwrm_if_change(struct bnge_dev *bd, bool up)
return bnge_hwrm_req_send(bd, req);
}
-static int bnge_open_core(struct bnge_net *bn)
+int bnge_open_core(struct bnge_net *bn)
{
struct bnge_dev *bd = bn->bd;
int rc;
@@ -2993,7 +2993,7 @@ static void bnge_save_ring_stats(struct bnge_net *bn)
}
}
-static void bnge_close_core(struct bnge_net *bn)
+void bnge_close_core(struct bnge_net *bn)
{
struct bnge_dev *bd = bn->bd;
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
index 3c0fea0a7608..d68eaa78d4e0 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
@@ -579,4 +579,6 @@ int bnge_alloc_rx_netmem(struct bnge_net *bn, struct bnge_rx_ring_info *rxr,
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);
+int bnge_open_core(struct bnge_net *bn);
+void bnge_close_core(struct bnge_net *bn);
#endif /* _BNGE_NETDEV_H_ */
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
index af066d8ff156..b2a1d8332a5f 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
@@ -15,6 +15,7 @@ struct bnge_l2_filter;
#define BNGE_MAX_RSS_TABLE_ENTRIES \
(BNGE_RSS_TABLE_ENTRIES * BNGE_RSS_TABLE_MAX_TBL)
+#define BNGE_MAX_ETH_RSS_CTX 32
#define BNGE_MAX_CTX_PER_VNIC 8
#define BNGE_MAX_MC_ADDRS 16
--
2.47.1
next prev parent reply other threads:[~2026-08-14 1:15 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 1:14 [PATCH net-next 00/11] add features to bnge Vikas Gupta
2026-08-14 1:14 ` [PATCH net-next 01/11] bnge: update HSI Vikas Gupta
2026-08-14 1:14 ` [PATCH net-next 02/11] bnge: restructure VNIC and filter code Vikas Gupta
2026-08-14 1:14 ` [PATCH net-next 03/11] bnge: add NTUPLE/ARFS VNIC Vikas Gupta
2026-08-14 1:14 ` [PATCH net-next 04/11] bnge: add helper functions for multi RSS contexts Vikas Gupta
2026-08-14 1:14 ` Vikas Gupta [this message]
2026-08-14 1:14 ` [PATCH net-next 06/11] bnge: add ethtool support to manage " Vikas Gupta
2026-08-14 1:14 ` [PATCH net-next 07/11] bnge: remove refcount from L2 filter Vikas Gupta
2026-08-14 1:14 ` [PATCH net-next 08/11] bnge: add NTUPLE filter infrastructure Vikas Gupta
2026-08-17 23:35 ` Jakub Kicinski
2026-08-14 1:14 ` [PATCH net-next 09/11] bnge: add NTUPLE filter support in ethtool Vikas Gupta
2026-08-14 1:14 ` [PATCH net-next 10/11] bnge: add aRFS flow steering ndo support Vikas Gupta
2026-08-17 23:36 ` Jakub Kicinski
2026-08-14 1:14 ` [PATCH net-next 11/11] bnge: add cpu_rmap support for IRQ affinity Vikas Gupta
2026-08-17 23:38 ` [PATCH net-next 00/11] add features to bnge Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260814011435.194631-6-vikas.gupta@broadcom.com \
--to=vikas.gupta@broadcom.com \
--cc=ajit.khaparde@broadcom.com \
--cc=andrew+netdev@lunn.ch \
--cc=bhargava.marreddy@broadcom.com \
--cc=davem@davemloft.net \
--cc=dharmender.garg@broadcom.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rahul-rg.gupta@broadcom.com \
--cc=rajashekar.hudumula@broadcom.com \
--cc=vsrama-krishna.nemani@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.