DPDK patches and discussions
 help / color / mirror / Atom feed
From: Soumyadeep Hore <soumyadeep.hore@intel.com>
To: bruce.richardson@intel.com, ian.stokes@intel.com,
	aman.deep.singh@intel.com
Cc: dev@dpdk.org, shaiq.wani@intel.com,
	Norbert Zulinski <norbertx.zulinski@intel.com>,
	stable@dpdk.org
Subject: [PATCH v3 02/12] net/ice: updates for ptp init in E825C
Date: Fri, 23 Aug 2024 09:56:40 +0000	[thread overview]
Message-ID: <20240823095650.349785-3-soumyadeep.hore@intel.com> (raw)
In-Reply-To: <20240823095650.349785-1-soumyadeep.hore@intel.com>

From: Norbert Zulinski <norbertx.zulinski@intel.com>

The implementation was done incorrectly assuming
the TS PLL parameters would be similar to E822/E823
devices. Fix it by using proper values.

Define access to SB (sideband) for second PHY and
CGU devices in case of E825C devices.

In E825C soft straps of CGU cannot be read from HW,
and therefore it must be hard coded to default values.

Fixes: 620ecf247c22 ("net/ice/base: support E825-C Tx clock changing")
Cc: stable@dpdk.org

Signed-off-by: Norbert Zulinski <norbertx.zulinski@intel.com>
Signed-off-by: Soumyadeep Hore <soumyadeep.hore@intel.com>
---
 drivers/net/ice/base/ice_cgu_regs.h   | 19 +++++++
 drivers/net/ice/base/ice_common.c     |  4 ++
 drivers/net/ice/base/ice_ptp_consts.h | 75 +++++++++++++++++++++++++++
 drivers/net/ice/base/ice_ptp_hw.c     | 75 ++++++++++++++++++---------
 drivers/net/ice/base/ice_ptp_hw.h     | 21 ++++++++
 5 files changed, 169 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ice/base/ice_cgu_regs.h b/drivers/net/ice/base/ice_cgu_regs.h
index f24f4746dd..4d831959bf 100644
--- a/drivers/net/ice/base/ice_cgu_regs.h
+++ b/drivers/net/ice/base/ice_cgu_regs.h
@@ -64,6 +64,17 @@ union nac_cgu_dword11_e825c {
 	u32 val;
 };
 
+#define NAC_CGU_DWORD16_E825C 0x40
+union nac_cgu_dword16_e825c {
+	struct {
+		u32 synce_remndr : 6;
+		u32 synce_phlmt_en : 1;
+		u32 misc13 : 17;
+		u32 tspll_ck_refclkfreq : 8;
+	} field;
+	u32 val;
+};
+
 #define NAC_CGU_DWORD19 0x4c
 union nac_cgu_dword19 {
 	struct {
@@ -120,6 +131,13 @@ union nac_cgu_dword23_e825c {
 	u32 val;
 };
 
+union nac_cgu_dword24_e825c {
+	struct {
+		u32 tspll_fbdiv_frac : 32;
+	} field;
+	u32 val;
+};
+
 #define NAC_CGU_DWORD24 0x60
 union nac_cgu_dword24 {
 	struct {
@@ -134,6 +152,7 @@ union nac_cgu_dword24 {
 	u32 val;
 };
 
+
 #define TSPLL_CNTR_BIST_SETTINGS 0x344
 union tspll_cntr_bist_settings {
 	struct {
diff --git a/drivers/net/ice/base/ice_common.c b/drivers/net/ice/base/ice_common.c
index 48d5fff42a..4750076b7d 100644
--- a/drivers/net/ice/base/ice_common.c
+++ b/drivers/net/ice/base/ice_common.c
@@ -2585,6 +2585,10 @@ ice_parse_1588_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
 
 	info->clk_src = ((number & ICE_TS_CLK_SRC_M) != 0);
 	clk_freq = (number & ICE_TS_CLK_FREQ_M) >> ICE_TS_CLK_FREQ_S;
+	if (ice_is_e825c(hw)) {
+		info->clk_src = ICE_CLK_SRC_TCX0;
+		clk_freq = ICE_TIME_REF_FREQ_156_250;
+	}
 	if (clk_freq < NUM_ICE_TIME_REF_FREQ) {
 		info->time_ref = (enum ice_time_ref_freq)clk_freq;
 	} else {
diff --git a/drivers/net/ice/base/ice_ptp_consts.h b/drivers/net/ice/base/ice_ptp_consts.h
index bd0258f437..d1f4fd2738 100644
--- a/drivers/net/ice/base/ice_ptp_consts.h
+++ b/drivers/net/ice/base/ice_ptp_consts.h
@@ -157,6 +157,81 @@ const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = {
 	},
 };
 
+const
+struct ice_cgu_pll_params_e825c e825c_cgu_params[NUM_ICE_TIME_REF_FREQ] = {
+	/* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */
+	{
+		/* tspll_ck_refclkfreq */
+		0x19,
+		/* tspll_ndivratio */
+		1,
+		/* tspll_fbdiv_intgr */
+		320,
+		/* tspll_fbdiv_frac */
+		0,
+	},
+
+	/* ICE_TIME_REF_FREQ_122_880 -> 122.88 MHz */
+	{
+		/* tspll_ck_refclkfreq */
+		0x29,
+		/* tspll_ndivratio */
+		3,
+		/* tspll_fbdiv_intgr */
+		195,
+		/* tspll_fbdiv_frac */
+		1342177280,
+	},
+
+	/* ICE_TIME_REF_FREQ_125_000 -> 125 MHz */
+	{
+		/* tspll_ck_refclkfreq */
+		0x3E,
+		/* tspll_ndivratio */
+		2,
+		/* tspll_fbdiv_intgr */
+		128,
+		/* tspll_fbdiv_frac */
+		0,
+	},
+
+	/* ICE_TIME_REF_FREQ_153_600 -> 153.6 MHz */
+	{
+		/* tspll_ck_refclkfreq */
+		0x33,
+		/* tspll_ndivratio */
+		3,
+		/* tspll_fbdiv_intgr */
+		156,
+		/* tspll_fbdiv_frac */
+		1073741824,
+	},
+
+	/* ICE_TIME_REF_FREQ_156_250 -> 156.25 MHz */
+	{
+		/* tspll_ck_refclkfreq */
+		0x1F,
+		/* tspll_ndivratio */
+		5,
+		/* tspll_fbdiv_intgr */
+		256,
+		/* tspll_fbdiv_frac */
+		0,
+	},
+
+	/* ICE_TIME_REF_FREQ_245_760 -> 245.76 MHz */
+	{
+		/* tspll_ck_refclkfreq */
+		0x52,
+		/* tspll_ndivratio */
+		3,
+		/* tspll_fbdiv_intgr */
+		97,
+		/* tspll_fbdiv_frac */
+		2818572288,
+	},
+};
+
 /*
  * struct ice_vernier_info_e822
  *
diff --git a/drivers/net/ice/base/ice_ptp_hw.c b/drivers/net/ice/base/ice_ptp_hw.c
index 004f659eae..e574ae6d4f 100644
--- a/drivers/net/ice/base/ice_ptp_hw.c
+++ b/drivers/net/ice/base/ice_ptp_hw.c
@@ -362,10 +362,11 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 		      enum ice_clk_src *clk_src)
 {
 	union tspll_ro_lock_e825c ro_lock;
+	union nac_cgu_dword16_e825c dw16;
 	union nac_cgu_dword23_e825c dw23;
+	union nac_cgu_dword24_e825c dw24;
 	union nac_cgu_dword19 dw19;
 	union nac_cgu_dword22 dw22;
-	union nac_cgu_dword24 dw24;
 	union nac_cgu_dword9 dw9;
 	int err;
 
@@ -380,8 +381,8 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 	}
 
 	if (*clk_src == ICE_CLK_SRC_TCX0 &&
-	    *clk_freq != ICE_TIME_REF_FREQ_25_000) {
-		ice_warn(hw, "TCX0 only supports 25 MHz frequency\n");
+	    *clk_freq != ICE_TIME_REF_FREQ_156_250) {
+		ice_warn(hw, "TCX0 only supports 156.25 MHz frequency\n");
 		return ICE_ERR_PARAM;
 	}
 
@@ -393,6 +394,10 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 	if (err)
 		return err;
 
+	err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD16_E825C, &dw16.val);
+	if (err)
+		return err;
+
 	err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, &dw23.val);
 	if (err)
 		return err;
@@ -403,7 +408,7 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 
 	/* Log the current clock configuration */
 	ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
-		  dw24.field.ts_pll_enable ? "enabled" : "disabled",
+		  dw23.field.ts_pll_enable ? "enabled" : "disabled",
 		  ice_clk_src_str(dw23.field.time_ref_sel),
 		  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
 		  ro_lock.field.plllock_true_lock_cri ? "locked" : "unlocked");
@@ -418,19 +423,43 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 			return err;
 	}
 
-	/* Set the frequency */
+	if (dw9.field.time_sync_en) {
+		dw9.field.time_sync_en = 0;
+
+		err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9,
+					     dw9.val);
+		if (err)
+			return err;
+	}
+
+	/* Set the frequency and enable the correct receiver */
 	dw9.field.time_ref_freq_sel = *clk_freq;
+	if (*clk_src == ICE_CLK_SRC_TCX0) {
+		dw9.field.time_ref_en = 0;
+		dw9.field.clk_eref0_en = 1;
+	} else {
+		dw9.field.time_ref_en = 1;
+		dw9.field.clk_eref0_en = 0;
+	}
+	dw9.field.time_sync_en = 1;
 	err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val);
 	if (err)
 		return err;
 
+	/* Choose the referenced frequency */
+	dw16.field.tspll_ck_refclkfreq =
+	e825c_cgu_params[*clk_freq].tspll_ck_refclkfreq;
+	err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD16_E825C, dw16.val);
+	if (err)
+		return err;
+
 	/* Configure the TS PLL feedback divisor */
 	err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val);
 	if (err)
 		return err;
 
-	dw19.field.tspll_fbdiv_intgr = e822_cgu_params[*clk_freq].feedback_div;
-	dw19.field.tspll_ndivratio = 1;
+	dw19.field.tspll_fbdiv_intgr = e825c_cgu_params[*clk_freq].tspll_fbdiv_intgr;
+	dw19.field.tspll_ndivratio = e825c_cgu_params[*clk_freq].tspll_ndivratio;
 
 	err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val);
 	if (err)
@@ -441,7 +470,8 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 	if (err)
 		return err;
 
-	dw22.field.time1588clk_div = e822_cgu_params[*clk_freq].post_pll_div;
+	/* those two are constant for E825C */
+	dw22.field.time1588clk_div = 5;
 	dw22.field.time1588clk_sel_div2 = 0;
 
 	err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val);
@@ -453,14 +483,14 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 	if (err)
 		return err;
 
-	dw23.field.ref1588_ck_div = e822_cgu_params[*clk_freq].refclk_pre_div;
+	dw23.field.ref1588_ck_div = REF1588_CK_DIV;
 	dw23.field.time_ref_sel = *clk_src;
 
 	err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD23_E825C, dw23.val);
 	if (err)
 		return err;
 
-	dw24.field.tspll_fbdiv_frac = e822_cgu_params[*clk_freq].frac_n_div;
+	dw24.field.tspll_fbdiv_frac = e825c_cgu_params[*clk_freq].tspll_fbdiv_frac;
 
 	err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
 	if (err)
@@ -486,11 +516,9 @@ ice_cfg_cgu_pll_e825c(struct ice_hw *hw, enum ice_time_ref_freq *clk_freq,
 	}
 
 	/* Log the current clock configuration */
-	ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
-		  dw24.field.ts_pll_enable ? "enabled" : "disabled",
+	ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- clk_src %s, clk_freq %s\n",
 		  ice_clk_src_str(dw23.field.time_ref_sel),
-		  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
-		  ro_lock.field.plllock_true_lock_cri ? "locked" : "unlocked");
+		  ice_clk_freq_str(dw9.field.time_ref_freq_sel));
 
 	*clk_freq = (enum ice_time_ref_freq)dw9.field.time_ref_freq_sel;
 	*clk_src = (enum ice_clk_src)dw23.field.time_ref_sel;
@@ -770,7 +798,10 @@ static int ice_init_cgu_e82x(struct ice_hw *hw)
 		ice_warn(hw, "Failed to lock TS PLL to predefined frequency. Retrying with fallback frequency.\n");
 
 		/* Try to lock to internal 25 MHz TCXO as a fallback */
-		time_ref_freq = ICE_TIME_REF_FREQ_25_000;
+		if (hw->phy_model == ICE_PHY_ETH56G)
+			time_ref_freq = ICE_TIME_REF_FREQ_156_250;
+		else
+			time_ref_freq = ICE_TIME_REF_FREQ_25_000;
 		clk_src = ICE_CLK_SRC_TCX0;
 		if (ice_is_e825c(hw))
 			err = ice_cfg_cgu_pll_e825c(hw, &time_ref_freq,
@@ -2328,21 +2359,15 @@ ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port)
  */
 static void ice_sb_access_ena_eth56g(struct ice_hw *hw, bool enable)
 {
-	u32 regval;
-
 	/* Enable reading and writing switch and PHY registers over the
 	 * sideband queue.
 	 */
-#define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1)
-#define PF_SB_REM_DEV_CTL_PHY0 BIT(2)
-	regval = rd32(hw, PF_SB_REM_DEV_CTL);
+	u32 regval = rd32(hw, PF_SB_REM_DEV_CTL);
+
 	if (enable)
-		regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ |
-			   PF_SB_REM_DEV_CTL_PHY0);
+		regval |= (cgu | eth56g_dev_0 | eth56g_dev_1);
 	else
-		regval &= ~(PF_SB_REM_DEV_CTL_SWITCH_READ |
-			    PF_SB_REM_DEV_CTL_PHY0);
-
+		regval &= ~(cgu | eth56g_dev_0 | eth56g_dev_1);
 	wr32(hw, PF_SB_REM_DEV_CTL, regval);
 }
 
diff --git a/drivers/net/ice/base/ice_ptp_hw.h b/drivers/net/ice/base/ice_ptp_hw.h
index 9357dfd327..5d6636c0d1 100644
--- a/drivers/net/ice/base/ice_ptp_hw.h
+++ b/drivers/net/ice/base/ice_ptp_hw.h
@@ -122,6 +122,27 @@ struct ice_cgu_pll_params_e822 {
 extern const struct
 ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ];
 
+/**
+ * struct ice_cgu_pll_params_e825c
+ * @tspll_ck_refclkfreq: tspll_ck_refclkfreq selection
+ * @tspll_ndivratio: ndiv ratio that goes directly to the pll
+ * @tspll_fbdiv_intgr: TS PLL integer feedback divide
+ * @tspll_fbdiv_frac:  TS PLL fractional feedback divide
+ *
+ * Clock Generation Unit parameters used to program the PLL based on the
+ * selected TIME_REF/TCXO frequency.
+ */
+struct ice_cgu_pll_params_e825c {
+	u32 tspll_ck_refclkfreq;
+	u32 tspll_ndivratio;
+	u32 tspll_fbdiv_intgr;
+	u32 tspll_fbdiv_frac;
+};
+
+extern const struct
+ice_cgu_pll_params_e825c e825c_cgu_params[NUM_ICE_TIME_REF_FREQ];
+#define REF1588_CK_DIV 0
+
 /* Table of constants related to possible TIME_REF sources */
 extern const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ];
 
-- 
2.43.0


  parent reply	other threads:[~2024-08-23 10:51 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-22  9:56 [PATCH v1 00/12] Align ICE shared code with Base driver Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 01/12] net/ice: use correct format specifiers for unsigned ints Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 02/12] net/ice: updates for ptp init GNRD Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 03/12] net/ice: add new tag definitions Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 04/12] net/ice: avoid reading past end of PFA Soumyadeep Hore
2024-08-22 14:41   ` Bruce Richardson
2024-08-22  9:56 ` [PATCH v1 05/12] net/ice: update PTP init Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 06/12] net/ice: address compilation errors Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 07/12] net/ice: fix link speed for 200G Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 08/12] net/ice: update iteration of TLVs in Preserved Fields Area Soumyadeep Hore
2024-08-22 14:45   ` Bruce Richardson
2024-08-23  6:55     ` Hore, Soumyadeep
2024-08-22  9:56 ` [PATCH v1 09/12] net/ice: correct Tx Scheduler AQ command RD bit for E825C Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 10/12] net/ice: support optional flags in signature segment header Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 11/12] net/ice: update E830 50G branding strings Soumyadeep Hore
2024-08-22  9:56 ` [PATCH v1 12/12] net/ice: add support for FEC auto-detect for Connorsville Soumyadeep Hore
2024-08-22 18:53 ` [PATCH v2 00/12] Align ICE shared code with Base driver Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 01/12] net/ice: use correct format specifiers for unsigned ints Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 02/12] net/ice: updates for ptp init in E825C Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 03/12] net/ice: add new tag definitions Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 04/12] net/ice: avoid reading past end of PFA Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 05/12] net/ice: update PTP init Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 06/12] net/ice: address compilation errors Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 07/12] net/ice: fix link speed for 200G Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 08/12] net/ice: update iteration of TLVs in Preserved Fields Area Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 09/12] net/ice: correct Tx Scheduler AQ command RD bit for E825C Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 10/12] net/ice: support optional flags in signature segment header Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 11/12] net/ice: update E830 50G branding strings Soumyadeep Hore
2024-08-22 18:53   ` [PATCH v2 12/12] net/ice: add support for FEC auto-detect for E830 Soumyadeep Hore
2024-08-23  9:56     ` [PATCH v3 00/12] Align ICE shared code with Base driver Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 01/12] net/ice: use correct format specifiers for unsigned ints Soumyadeep Hore
2024-08-27 10:00         ` Bruce Richardson
2024-08-23  9:56       ` Soumyadeep Hore [this message]
2024-08-28 10:53         ` [PATCH v3 02/12] net/ice: updates for ptp init in E825C Bruce Richardson
2024-08-23  9:56       ` [PATCH v3 03/12] net/ice: add new tag definitions Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 04/12] net/ice: avoid reading past end of PFA Soumyadeep Hore
2024-08-28 15:36         ` Bruce Richardson
2024-08-23  9:56       ` [PATCH v3 05/12] net/ice: update PTP init Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 06/12] net/ice: address compilation errors Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 07/12] net/ice: fix link speed for 200G Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 08/12] net/ice: update iteration of TLVs in Preserved Fields Area Soumyadeep Hore
2024-08-28 16:05         ` Bruce Richardson
2024-08-23  9:56       ` [PATCH v3 09/12] net/ice: correct Tx Scheduler AQ command RD bit for E825C Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 10/12] net/ice: support optional flags in signature segment header Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 11/12] net/ice: update E830 50G branding strings Soumyadeep Hore
2024-08-23  9:56       ` [PATCH v3 12/12] net/ice: add support for FEC auto-detect for E830 Soumyadeep Hore
2024-08-26 15:55       ` [PATCH v3 00/12] Align ICE shared code with Base driver Patrick Robb
2024-08-28 16:42       ` Bruce Richardson
2024-09-13 10:22         ` Bruce Richardson

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=20240823095650.349785-3-soumyadeep.hore@intel.com \
    --to=soumyadeep.hore@intel.com \
    --cc=aman.deep.singh@intel.com \
    --cc=bruce.richardson@intel.com \
    --cc=dev@dpdk.org \
    --cc=ian.stokes@intel.com \
    --cc=norbertx.zulinski@intel.com \
    --cc=shaiq.wani@intel.com \
    --cc=stable@dpdk.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).