All of lore.kernel.org
 help / color / mirror / Atom feed
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
To: Archit Taneja <architt@codeaurora.org>, agross@codeaurora.org
Cc: galak@codeaurora.org, linux-arm-msm@vger.kernel.org
Subject: Re: [PATCH 1/3] dmaengine: qcom_bam_dma: Generalize BAM register offset calculations
Date: Fri, 19 Sep 2014 01:26:03 +0100	[thread overview]
Message-ID: <541B781B.6010209@linaro.org> (raw)
In-Reply-To: <1411037575-13153-1-git-send-email-architt@codeaurora.org>

Hi Andy,

Does this patchset supersede "dmaengine: qcom_bam_dma: Add v1.3.0 ..."
https://lkml.org/lkml/2014/4/16/660

--srini


On 18/09/14 11:52, Archit Taneja wrote:
> The BAM DMA IP comes in different versions. The register offset layout varies
> among these versions. The layouts depend on which generation/family of SoCs they
> belong to.
>
"dmaengine: qcom_bam_dma: Add v1.3.0 ..."
https://lkml.org/lkml/
> The current SoCs(like 8084, 8074) have a layout where the Top level registers
> come in the beginning of the address range, followed by pipe and event
> registers. The BAM revision numbers fall above 1.4.0.
>
> The older SoCs (like 8064, 8960) have a layout where the pipe registers come
> first, and the top level come later. These have BAM revision numbers lesser than
> 1.4.0.
> -#define BAM_CTRL		
>
> It isn't suitable to have macros provide the register offsets with the layouts
> changed. Future BAM revisions may have different register layouts too. The
> register addresses are now calculated by referring a table which contains a base
> offset and multipliers for pipe/evnt/ee registers.
>
> We have a common function bam_addr() which computes addresses for all the
> registers. When computing address of top level/ee registers, we pass 0 to the
> pipe argument in addr() since they don't have any multiple instances.
>
> Some of the unused register definitions are removed. We can add new registers as
> we need them.
>
> Signed-off-by: Archit Taneja <architt@codeaurora.org>
> ---
>   drivers/dma/qcom_bam_dma.c | 176 +++++++++++++++++++++++++++++----------------
>   1 file changed, 113 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/dma/qcom_bam_dma.c b/drivers/dma/qcom_bam_dma.c
> index 7a4bbb0..b5a1662 100644
> --- a/drivers/dma/qcom_bam_dma.c
> +++ b/drivers/dma/qcom_bam_dma.c
> @@ -79,35 +79,68 @@ struct bam_async_desc {
>   	struct bam_desc_hw desc[0];
>   };
>
> -#define BAM_CTRL			0x0000
> -#define BAM_REVISION			0x0004
> -#define BAM_SW_REVISION			0x0080
> -#define BAM_NUM_PIPES			0x003C
> -#define BAM_TIMER			0x0040
> -#define BAM_TIMER_CTRL			0x0044
> -#define BAM_DESC_CNT_TRSHLD		0x0008
> -#define BAM_IRQ_SRCS			0x000C
> -#define BAM_IRQ_SRCS_MSK		0x0010
> -#define BAM_IRQ_SRCS_UNMASKED		0x0030
> -#define BAM_IRQ_STTS			0x0014
> -#define BAM_IRQ_CLR			0x0018
> -#define BAM_IRQ_EN			0x001C
> -#define BAM_CNFG_BITS			0x007C
> -#define BAM_IRQ_SRCS_EE(ee)		(0x0800 + ((ee) * 0x80))
> -#define BAM_IRQ_SRCS_MSK_EE(ee)		(0x0804 + ((ee) * 0x80))
> -#define BAM_P_CTRL(pipe)		(0x1000 + ((pipe) * 0x1000))
> -#define BAM_P_RST(pipe)			(0x1004 + ((pipe) * 0x1000))
> -#define BAM_P_HALT(pipe)		(0x1008 + ((pipe) * 0x1000))
> -#define BAM_P_IRQ_STTS(pipe)		(0x1010 + ((pipe) * 0x1000))
> -#define BAM_P_IRQ_CLR(pipe)		(0x1014 + ((pipe) * 0x1000))
> -#define BAM_P_IRQ_EN(pipe)		(0x1018 + ((pipe) * 0x1000))
> -#define BAM_P_EVNT_DEST_ADDR(pipe)	(0x182C + ((pipe) * 0x1000))
> -#define BAM_P_EVNT_REG(pipe)		(0x1818 + ((pipe) * 0x1000))
> -#define BAM_P_SW_OFSTS(pipe)		(0x1800 + ((pipe) * 0x1000))
> -#define BAM_P_DATA_FIFO_ADDR(pipe)	(0x1824 + ((pipe) * 0x1000))
> -#define BAM_P_DESC_FIFO_ADDR(pipe)	(0x181C + ((pipe) * 0x1000))
> -#define BAM_P_EVNT_TRSHLD(pipe)		(0x1828 + ((pipe) * 0x1000))
> -#define BAM_P_FIFO_SIZES(pipe)		(0x1820 + ((pipe) * 0x1000))
> +enum bam_reg {
> +	BAM_CTRL,
> +	BAM_REVISION,
> +	BAM_NUM_PIPES,
> +	BAM_DESC_CNT_TRSHLD,
> +	BAM_IRQ_SRCS,
> +	BAM_IRQ_SRCS_MSK,
> +	BAM_IRQ_SRCS_UNMASKED,
> +	BAM_IRQ_STTS,
> +	BAM_IRQ_CLR,
> +	BAM_IRQ_EN,
> +	BAM_CNFG_BITS,
> +	BAM_IRQ_SRCS_EE,
> +	BAM_IRQ_SRCS_MSK_EE,
> +	BAM_P_CTRL,
> +	BAM_P_RST,
> +	BAM_P_HALT,
> +	BAM_P_IRQ_STTS,
> +	BAM_P_IRQ_CLR,
> +	BAM_P_IRQ_EN,
> +	BAM_P_EVNT_DEST_ADDR,
> +	BAM_P_EVNT_REG,
> +	BAM_P_SW_OFSTS,
> +	BAM_P_DATA_FIFO_ADDR,
> +	BAM_P_DESC_FIFO_ADDR,
> +	BAM_P_EVNT_GEN_TRSHLD,
> +	BAM_P_FIFO_SIZES,
> +};
> +
> +struct reg_offset_data {
> +	u32 base_offset;
> +	unsigned int pipe_mult, evnt_mult, ee_mult;
> +};
> +
> +static const struct reg_offset_data reg_info[] = {
> +	[BAM_CTRL]		= { 0x0000, 0x00, 0x00, 0x00 },
> +	[BAM_REVISION]		= { 0x0004, 0x00, 0x00, 0x00 },
> +	[BAM_NUM_PIPES]		= { 0x003C, 0x00, 0x00, 0x00 },
> +	[BAM_DESC_CNT_TRSHLD]	= { 0x0008, 0x00, 0x00, 0x00 },
> +	[BAM_IRQ_SRCS]		= { 0x000C, 0x00, 0x00, 0x00 },
> +	[BAM_IRQ_SRCS_MSK]	= { 0x0010, 0x00, 0x00, 0x00 },
> +	[BAM_IRQ_SRCS_UNMASKED]	= { 0x0030, 0x00, 0x00, 0x00 },
> +	[BAM_IRQ_STTS]		= { 0x0014, 0x00, 0x00, 0x00 },
> +	[BAM_IRQ_CLR]		= { 0x0018, 0x00, 0x00, 0x00 },
> +	[BAM_IRQ_EN]		= { 0x001C, 0x00, 0x00, 0x00 },
> +	[BAM_CNFG_BITS]		= { 0x007C, 0x00, 0x00, 0x00 },
> +	[BAM_IRQ_SRCS_EE]	= { 0x0800, 0x00, 0x00, 0x80 },
> +	[BAM_IRQ_SRCS_MSK_EE]	= { 0x0804, 0x00, 0x00, 0x80 },
> +	[BAM_P_CTRL]		= { 0x1000, 0x1000, 0x00, 0x00 },
> +	[BAM_P_RST]		= { 0x1004, 0x1000, 0x00, 0x00 },
> +	[BAM_P_HALT]		= { 0x1008, 0x1000, 0x00, 0x00 },
> +	[BAM_P_IRQ_STTS]	= { 0x1010, 0x1000, 0x00, 0x00 },
> +	[BAM_P_IRQ_CLR]		= { 0x1014, 0x1000, 0x00, 0x00 },
> +	[BAM_P_IRQ_EN]		= { 0x1018, 0x1000, 0x00, 0x00 },
> +	[BAM_P_EVNT_DEST_ADDR]	= { 0x102C, 0x00, 0x1000, 0x00 },
> +	[BAM_P_EVNT_REG]	= { 0x1018, 0x00, 0x1000, 0x00 },
> +	[BAM_P_SW_OFSTS]	= { 0x1000, 0x00, 0x1000, 0x00 },
> +	[BAM_P_DATA_FIFO_ADDR]	= { 0x1824, 0x00, 0x1000, 0x00 },
> +	[BAM_P_DESC_FIFO_ADDR]	= { 0x181C, 0x00, 0x1000, 0x00 },
> +	[BAM_P_EVNT_GEN_TRSHLD]	= { 0x1828, 0x00, 0x1000, 0x00 },
> +	[BAM_P_FIFO_SIZES]	= { 0x1820, 0x00, 0x1000, 0x00 },
> +};
>
>   /* BAM CTRL */
>   #define BAM_SW_RST			BIT(0)
> @@ -305,6 +338,23 @@ struct bam_device {
>   };
>
>   /**
> + * bam_addr - returns BAM register address
> + * @bdev: bam device
> + * @pipe: pipe instance (ignored when register doesn't have multiple instances)
> + * @reg:  register enum
> + */
> +static inline void __iomem *bam_addr(struct bam_device *bdev, u32 pipe,
> +		enum bam_reg reg)
> +{
> +	const struct reg_offset_data r = reg_info[reg];
> +
> +	return bdev->regs + r.base_offset +
> +		r.pipe_mult * pipe +
> +		r.evnt_mult * pipe +
> +		r.ee_mult * bdev->ee;
> +}
> +
> +/**
>    * bam_reset_channel - Reset individual BAM DMA channel
>    * @bchan: bam channel
>    *
> @@ -317,8 +367,8 @@ static void bam_reset_channel(struct bam_chan *bchan)
>   	lockdep_assert_held(&bchan->vc.lock);
>
>   	/* reset channel */
> -	writel_relaxed(1, bdev->regs + BAM_P_RST(bchan->id));
> -	writel_relaxed(0, bdev->regs + BAM_P_RST(bchan->id));
> +	writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_RST));
> +	writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_RST));
>
>   	/* don't allow cpu to reorder BAM register accesses done after this */
>   	wmb();
> @@ -347,17 +397,18 @@ static void bam_chan_init_hw(struct bam_chan *bchan,
>   	 * because we allocated 1 more descriptor (8 bytes) than we can use
>   	 */
>   	writel_relaxed(ALIGN(bchan->fifo_phys, sizeof(struct bam_desc_hw)),
> -			bdev->regs + BAM_P_DESC_FIFO_ADDR(bchan->id));
> -	writel_relaxed(BAM_DESC_FIFO_SIZE, bdev->regs +
> -			BAM_P_FIFO_SIZES(bchan->id));
> +			bam_addr(bdev, bchan->id, BAM_P_DESC_FIFO_ADDR));
> +	writel_relaxed(BAM_DESC_FIFO_SIZE,
> +			bam_addr(bdev, bchan->id, BAM_P_FIFO_SIZES));
>
>   	/* enable the per pipe interrupts, enable EOT, ERR, and INT irqs */
> -	writel_relaxed(P_DEFAULT_IRQS_EN, bdev->regs + BAM_P_IRQ_EN(bchan->id));
> +	writel_relaxed(P_DEFAULT_IRQS_EN,
> +			bam_addr(bdev, bchan->id, BAM_P_IRQ_EN));
>
>   	/* unmask the specific pipe and EE combo */
> -	val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
> +	val = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
>   	val |= BIT(bchan->id);
> -	writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
> +	writel_relaxed(val, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
>
>   	/* don't allow cpu to reorder the channel enable done below */
>   	wmb();
> @@ -367,7 +418,7 @@ static void bam_chan_init_hw(struct bam_chan *bchan,
>   	if (dir == DMA_DEV_TO_MEM)
>   		val |= P_DIRECTION;
>
> -	writel_relaxed(val, bdev->regs + BAM_P_CTRL(bchan->id));
> +	writel_relaxed(val, bam_addr(bdev, bchan->id, BAM_P_CTRL));
>
>   	bchan->initialized = 1;
>
> @@ -432,12 +483,12 @@ static void bam_free_chan(struct dma_chan *chan)
>   	bchan->fifo_virt = NULL;
>
>   	/* mask irq for pipe/channel */
> -	val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
> +	val = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
>   	val &= ~BIT(bchan->id);
> -	writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
> +	writel_relaxed(val, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
>
>   	/* disable irq */
> -	writel_relaxed(0, bdev->regs + BAM_P_IRQ_EN(bchan->id));
> +	writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_IRQ_EN));
>   }
>
>   /**
> @@ -583,14 +634,14 @@ static int bam_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
>   	switch (cmd) {
>   	case DMA_PAUSE:
>   		spin_lock_irqsave(&bchan->vc.lock, flag);
> -		writel_relaxed(1, bdev->regs + BAM_P_HALT(bchan->id));
> +		writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_HALT));
>   		bchan->paused = 1;
>   		spin_unlock_irqrestore(&bchan->vc.lock, flag);
>   		break;
>
>   	case DMA_RESUME:
>   		spin_lock_irqsave(&bchan->vc.lock, flag);
> -		writel_relaxed(0, bdev->regs + BAM_P_HALT(bchan->id));
> +		writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_HALT));
>   		bchan->paused = 0;
>   		spin_unlock_irqrestore(&bchan->vc.lock, flag);
>   		break;
> @@ -626,7 +677,7 @@ static u32 process_channel_irqs(struct bam_device *bdev)
>   	unsigned long flags;
>   	struct bam_async_desc *async_desc;
>
> -	srcs = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_EE(bdev->ee));
> +	srcs = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_EE));
>
>   	/* return early if no pipe/channel interrupts are present */
>   	if (!(srcs & P_IRQ))
> @@ -639,11 +690,9 @@ static u32 process_channel_irqs(struct bam_device *bdev)
>   			continue;
>
>   		/* clear pipe irq */
> -		pipe_stts = readl_relaxed(bdev->regs +
> -			BAM_P_IRQ_STTS(i));
> +		pipe_stts = readl_relaxed(bam_addr(bdev, i, BAM_P_IRQ_STTS));
>
> -		writel_relaxed(pipe_stts, bdev->regs +
> -				BAM_P_IRQ_CLR(i));
> +		writel_relaxed(pipe_stts, bam_addr(bdev, i, BAM_P_IRQ_CLR));
>
>   		spin_lock_irqsave(&bchan->vc.lock, flags);
>   		async_desc = bchan->curr_txd;
> @@ -694,12 +743,12 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
>   		tasklet_schedule(&bdev->task);
>
>   	if (srcs & BAM_IRQ)
> -		clr_mask = readl_relaxed(bdev->regs + BAM_IRQ_STTS);
> +		clr_mask = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_STTS));
>
>   	/* don't allow reorder of the various accesses to the BAM registers */
>   	mb();
>
> -	writel_relaxed(clr_mask, bdev->regs + BAM_IRQ_CLR);
> +	writel_relaxed(clr_mask, bam_addr(bdev, 0, BAM_IRQ_CLR));
>
>   	return IRQ_HANDLED;
>   }
> @@ -763,7 +812,7 @@ static void bam_apply_new_config(struct bam_chan *bchan,
>   	else
>   		maxburst = bchan->slave.dst_maxburst;
>
> -	writel_relaxed(maxburst, bdev->regs + BAM_DESC_CNT_TRSHLD);
> +	writel_relaxed(maxburst, bam_addr(bdev, 0, BAM_DESC_CNT_TRSHLD));
>
>   	bchan->reconfigure = 0;
>   }
> @@ -830,7 +879,7 @@ static void bam_start_dma(struct bam_chan *bchan)
>   	/* ensure descriptor writes and dma start not reordered */
>   	wmb();
>   	writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
> -			bdev->regs + BAM_P_EVNT_REG(bchan->id));
> +			bam_addr(bdev, bchan->id, BAM_P_EVNT_REG));
>   }
>
>   /**
> @@ -918,43 +967,44 @@ static int bam_init(struct bam_device *bdev)
>   	u32 val;
>
>   	/* read revision and configuration information */
> -	val = readl_relaxed(bdev->regs + BAM_REVISION) >> NUM_EES_SHIFT;
> +	val = readl_relaxed(bam_addr(bdev, 0, BAM_REVISION)) >> NUM_EES_SHIFT;
>   	val &= NUM_EES_MASK;
>
>   	/* check that configured EE is within range */
>   	if (bdev->ee >= val)
>   		return -EINVAL;
>
> -	val = readl_relaxed(bdev->regs + BAM_NUM_PIPES);
> +	val = readl_relaxed(bam_addr(bdev, 0, BAM_NUM_PIPES));
>   	bdev->num_channels = val & BAM_NUM_PIPES_MASK;
>
>   	/* s/w reset bam */
>   	/* after reset all pipes are disabled and idle */
> -	val = readl_relaxed(bdev->regs + BAM_CTRL);
> +	val = readl_relaxed(bam_addr(bdev, 0, BAM_CTRL));
>   	val |= BAM_SW_RST;
> -	writel_relaxed(val, bdev->regs + BAM_CTRL);
> +	writel_relaxed(val, bam_addr(bdev, 0, BAM_CTRL));
>   	val &= ~BAM_SW_RST;
> -	writel_relaxed(val, bdev->regs + BAM_CTRL);
> +	writel_relaxed(val, bam_addr(bdev, 0, BAM_CTRL));
>
>   	/* make sure previous stores are visible before enabling BAM */
>   	wmb();
>
>   	/* enable bam */
>   	val |= BAM_EN;
> -	writel_relaxed(val, bdev->regs + BAM_CTRL);
> +	writel_relaxed(val, bam_addr(bdev, 0, BAM_CTRL));
>
>   	/* set descriptor threshhold, start with 4 bytes */
> -	writel_relaxed(DEFAULT_CNT_THRSHLD, bdev->regs + BAM_DESC_CNT_TRSHLD);
> +	writel_relaxed(DEFAULT_CNT_THRSHLD,
> +			bam_addr(bdev, 0, BAM_DESC_CNT_TRSHLD));
>
>   	/* Enable default set of h/w workarounds, ie all except BAM_FULL_PIPE */
> -	writel_relaxed(BAM_CNFG_BITS_DEFAULT, bdev->regs + BAM_CNFG_BITS);
> +	writel_relaxed(BAM_CNFG_BITS_DEFAULT, bam_addr(bdev, 0, BAM_CNFG_BITS));
>
>   	/* enable irqs for errors */
>   	writel_relaxed(BAM_ERROR_EN | BAM_HRESP_ERR_EN,
> -				bdev->regs + BAM_IRQ_EN);
> +			bam_addr(bdev, 0, BAM_IRQ_EN));
>
>   	/* unmask global bam interrupt */
> -	writel_relaxed(BAM_IRQ_MSK, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
> +	writel_relaxed(BAM_IRQ_MSK, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
>
>   	return 0;
>   }
> @@ -1084,7 +1134,7 @@ static int bam_dma_remove(struct platform_device *pdev)
>   	dma_async_device_unregister(&bdev->common);
>
>   	/* mask all interrupts for this execution environment */
> -	writel_relaxed(0, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
> +	writel_relaxed(0, bam_addr(bdev, 0,  BAM_IRQ_SRCS_MSK_EE));
>
>   	devm_free_irq(bdev->dev, bdev->irq, bdev);
>
>

  parent reply	other threads:[~2014-09-19  0:26 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-18 10:52 [PATCH 1/3] dmaengine: qcom_bam_dma: Generalize BAM register offset calculations Archit Taneja
2014-09-18 10:52 ` [PATCH 2/3] dmaengine: qcom_bam_dma: Add BAM v1.3.0 support Archit Taneja
2014-09-19 19:00   ` Kumar Gala
2014-09-22  4:51   ` Andy Gross
2014-09-18 10:52 ` [PATCH 3/3] dt/bindings: dmaengine: qcom_bam_dma: Add compatible string for BAM v1.3.0 Archit Taneja
2014-09-19 19:00   ` Kumar Gala
2014-09-22  4:56   ` Andy Gross
2014-09-19  0:26 ` Srinivas Kandagatla [this message]
2014-09-22  4:44   ` [PATCH 1/3] dmaengine: qcom_bam_dma: Generalize BAM register offset calculations Andy Gross
2014-09-19 19:00 ` Kumar Gala
2014-09-22  4:48 ` Andy Gross
2014-09-29  4:33 ` [PATCH v2 " Archit Taneja
     [not found]   ` <1411965189-24499-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2014-09-29  4:33     ` [PATCH v2 2/3] dmaengine: qcom_bam_dma: Add BAM v1.3.0 support Archit Taneja
2014-09-29  4:33       ` Archit Taneja
2014-11-12 10:40     ` [PATCH v2 1/3] dmaengine: qcom_bam_dma: Generalize BAM register offset calculations Vinod Koul
2014-11-12 10:40       ` Vinod Koul
2014-09-29  4:33   ` [PATCH v2 3/3] dt/bindings: dmaengine: qcom_bam_dma: Add compatible string for BAM v1.3.0 Archit Taneja
2014-09-29 22:14   ` [PATCH v2 1/3] dmaengine: qcom_bam_dma: Generalize BAM register offset calculations Andy Gross
     [not found]     ` <20140929221406.GE11142-zC7DfRvBq/JWk0Htik3J/w@public.gmane.org>
2014-10-01  8:22       ` Pramod Gurav
2014-10-01  8:22         ` Pramod Gurav
2014-10-02  5:24         ` Andy Gross

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=541B781B.6010209@linaro.org \
    --to=srinivas.kandagatla@linaro.org \
    --cc=agross@codeaurora.org \
    --cc=architt@codeaurora.org \
    --cc=galak@codeaurora.org \
    --cc=linux-arm-msm@vger.kernel.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 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.