DPDK patches and discussions
 help / color / mirror / Atom feed
From: Wenbo Cao <caowenbo@mucse.com>
To: Wenbo Cao <caowenbo@mucse.com>
Cc: dev@dpdk.org, ferruh.yigit@amd.com, thomas@monjalon.net,
	andrew.rybchenko@oktetlabs.ru, yaojun@mucse.com
Subject: [PATCH v6 5/8] net/rnp add reset code for Chip Init process
Date: Fri,  1 Sep 2023 02:30:47 +0000	[thread overview]
Message-ID: <20230901023050.40893-6-caowenbo@mucse.com> (raw)
In-Reply-To: <20230901023050.40893-1-caowenbo@mucse.com>

we must get the shape info of nic from Firmware for
reset. so the related codes is first get firmware info
and then reset the chip

Signed-off-by: Wenbo Cao <caowenbo@mucse.com>
---
 drivers/net/rnp/base/rnp_hw.h |  56 +++++++++++-
 drivers/net/rnp/meson.build   |   3 +
 drivers/net/rnp/rnp.h         |  27 ++++++
 drivers/net/rnp/rnp_ethdev.c  |  93 ++++++++++++++++++-
 drivers/net/rnp/rnp_mbx_fw.h  | 163 +++++++++++++++++++++++++++++++++-
 5 files changed, 339 insertions(+), 3 deletions(-)

diff --git a/drivers/net/rnp/base/rnp_hw.h b/drivers/net/rnp/base/rnp_hw.h
index 1db966cf21..57b7dc75a0 100644
--- a/drivers/net/rnp/base/rnp_hw.h
+++ b/drivers/net/rnp/base/rnp_hw.h
@@ -8,6 +8,9 @@
 #include <ethdev_driver.h>
 
 #include "rnp_osdep.h"
+#include "rnp_dma_regs.h"
+#include "rnp_eth_regs.h"
+#include "rnp_cfg.h"
 
 static inline unsigned int rnp_rd_reg(volatile void *addr)
 {
@@ -29,7 +32,18 @@ static inline void rnp_wr_reg(volatile void *reg, int val)
 	rnp_rd_reg((uint8_t *)(_base) + (_off))
 #define rnp_io_wr(_base, _off, _val)	\
 	rnp_wr_reg((uint8_t *)(_base) + (_off), (_val))
-
+#define rnp_eth_rd(_hw, _off)		\
+	rnp_rd_reg((uint8_t *)((_hw)->eth_base) + (_off))
+#define rnp_eth_wr(_hw, _off, _val)	\
+	rnp_wr_reg((uint8_t *)((_hw)->eth_base) + (_off), (_val))
+#define rnp_dma_rd(_hw, _off)		\
+	rnp_rd_reg((uint8_t *)((_hw)->dma_base) + (_off))
+#define rnp_dma_wr(_hw, _off, _val)	\
+	rnp_wr_reg((uint8_t *)((_hw)->dma_base) + (_off), (_val))
+#define rnp_top_rd(_hw, _off)		\
+	rnp_rd_reg((uint8_t *)((_hw)->comm_reg_base) + (_off))
+#define rnp_top_wr(_hw, _off, _val)	\
+	rnp_wr_reg((uint8_t *)((_hw)->comm_reg_base) + (_off), (_val))
 struct rnp_hw;
 /* Mbx Operate info */
 enum MBX_ID {
@@ -98,6 +112,17 @@ struct rnp_mbx_info {
 	rte_atomic16_t state;
 } __rte_cache_aligned;
 
+struct rnp_mac_api {
+	int32_t (*init_hw)(struct rnp_hw *hw);
+	int32_t (*reset_hw)(struct rnp_hw *hw);
+};
+
+struct rnp_mac_info {
+	uint8_t assign_addr[RTE_ETHER_ADDR_LEN];
+	uint8_t set_addr[RTE_ETHER_ADDR_LEN];
+	struct rnp_mac_api ops;
+} __rte_cache_aligned;
+
 struct rnp_eth_adapter;
 #define RNP_MAX_HW_PORT_PERR_PF (4)
 struct rnp_hw {
@@ -111,8 +136,10 @@ struct rnp_hw {
 	void *eth_base;
 	void *veb_base;
 	void *mac_base[RNP_MAX_HW_PORT_PERR_PF];
+	void *comm_reg_base;
 	void *msix_base;
 	/* === dma == */
+	void *dev_version;
 	void *dma_axi_en;
 	void *dma_axi_st;
 
@@ -120,10 +147,37 @@ struct rnp_hw {
 	uint16_t vendor_id;
 	uint16_t function;
 	uint16_t pf_vf_num;
+	int pfvfnum;
 	uint16_t max_vfs;
+
+	bool ncsi_en;
+	uint8_t ncsi_rar_entries;
+
+	int sgmii_phy_id;
+	int is_sgmii;
+	u16 phy_type;
+	uint8_t force_10g_1g_speed_ablity;
+	uint8_t force_speed_stat;
+#define FORCE_SPEED_STAT_DISABLED       (0)
+#define FORCE_SPEED_STAT_1G             (1)
+#define FORCE_SPEED_STAT_10G            (2)
+	uint32_t speed;
+	unsigned int axi_mhz;
+
+	int fw_version;  /* Primary FW Version */
+	uint32_t fw_uid; /* Subclass Fw Version */
+
+	int nic_mode;
+	unsigned char lane_mask;
+	int lane_of_port[4];
+	char phy_port_ids[4]; /* port id: for lane0~3: value: 0 ~ 7 */
+	uint8_t max_port_num; /* Max Port Num This PF Have */
+
 	void *cookie_pool;
 	char cookie_p_name[RTE_MEMZONE_NAMESIZE];
 
+	struct rnp_mac_info mac;
 	struct rnp_mbx_info mbx;
+	rte_spinlock_t fw_lock;
 } __rte_cache_aligned;
 #endif /* __RNP_H__*/
diff --git a/drivers/net/rnp/meson.build b/drivers/net/rnp/meson.build
index 60bba486fc..855c894032 100644
--- a/drivers/net/rnp/meson.build
+++ b/drivers/net/rnp/meson.build
@@ -9,5 +9,8 @@ endif
 sources = files(
 		'rnp_ethdev.c',
 		'rnp_mbx.c',
+		'rnp_mbx_fw.c',
+		'base/rnp_api.c',
 )
+
 includes += include_directories('base')
diff --git a/drivers/net/rnp/rnp.h b/drivers/net/rnp/rnp.h
index 6e12885877..45638aae5b 100644
--- a/drivers/net/rnp/rnp.h
+++ b/drivers/net/rnp/rnp.h
@@ -13,6 +13,20 @@
 #define RNP_CFG_BAR		(4)
 #define RNP_PF_INFO_BAR		(0)
 
+enum rnp_resource_share_m {
+	RNP_SHARE_CORPORATE = 0,
+	RNP_SHARE_INDEPENDENT,
+};
+/*
+ * Structure to store private data for each driver instance (for each port).
+ */
+enum rnp_work_mode {
+	RNP_SINGLE_40G = 0,
+	RNP_SINGLE_10G = 1,
+	RNP_DUAL_10G = 2,
+	RNP_QUAD_10G = 3,
+};
+
 struct rnp_eth_port {
 	struct rnp_eth_adapter *adapt;
 	struct rnp_hw *hw;
@@ -21,9 +35,12 @@ struct rnp_eth_port {
 
 struct rnp_share_ops {
 	const struct rnp_mbx_api *mbx_api;
+	const struct rnp_mac_api *mac_api;
 } __rte_cache_aligned;
 
 struct rnp_eth_adapter {
+	enum rnp_work_mode mode;
+	enum rnp_resource_share_m s_mode; /* Port Resource Share Policy */
 	struct rnp_hw hw;
 	uint16_t max_vfs;
 	struct rte_pci_device *pdev;
@@ -31,7 +48,9 @@ struct rnp_eth_adapter {
 	struct rnp_eth_port *ports[RNP_MAX_PORT_OF_PF];
 	struct rnp_share_ops *share_priv;
 
+	int max_link_speed;
 	uint8_t num_ports; /* Cur Pf Has physical Port Num */
+	uint8_t lane_mask;
 } __rte_cache_aligned;
 
 #define RNP_DEV_TO_PORT(eth_dev) \
@@ -40,9 +59,14 @@ struct rnp_eth_adapter {
 	((struct rnp_eth_adapter *)(RNP_DEV_TO_PORT(eth_dev)->adapt))
 #define RNP_DEV_TO_HW(eth_dev) \
 	(&((struct rnp_eth_adapter *)(RNP_DEV_TO_PORT((eth_dev))->adapt))->hw)
+#define RNP_HW_TO_ADAPTER(hw) \
+	((struct rnp_eth_adapter *)((hw)->back))
 #define RNP_DEV_PP_PRIV_TO_MBX_OPS(dev) \
 	(((struct rnp_share_ops *)(dev)->process_private)->mbx_api)
 #define RNP_DEV_TO_MBX_OPS(dev)	RNP_DEV_PP_PRIV_TO_MBX_OPS(dev)
+#define RNP_DEV_PP_PRIV_TO_MAC_OPS(dev) \
+	(((struct rnp_share_ops *)(dev)->process_private)->mac_api)
+#define RNP_DEV_TO_MAC_OPS(dev) RNP_DEV_PP_PRIV_TO_MAC_OPS(dev)
 
 static inline void rnp_reg_offset_init(struct rnp_hw *hw)
 {
@@ -56,6 +80,7 @@ static inline void rnp_reg_offset_init(struct rnp_hw *hw)
 		hw->msix_base = (void *)((uint8_t *)hw->iobar4 + 0xa4000);
 	}
 	/* === dma status/config====== */
+	hw->dev_version = (void *)((uint8_t *)hw->iobar4 + 0x0000);
 	hw->link_sync = (void *)((uint8_t *)hw->iobar4 + 0x000c);
 	hw->dma_axi_en = (void *)((uint8_t *)hw->iobar4 + 0x0010);
 	hw->dma_axi_st = (void *)((uint8_t *)hw->iobar4 + 0x0014);
@@ -69,5 +94,7 @@ static inline void rnp_reg_offset_init(struct rnp_hw *hw)
 	/* mac */
 	for (i = 0; i < RNP_MAX_HW_PORT_PERR_PF; i++)
 		hw->mac_base[i] = (void *)((uint8_t *)hw->iobar4 + 0x60000 + 0x10000 * i);
+	/* ===  top reg === */
+	hw->comm_reg_base = (void *)((uint8_t *)hw->iobar4 + 0x30000);
 }
 #endif /* __RNP_H__ */
diff --git a/drivers/net/rnp/rnp_ethdev.c b/drivers/net/rnp/rnp_ethdev.c
index a2dc27548a..8bb4fd5963 100644
--- a/drivers/net/rnp/rnp_ethdev.c
+++ b/drivers/net/rnp/rnp_ethdev.c
@@ -8,7 +8,9 @@
 #include <ethdev_driver.h>
 
 #include "rnp.h"
+#include "rnp_api.h"
 #include "rnp_mbx.h"
+#include "rnp_mbx_fw.h"
 #include "rnp_logs.h"
 
 static int
@@ -92,7 +94,30 @@ rnp_alloc_eth_port(struct rte_pci_device *primary_pci, char *name)
 
 static void rnp_get_nic_attr(struct rnp_eth_adapter *adapter)
 {
-	RTE_SET_USED(adapter);
+	struct rnp_hw *hw = &adapter->hw;
+	int lane_mask = 0, err, mode = 0;
+
+	rnp_mbx_link_event_enable(adapter->eth_dev, false);
+
+	err = rnp_mbx_get_capability(adapter->eth_dev, &lane_mask, &mode);
+	if (err < 0 || !lane_mask) {
+		PMD_DRV_LOG(ERR, "%s: mbx_get_capability error! errcode=%d\n",
+				__func__, hw->speed);
+		return;
+	}
+
+	adapter->num_ports = __builtin_popcount(lane_mask);
+	adapter->max_link_speed = hw->speed;
+	adapter->lane_mask = lane_mask;
+	adapter->mode = hw->nic_mode;
+
+	PMD_DRV_LOG(INFO, "max link speed:%d lane_mask:0x%x nic-mode:0x%x\n",
+			(int)adapter->max_link_speed,
+			(int)adapter->num_ports, adapter->mode);
+	if (adapter->num_ports && adapter->num_ports == 1)
+		adapter->s_mode = RNP_SHARE_CORPORATE;
+	else
+		adapter->s_mode = RNP_SHARE_INDEPENDENT;
 }
 
 static int
@@ -125,6 +150,72 @@ rnp_process_resource_init(struct rte_eth_dev *eth_dev)
 	return 0;
 }
 
+static int32_t rnp_init_hw_pf(struct rnp_hw *hw)
+{
+	struct rnp_eth_adapter *adapter = RNP_HW_TO_ADAPTER(hw);
+	uint32_t version;
+	uint32_t reg;
+
+	PMD_INIT_FUNC_TRACE();
+	version = rnp_rd_reg(hw->dev_version);
+	PMD_DRV_LOG(INFO, "NIC HW Version:0x%.2x\n", version);
+
+	/* Disable Rx/Tx Dma */
+	rnp_wr_reg(hw->dma_axi_en, false);
+	/* Check Dma Chanle Status */
+	while (rnp_rd_reg(hw->dma_axi_st) == 0)
+		;
+
+	/* Reset Nic All Hardware */
+	if (rnp_reset_hw(adapter->eth_dev, hw))
+		return -EPERM;
+
+	/* Rx Proto Offload No-BYPASS */
+	rnp_eth_wr(hw, RNP_ETH_ENGINE_BYPASS, false);
+	/* Enable Flow Filter Engine */
+	rnp_eth_wr(hw, RNP_HOST_FILTER_EN, true);
+	/* Enable VXLAN Parse */
+	rnp_eth_wr(hw, RNP_EN_TUNNEL_VXLAN_PARSE, true);
+	/* Enabled REDIR ACTION */
+	rnp_eth_wr(hw, RNP_REDIR_CTRL, true);
+
+	/* Setup Scatter DMA Mem Size */
+	reg = ((RTE_ETHER_MAX_LEN / 16) << RNP_DMA_SCATTER_MEM_SHIFT);
+	rnp_dma_wr(hw,  RNP_DMA_CTRL, reg);
+#ifdef PHYTIUM_SUPPORT
+#define RNP_DMA_PADDING      (1 << 8)
+	reg = rnp_dma_rd(hw, RNP_DMA_CTRL);
+	reg |= RNP_DMA_PADDING;
+	rnp_dma_wr(hw, RNP_DMA_CTRL, reg);
+#endif
+	/* Enable Rx/Tx Dma */
+	rnp_wr_reg(hw->dma_axi_en, 0b1111);
+
+	rnp_top_wr(hw, RNP_TX_QINQ_WORKAROUND, 1);
+
+	return 0;
+}
+
+static int32_t rnp_reset_hw_pf(struct rnp_hw *hw)
+{
+	struct rnp_eth_adapter *adapter = hw->back;
+
+	rnp_top_wr(hw, RNP_NIC_RESET, 0);
+	rte_wmb();
+	rnp_top_wr(hw, RNP_NIC_RESET, 1);
+
+	rnp_mbx_fw_reset_phy(adapter->eth_dev);
+
+	PMD_DRV_LOG(INFO, "PF[%d] reset nic finish\n",
+			hw->function);
+	return 0;
+}
+
+const struct rnp_mac_api rnp_mac_ops = {
+	.reset_hw	= rnp_reset_hw_pf,
+	.init_hw	= rnp_init_hw_pf
+};
+
 static void
 rnp_common_ops_init(struct rnp_eth_adapter *adapter)
 {
diff --git a/drivers/net/rnp/rnp_mbx_fw.h b/drivers/net/rnp/rnp_mbx_fw.h
index 439090b5a3..f842639c86 100644
--- a/drivers/net/rnp/rnp_mbx_fw.h
+++ b/drivers/net/rnp/rnp_mbx_fw.h
@@ -16,7 +16,168 @@ struct mbx_req_cookie {
 	int priv_len;
 	char priv[RNP_MAX_SHARE_MEM];
 };
+enum GENERIC_CMD {
+	/* link configuration admin commands */
+	GET_PHY_ABALITY = 0x0601,
+	RESET_PHY = 0x0603,
+	SET_EVENT_MASK = 0x0613,
+};
+
+enum link_event_mask {
+	EVT_LINK_UP = 1,
+	EVT_NO_MEDIA = 2,
+	EVT_LINK_FAULT = 3,
+	EVT_PHY_TEMP_ALARM = 4,
+	EVT_EXCESSIVE_ERRORS = 5,
+	EVT_SIGNAL_DETECT = 6,
+	EVT_AUTO_NEGOTIATION_DONE = 7,
+	EVT_MODULE_QUALIFICATION_FAILED = 8,
+	EVT_PORT_TX_SUSPEND = 9,
+};
+
+enum pma_type {
+	PHY_TYPE_NONE = 0,
+	PHY_TYPE_1G_BASE_KX,
+	PHY_TYPE_SGMII,
+	PHY_TYPE_10G_BASE_KR,
+	PHY_TYPE_25G_BASE_KR,
+	PHY_TYPE_40G_BASE_KR4,
+	PHY_TYPE_10G_BASE_SR,
+	PHY_TYPE_40G_BASE_SR4,
+	PHY_TYPE_40G_BASE_CR4,
+	PHY_TYPE_40G_BASE_LR4,
+	PHY_TYPE_10G_BASE_LR,
+	PHY_TYPE_10G_BASE_ER,
+};
+
+struct phy_abilities {
+	unsigned char link_stat;
+	unsigned char lane_mask;
+
+	int speed;
+	short phy_type;
+	short nic_mode;
+	short pfnum;
+	unsigned int fw_version;
+	unsigned int axi_mhz;
+	uint8_t port_ids[4];
+	uint32_t fw_uid;
+	uint32_t phy_id;
+
+	int wol_status;
+
+	union {
+		unsigned int ext_ablity;
+		struct {
+			unsigned int valid                 : 1;
+			unsigned int wol_en                : 1;
+			unsigned int pci_preset_runtime_en : 1;
+			unsigned int smbus_en              : 1;
+			unsigned int ncsi_en               : 1;
+			unsigned int rpu_en                : 1;
+			unsigned int v2                    : 1;
+			unsigned int pxe_en                : 1;
+			unsigned int mctp_en               : 1;
+		} e;
+	};
+} __rte_packed __rte_aligned(4);
+
+/* firmware -> driver */
 struct mbx_fw_cmd_reply {
-} __rte_cache_aligned;
+	/* fw must set: DD, CMP, Error(if error), copy value */
+	unsigned short flags;
+	/* from command: LB,RD,VFC,BUF,SI,EI,FE */
+	unsigned short opcode;     /* 2-3: copy from req */
+	unsigned short error_code; /* 4-5: 0 if no error */
+	unsigned short datalen;    /* 6-7: */
+	union {
+		struct {
+			unsigned int cookie_lo; /* 8-11: */
+			unsigned int cookie_hi; /* 12-15: */
+		};
+		void *cookie;
+	};
+	/* ===== data ==== [16-64] */
+	union {
+		struct phy_abilities phy_abilities;
+	};
+} __rte_packed __rte_aligned(4);
+
+#define MBX_REQ_HDR_LEN            24
+/* driver -> firmware */
+struct mbx_fw_cmd_req {
+	unsigned short flags;     /* 0-1 */
+	unsigned short opcode;    /* 2-3 enum LINK_ADM_CMD */
+	unsigned short datalen;   /* 4-5 */
+	unsigned short ret_value; /* 6-7 */
+	union {
+		struct {
+			unsigned int cookie_lo; /* 8-11 */
+			unsigned int cookie_hi; /* 12-15 */
+		};
+		void *cookie;
+	};
+	unsigned int reply_lo; /* 16-19 5dw */
+	unsigned int reply_hi; /* 20-23 */
+	/* === data === [24-64] 7dw */
+	union {
+		struct {
+			int requester;
+#define REQUEST_BY_DPDK 0xa1
+#define REQUEST_BY_DRV  0xa2
+#define REQUEST_BY_PXE  0xa3
+		} get_phy_ablity;
+
+		struct {
+			unsigned short enable_stat;
+			unsigned short event_mask; /* enum link_event_mask */
+		} stat_event_mask;
+	};
+} __rte_packed __rte_aligned(4);
+
+static inline void
+build_phy_abalities_req(struct mbx_fw_cmd_req *req, void *cookie)
+{
+	req->flags   = 0;
+	req->opcode  = GET_PHY_ABALITY;
+	req->datalen = 0;
+	req->reply_lo = 0;
+	req->reply_hi = 0;
+	req->cookie = cookie;
+}
+
+/* enum link_event_mask or */
+static inline void
+build_link_set_event_mask(struct mbx_fw_cmd_req *req,
+			  unsigned short event_mask,
+			  unsigned short enable,
+			  void *cookie)
+{
+	req->flags = 0;
+	req->opcode = SET_EVENT_MASK;
+	req->datalen = sizeof(req->stat_event_mask);
+	req->cookie = cookie;
+	req->reply_lo = 0;
+	req->reply_hi = 0;
+	req->stat_event_mask.event_mask = event_mask;
+	req->stat_event_mask.enable_stat = enable;
+}
+
+static inline void
+build_reset_phy_req(struct mbx_fw_cmd_req *req,
+		    void *cookie)
+{
+	req->flags = 0;
+	req->opcode = RESET_PHY;
+	req->datalen = 0;
+	req->reply_lo = 0;
+	req->reply_hi = 0;
+	req->cookie = cookie;
+}
 
+int rnp_mbx_get_capability(struct rte_eth_dev *dev,
+			   int *lane_mask,
+			   int *nic_mode);
+int rnp_mbx_link_event_enable(struct rte_eth_dev *dev, int enable);
+int rnp_mbx_fw_reset_phy(struct rte_eth_dev *dev);
 #endif /* __RNP_MBX_FW_H__*/
-- 
2.27.0


  parent reply	other threads:[~2023-09-01  2:32 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-01  2:30 [PATCH v6 0/8] [v6]drivers/net Add Support mucse N10 Pmd Driver Wenbo Cao
2023-09-01  2:30 ` [PATCH v6 1/8] net/rnp: add skeleton Wenbo Cao
2023-09-05 15:35   ` Ferruh Yigit
2023-09-06  8:15     ` 11
2024-03-29 11:28   ` Ferruh Yigit
2024-03-29 14:45     ` 11
2024-04-02 10:15       ` Ferruh Yigit
2023-09-01  2:30 ` [PATCH v6 2/8] net/rnp: add ethdev probe and remove Wenbo Cao
2023-09-05 15:36   ` Ferruh Yigit
2023-09-06 10:42     ` 11
2023-09-01  2:30 ` [PATCH v6 3/8] net/rnp: add device init and uninit Wenbo Cao
2023-09-05 15:44   ` Ferruh Yigit
2023-09-06 11:03     ` 11
2023-09-01  2:30 ` [PATCH v6 4/8] net/rnp: add mbx basic api feature Wenbo Cao
2023-09-05 15:45   ` Ferruh Yigit
2023-09-06 10:32     ` 11
2023-09-01  2:30 ` Wenbo Cao [this message]
2023-09-05 15:46   ` [PATCH v6 5/8] net/rnp add reset code for Chip Init process Ferruh Yigit
2023-09-06  9:23     ` 11
2023-09-01  2:30 ` [PATCH v6 6/8] net/rnp add port info resource init Wenbo Cao
2023-09-05 16:56   ` Ferruh Yigit
2023-09-06  9:07     ` 11
2023-09-01  2:30 ` [PATCH v6 7/8] net/rnp add devargs runtime parsing functions Wenbo Cao
2023-09-05 15:46   ` Ferruh Yigit
2023-09-06  9:13     ` 11
2023-09-01  2:30 ` [PATCH v6 8/8] net/rnp handle device interrupts Wenbo Cao
2023-09-05 15:34 ` [PATCH v6 0/8] [v6]drivers/net Add Support mucse N10 Pmd Driver 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=20230901023050.40893-6-caowenbo@mucse.com \
    --to=caowenbo@mucse.com \
    --cc=andrew.rybchenko@oktetlabs.ru \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@amd.com \
    --cc=thomas@monjalon.net \
    --cc=yaojun@mucse.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 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).