All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Min Hu (Connor)" <humin29@huawei.com>
To: <dev@dpdk.org>
Cc: <ferruh.yigit@intel.com>
Subject: [dpdk-dev] [PATCH 3/9] net/hns3: support for outer UDP cksum
Date: Wed, 10 Mar 2021 14:24:47 +0800	[thread overview]
Message-ID: <1615357493-42394-4-git-send-email-humin29@huawei.com> (raw)
In-Reply-To: <1615357493-42394-1-git-send-email-humin29@huawei.com>

From: Chengchang Tang <tangchengchang@huawei.com>

Kunpeng930 support outer UDP cksum, this patch add support for it.

Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
---
 doc/guides/rel_notes/release_21_05.rst |  1 +
 drivers/net/hns3/hns3_cmd.c            |  3 ++
 drivers/net/hns3/hns3_ethdev.c         |  3 ++
 drivers/net/hns3/hns3_ethdev.h         |  4 ++
 drivers/net/hns3/hns3_ethdev_vf.c      |  3 ++
 drivers/net/hns3/hns3_rxtx.c           | 85 +++++++++++++++++++++++++++-------
 drivers/net/hns3/hns3_rxtx.h           |  4 +-
 drivers/net/hns3/hns3_rxtx_vec_sve.c   |  5 +-
 8 files changed, 89 insertions(+), 19 deletions(-)

diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
index 10f6dd0..ba321a5 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -62,6 +62,7 @@ New Features
   * Added support for copper port in Kunpeng930.
   * Added support for runtime config to select IO burst function.
   * Added support for Tx push qick doorbell to improve performance.
+  * Added support for outer UDP checksum in Kunpeng930.
 
 * **Updated NXP DPAA2 driver.**
 
diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
index 8b9f075..03f8048 100644
--- a/drivers/net/hns3/hns3_cmd.c
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -433,6 +433,9 @@ hns3_parse_capability(struct hns3_hw *hw,
 	if (hns3_get_bit(caps, HNS3_CAPS_RXD_ADV_LAYOUT_B))
 		hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
 			     1);
+	if (hns3_get_bit(caps, HNS3_CAPS_UDP_TUNNEL_CSUM_B))
+		hns3_set_bit(hw->capability,
+				HNS3_DEV_SUPPORT_OUTER_UDP_CKSUM_B, 1);
 }
 
 static uint32_t
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index f725f5c..c15c891 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -2620,6 +2620,9 @@ hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
 				 DEV_TX_OFFLOAD_MBUF_FAST_FREE |
 				 hns3_txvlan_cap_get(hw));
 
+	if (hns3_dev_outer_udp_cksum_supported(hw))
+		info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_UDP_CKSUM;
+
 	if (hns3_dev_indep_txrx_supported(hw))
 		info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
 				 RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 173848a..28365e6 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -795,6 +795,7 @@ enum {
 #define HNS3_DEV_SUPPORT_INDEP_TXRX_B		0x6
 #define HNS3_DEV_SUPPORT_STASH_B		0x7
 #define HNS3_DEV_SUPPORT_RXD_ADV_LAYOUT_B	0x9
+#define HNS3_DEV_SUPPORT_OUTER_UDP_CKSUM_B	0xA
 
 #define hns3_dev_dcb_supported(hw) \
 	hns3_get_bit((hw)->capability, HNS3_DEV_SUPPORT_DCB_B)
@@ -828,6 +829,9 @@ enum {
 #define hns3_dev_rxd_adv_layout_supported(hw) \
 	hns3_get_bit((hw)->capability, HNS3_DEV_SUPPORT_RXD_ADV_LAYOUT_B)
 
+#define hns3_dev_outer_udp_cksum_supported(hw) \
+	hns3_get_bit((hw)->capability, HNS3_DEV_SUPPORT_OUTER_UDP_CKSUM_B)
+
 #define HNS3_DEV_PRIVATE_TO_HW(adapter) \
 	(&((struct hns3_adapter *)adapter)->hw)
 #define HNS3_DEV_PRIVATE_TO_PF(adapter) \
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 6a90cd5..b7c27f6 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -988,6 +988,9 @@ hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
 				 DEV_TX_OFFLOAD_MBUF_FAST_FREE |
 				 hns3_txvlan_cap_get(hw));
 
+	if (hns3_dev_outer_udp_cksum_supported(hw))
+		info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_UDP_CKSUM;
+
 	if (hns3_dev_indep_txrx_supported(hw))
 		info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
 				 RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index ffd8331..26127cd 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -3048,7 +3048,7 @@ hns3_fill_first_desc(struct hns3_tx_queue *txq, struct hns3_desc *desc,
 	hdr_len += (ol_flags & PKT_TX_TUNNEL_MASK) ?
 			   rxm->outer_l2_len + rxm->outer_l3_len : 0;
 	paylen = rxm->pkt_len - hdr_len;
-	desc->tx.paylen = rte_cpu_to_le_32(paylen);
+	desc->tx.paylen_fd_dop_ol4cs |= rte_cpu_to_le_32(paylen);
 	hns3_set_tso(desc, paylen, rxm);
 
 	/*
@@ -3285,8 +3285,10 @@ hns3_parse_tunneling_params(struct hns3_tx_queue *txq, struct rte_mbuf *m,
 {
 	struct hns3_desc *tx_ring = txq->tx_ring;
 	struct hns3_desc *desc = &tx_ring[tx_desc_id];
+	uint64_t ol_flags = m->ol_flags;
 	uint32_t tmp_outer = 0;
 	uint32_t tmp_inner = 0;
+	uint32_t tmp_ol4cs;
 	int ret;
 
 	/*
@@ -3296,7 +3298,7 @@ hns3_parse_tunneling_params(struct hns3_tx_queue *txq, struct rte_mbuf *m,
 	 * calculations, the length of the L2 header include the outer and
 	 * inner, will be filled during the parsing of tunnel packects.
 	 */
-	if (!(m->ol_flags & PKT_TX_TUNNEL_MASK)) {
+	if (!(ol_flags & PKT_TX_TUNNEL_MASK)) {
 		/*
 		 * For non tunnel type the tunnel type id is 0, so no need to
 		 * assign a value to it. Only the inner(normal) L2 header length
@@ -3311,7 +3313,8 @@ hns3_parse_tunneling_params(struct hns3_tx_queue *txq, struct rte_mbuf *m,
 		 * inner l2_len. It would lead a cksum error. So driver has to
 		 * calculate the header length.
 		 */
-		if (unlikely(!(m->ol_flags & PKT_TX_OUTER_IP_CKSUM) &&
+		if (unlikely(!(ol_flags &
+			(PKT_TX_OUTER_IP_CKSUM | PKT_TX_OUTER_UDP_CKSUM)) &&
 					m->outer_l2_len == 0)) {
 			struct rte_net_hdr_lens hdr_len;
 			(void)rte_net_get_ptype(m, &hdr_len,
@@ -3328,6 +3331,9 @@ hns3_parse_tunneling_params(struct hns3_tx_queue *txq, struct rte_mbuf *m,
 
 	desc->tx.ol_type_vlan_len_msec = rte_cpu_to_le_32(tmp_outer);
 	desc->tx.type_cs_vlan_tso_len = rte_cpu_to_le_32(tmp_inner);
+	tmp_ol4cs = ol_flags & PKT_TX_OUTER_UDP_CKSUM ?
+			BIT(HNS3_TXD_OL4CS_B) : 0;
+	desc->tx.paylen_fd_dop_ol4cs = rte_cpu_to_le_32(tmp_ol4cs);
 
 	return 0;
 }
@@ -3457,31 +3463,78 @@ hns3_pkt_need_linearized(struct rte_mbuf *tx_pkts, uint32_t bd_num,
 	return false;
 }
 
+static bool
+hns3_outer_ipv4_cksum_prepared(struct rte_mbuf *m, uint64_t ol_flags,
+				uint32_t *l4_proto)
+{
+	struct rte_ipv4_hdr *ipv4_hdr;
+	ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *,
+					   m->outer_l2_len);
+	if (ol_flags & PKT_TX_OUTER_IP_CKSUM)
+		ipv4_hdr->hdr_checksum = 0;
+	if (ol_flags & PKT_TX_OUTER_UDP_CKSUM) {
+		struct rte_udp_hdr *udp_hdr;
+		/*
+		 * If OUTER_UDP_CKSUM is support, HW can caclulate the pseudo
+		 * header for TSO packets
+		 */
+		if (ol_flags & PKT_TX_TCP_SEG)
+			return true;
+		udp_hdr = rte_pktmbuf_mtod_offset(m, struct rte_udp_hdr *,
+				m->outer_l2_len + m->outer_l3_len);
+		udp_hdr->dgram_cksum = rte_ipv4_phdr_cksum(ipv4_hdr, ol_flags);
+
+		return true;
+	}
+	*l4_proto = ipv4_hdr->next_proto_id;
+	return false;
+}
+
+static bool
+hns3_outer_ipv6_cksum_prepared(struct rte_mbuf *m, uint64_t ol_flags,
+				uint32_t *l4_proto)
+{
+	struct rte_ipv6_hdr *ipv6_hdr;
+	ipv6_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv6_hdr *,
+					   m->outer_l2_len);
+	if (ol_flags & PKT_TX_OUTER_UDP_CKSUM) {
+		struct rte_udp_hdr *udp_hdr;
+		/*
+		 * If OUTER_UDP_CKSUM is support, HW can caclulate the pseudo
+		 * header for TSO packets
+		 */
+		if (ol_flags & PKT_TX_TCP_SEG)
+			return true;
+		udp_hdr = rte_pktmbuf_mtod_offset(m, struct rte_udp_hdr *,
+				m->outer_l2_len + m->outer_l3_len);
+		udp_hdr->dgram_cksum = rte_ipv6_phdr_cksum(ipv6_hdr, ol_flags);
+
+		return true;
+	}
+	*l4_proto = ipv6_hdr->proto;
+	return false;
+}
+
 static void
 hns3_outer_header_cksum_prepare(struct rte_mbuf *m)
 {
 	uint64_t ol_flags = m->ol_flags;
 	uint32_t paylen, hdr_len, l4_proto;
+	struct rte_udp_hdr *udp_hdr;
 
 	if (!(ol_flags & (PKT_TX_OUTER_IPV4 | PKT_TX_OUTER_IPV6)))
 		return;
 
 	if (ol_flags & PKT_TX_OUTER_IPV4) {
-		struct rte_ipv4_hdr *ipv4_hdr;
-		ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *,
-						   m->outer_l2_len);
-		l4_proto = ipv4_hdr->next_proto_id;
-		if (ol_flags & PKT_TX_OUTER_IP_CKSUM)
-			ipv4_hdr->hdr_checksum = 0;
+		if (hns3_outer_ipv4_cksum_prepared(m, ol_flags, &l4_proto))
+			return;
 	} else {
-		struct rte_ipv6_hdr *ipv6_hdr;
-		ipv6_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv6_hdr *,
-						   m->outer_l2_len);
-		l4_proto = ipv6_hdr->proto;
+		if (hns3_outer_ipv6_cksum_prepared(m, ol_flags, &l4_proto))
+			return;
 	}
+
 	/* driver should ensure the outer udp cksum is 0 for TUNNEL TSO */
 	if (l4_proto == IPPROTO_UDP && (ol_flags & PKT_TX_TCP_SEG)) {
-		struct rte_udp_hdr *udp_hdr;
 		hdr_len = m->l2_len + m->l3_len + m->l4_len;
 		hdr_len += m->outer_l2_len + m->outer_l3_len;
 		paylen = m->pkt_len - hdr_len;
@@ -3767,7 +3820,7 @@ hns3_tx_setup_4bd(struct hns3_desc *txdp, struct rte_mbuf **pkts)
 		dma_addr = rte_mbuf_data_iova(*pkts);
 		txdp->addr = rte_cpu_to_le_64(dma_addr);
 		txdp->tx.send_size = rte_cpu_to_le_16((*pkts)->data_len);
-		txdp->tx.paylen = 0;
+		txdp->tx.paylen_fd_dop_ol4cs = 0;
 		txdp->tx.type_cs_vlan_tso_len = 0;
 		txdp->tx.ol_type_vlan_len_msec = 0;
 		txdp->tx.tp_fe_sc_vld_ra_ri = rte_cpu_to_le_16(bd_flag);
@@ -3783,7 +3836,7 @@ hns3_tx_setup_1bd(struct hns3_desc *txdp, struct rte_mbuf **pkts)
 	dma_addr = rte_mbuf_data_iova(*pkts);
 	txdp->addr = rte_cpu_to_le_64(dma_addr);
 	txdp->tx.send_size = rte_cpu_to_le_16((*pkts)->data_len);
-	txdp->tx.paylen = 0;
+	txdp->tx.paylen_fd_dop_ol4cs = 0;
 	txdp->tx.type_cs_vlan_tso_len = 0;
 	txdp->tx.ol_type_vlan_len_msec = 0;
 	txdp->tx.tp_fe_sc_vld_ra_ri = rte_cpu_to_le_16(bd_flag);
diff --git a/drivers/net/hns3/hns3_rxtx.h b/drivers/net/hns3/hns3_rxtx.h
index 6ce89cc..db34ff9 100644
--- a/drivers/net/hns3/hns3_rxtx.h
+++ b/drivers/net/hns3/hns3_rxtx.h
@@ -149,6 +149,7 @@
 #define HNS3_TXD_MSS_S				0
 #define HNS3_TXD_MSS_M				(0x3fff << HNS3_TXD_MSS_S)
 
+#define HNS3_TXD_OL4CS_B			22
 #define HNS3_L2_LEN_UNIT			1UL
 #define HNS3_L3_LEN_UNIT			2UL
 #define HNS3_L4_LEN_UNIT			2UL
@@ -234,7 +235,7 @@ struct hns3_desc {
 				};
 			};
 
-			uint32_t paylen;
+			uint32_t paylen_fd_dop_ol4cs;
 			uint16_t tp_fe_sc_vld_ra_ri;
 			uint16_t mss;
 		} tx;
@@ -505,6 +506,7 @@ struct hns3_queue_info {
 };
 
 #define HNS3_TX_CKSUM_OFFLOAD_MASK ( \
+	PKT_TX_OUTER_UDP_CKSUM | \
 	PKT_TX_OUTER_IP_CKSUM | \
 	PKT_TX_IP_CKSUM | \
 	PKT_TX_TCP_SEG | \
diff --git a/drivers/net/hns3/hns3_rxtx_vec_sve.c b/drivers/net/hns3/hns3_rxtx_vec_sve.c
index 6a20378..f8655fa 100644
--- a/drivers/net/hns3/hns3_rxtx_vec_sve.c
+++ b/drivers/net/hns3/hns3_rxtx_vec_sve.c
@@ -408,8 +408,9 @@ hns3_tx_fill_hw_ring_sve(struct hns3_tx_queue *txq,
 				(uint64_t *)&txdp->tx.outer_vlan_tag,
 				offsets, svdup_n_u64(0));
 		/* save offset 24~31byte of every BD */
-		svst1_scatter_u64offset_u64(pg, (uint64_t *)&txdp->tx.paylen,
-					    offsets, svdup_n_u64(valid_bit));
+		svst1_scatter_u64offset_u64(pg,
+				(uint64_t *)&txdp->tx.paylen_fd_dop_ol4cs,
+				offsets, svdup_n_u64(valid_bit));
 
 		/* Increment bytes counter */
 		uint32_t idx;
-- 
2.7.4


  parent reply	other threads:[~2021-03-10  6:24 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-10  6:24 [dpdk-dev] [PATCH 0/9] features and bugfixes for hns3 Min Hu (Connor)
2021-03-10  6:24 ` [dpdk-dev] [PATCH 1/9] net/hns3: support runtime config to select IO burst func Min Hu (Connor)
2021-03-10  6:24 ` [dpdk-dev] [PATCH 2/9] net/hns3: support Tx push quick doorbell to improve perf Min Hu (Connor)
2021-03-10  6:24 ` Min Hu (Connor) [this message]
2021-03-10  6:24 ` [dpdk-dev] [PATCH 4/9] net/hns3: adjust the format of RAS related structures Min Hu (Connor)
2021-03-10  6:24 ` [dpdk-dev] [PATCH 5/9] net/hns3: delete redundant xstats RAS statistics Min Hu (Connor)
2021-03-10  6:24 ` [dpdk-dev] [PATCH 6/9] net/hns3: support imissed stats for PF/VF Min Hu (Connor)
2021-03-10  6:24 ` [dpdk-dev] [PATCH 7/9] net/hns3: support oerrors stats in PF Min Hu (Connor)
2021-03-10  6:24 ` [dpdk-dev] [PATCH 8/9] net/hns3: support query Tx descriptor status Min Hu (Connor)
2021-03-10  6:24 ` [dpdk-dev] [PATCH 9/9] net/hns3: support query Rx " Min Hu (Connor)
2021-03-17  9:50 ` [dpdk-dev] [PATCH v4 0/8] features and bugfixes for hns3 Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 1/8] net/hns3: support runtime config to select IO burst func Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 2/8] net/hns3: support for outer UDP cksum Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 3/8] net/hns3: adjust the format of RAS related structures Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 4/8] net/hns3: delete redundant xstats RAS statistics Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 5/8] net/hns3: support imissed stats for PF/VF Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 6/8] net/hns3: support oerrors stats in PF Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 7/8] net/hns3: support query Tx descriptor status Min Hu (Connor)
2021-03-17  9:50   ` [dpdk-dev] [PATCH v4 8/8] net/hns3: support query Rx " Min Hu (Connor)
2021-03-19  1:07 ` [dpdk-dev] [PATCH v5 0/8] features and bugfixes for hns3 Min Hu (Connor)
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 1/8] net/hns3: support runtime config to select IO burst func Min Hu (Connor)
2021-03-22 13:58     ` Ferruh Yigit
2021-03-22 14:03       ` Ferruh Yigit
2021-03-23  3:31       ` fengchengwen
2021-03-23 10:31         ` Ferruh Yigit
2021-03-23 11:22           ` Min Hu (Connor)
2021-03-23  3:37       ` fengchengwen
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 2/8] net/hns3: support for outer UDP cksum Min Hu (Connor)
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 3/8] net/hns3: adjust the format of RAS related structures Min Hu (Connor)
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 4/8] net/hns3: delete redundant xstats RAS statistics Min Hu (Connor)
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 5/8] net/hns3: support imissed stats for PF/VF Min Hu (Connor)
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 6/8] net/hns3: support oerrors stats in PF Min Hu (Connor)
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 7/8] net/hns3: support query Tx descriptor status Min Hu (Connor)
2021-03-19  1:07   ` [dpdk-dev] [PATCH v5 8/8] net/hns3: support query Rx " Min Hu (Connor)
2021-03-23 11:20 ` [dpdk-dev] [PATCH v6 0/8] features and bugfixes for hns3 Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 1/8] net/hns3: support runtime config to select IO burst func Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 2/8] net/hns3: support for outer UDP cksum Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 3/8] net/hns3: adjust the format of RAS related structures Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 4/8] net/hns3: delete redundant xstats RAS statistics Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 5/8] net/hns3: support imissed stats for PF/VF Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 6/8] net/hns3: support oerrors stats in PF Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 7/8] net/hns3: support query Tx descriptor status Min Hu (Connor)
2021-03-23 11:21   ` [dpdk-dev] [PATCH v6 8/8] net/hns3: support query Rx " Min Hu (Connor)
2021-03-23 12:49   ` [dpdk-dev] [PATCH v6 0/8] features and bugfixes for hns3 Ferruh Yigit

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=1615357493-42394-4-git-send-email-humin29@huawei.com \
    --to=humin29@huawei.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@intel.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.