All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Harrison <john.c.harrison@intel.com>
To: Matthew Brost <matthew.brost@intel.com>,
	<intel-gfx@lists.freedesktop.org>,
	<dri-devel@lists.freedesktop.org>
Cc: <daniel.vetter@ffwll.ch>, <tony.ye@intel.com>, <zhengguo.xu@intel.com>
Subject: Re: [Intel-gfx] [PATCH 12/27] drm/i915/guc: Add multi-lrc context registration
Date: Wed, 15 Sep 2021 12:21:35 -0700	[thread overview]
Message-ID: <64a5c154-1a00-820e-2b30-d95af73937d7@intel.com> (raw)
In-Reply-To: <20210820224446.30620-13-matthew.brost@intel.com>

On 8/20/2021 15:44, Matthew Brost wrote:
> Add multi-lrc context registration H2G. In addition a workqueue and
> process descriptor are setup during multi-lrc context registration as
> these data structures are needed for multi-lrc submission.
>
> Signed-off-by: Matthew Brost <matthew.brost@intel.com>
> ---
>   drivers/gpu/drm/i915/gt/intel_context_types.h |  12 ++
>   drivers/gpu/drm/i915/gt/intel_lrc.c           |   5 +
>   drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |   2 +-
>   .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 109 +++++++++++++++++-
>   4 files changed, 126 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
> index 0fafc178cf2c..6f567ebeb039 100644
> --- a/drivers/gpu/drm/i915/gt/intel_context_types.h
> +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
> @@ -232,8 +232,20 @@ struct intel_context {
>   		/** @parent: pointer to parent if child */
>   		struct intel_context *parent;
>   
> +
> +		/** @guc_wqi_head: head pointer in work queue */
> +		u16 guc_wqi_head;
> +		/** @guc_wqi_tail: tail pointer in work queue */
> +		u16 guc_wqi_tail;
> +
These should be in the 'guc_state' sub-struct? Would be good to keep all 
GuC specific content in one self-contained struct. Especially given the 
other child/parent fields are no going to be guc_ prefixed any more.


>   		/** @guc_number_children: number of children if parent */
>   		u8 guc_number_children;
> +
> +		/**
> +		 * @parent_page: page in context used by parent for work queue,
Maybe 'page in context record'? Otherwise, exactly what 'context' is 
meant here? It isn't the 'struct intel_context'. The contetx record is 
saved as 'ce->state' / 'ce->lrc_reg_state', yes? Is it possible to link 
to either of those field? Probably not given that they don't appear to 
have any kerneldoc description :(. Maybe add that in too :).

> +		 * work queue descriptor
Later on, it is described as 'process descriptor and work queue'. It 
would be good to be consistent.

> +		 */
> +		u8 parent_page;
>   	};
>   
>   #ifdef CONFIG_DRM_I915_SELFTEST
> diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
> index bb4af4977920..0ddbad4e062a 100644
> --- a/drivers/gpu/drm/i915/gt/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
> @@ -861,6 +861,11 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine)
>   		context_size += PAGE_SIZE;
>   	}
>   
> +	if (intel_context_is_parent(ce)) {
> +		ce->parent_page = context_size / PAGE_SIZE;
> +		context_size += PAGE_SIZE;
> +	}
> +
>   	obj = i915_gem_object_create_lmem(engine->i915, context_size, 0);
>   	if (IS_ERR(obj))
>   		obj = i915_gem_object_create_shmem(engine->i915, context_size);
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> index fa4be13c8854..0e600a3b8f1e 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
> @@ -52,7 +52,7 @@
>   
>   #define GUC_DOORBELL_INVALID		256
>   
> -#define GUC_WQ_SIZE			(PAGE_SIZE * 2)
> +#define GUC_WQ_SIZE			(PAGE_SIZE / 2)
Is this size actually dictated by the GuC API? Or is it just a driver 
level decision? If the latter, shouldn't this be below instead?

>   
>   /* Work queue item header definitions */
>   #define WQ_STATUS_ACTIVE		1
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> index 14b24298cdd7..dbcb9ab28a9a 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> @@ -340,6 +340,39 @@ static struct i915_priolist *to_priolist(struct rb_node *rb)
>   	return rb_entry(rb, struct i915_priolist, node);
>   }
>   
> +/*
> + * When using multi-lrc submission an extra page in the context state is
> + * reserved for the process descriptor and work queue.
> + *
> + * The layout of this page is below:
> + * 0						guc_process_desc
> + * ...						unused
> + * PAGE_SIZE / 2				work queue start
> + * ...						work queue
> + * PAGE_SIZE - 1				work queue end
> + */
> +#define WQ_OFFSET	(PAGE_SIZE / 2)
Can this not be derived from GUC_WQ_SIZE given that the two are 
fundamentally linked? E.g. '#define WQ_OFFSET (PAGE_SIZE - 
GUC_WQ_SIZE)'? And maybe have a '#define WQ_TOTAL_SIZE PAGE_SIZE' and 
use that in all of WQ_OFFSET, GUC_WQ_SIZE and the allocation itself in 
intel_lrc.c?

Also, the process descriptor is actually an array of descriptors sized 
by the number of children? Or am I misunderstanding the code below? In 
so, shouldn't there be a 'COMPILE_BUG_ON((MAX_ENGINE_INSTANCE * 
sizeof(descriptor)) < (WQ_DESC_SIZE)' where WQ_DESC_SIZE is 
WQ_TOTAL_SIZE - WQ_SIZE?

> +static u32 __get_process_desc_offset(struct intel_context *ce)
> +{
> +	GEM_BUG_ON(!ce->parent_page);
> +
> +	return ce->parent_page * PAGE_SIZE;
> +}
> +
> +static u32 __get_wq_offset(struct intel_context *ce)
> +{
> +	return __get_process_desc_offset(ce) + WQ_OFFSET;
> +}
> +
> +static struct guc_process_desc *
> +__get_process_desc(struct intel_context *ce)
> +{
> +	return (struct guc_process_desc *)
> +		(ce->lrc_reg_state +
> +		 ((__get_process_desc_offset(ce) -
> +		   LRC_STATE_OFFSET) / sizeof(u32)));
Where did the LRC_STATE_OFFSET come from? Is that built in to the 
lrg_reg_state pointer itself? That needs to be documented somewhere.

> +}
> +
>   static struct guc_lrc_desc *__get_lrc_desc(struct intel_guc *guc, u32 index)
>   {
>   	struct guc_lrc_desc *base = guc->lrc_desc_pool_vaddr;
> @@ -1342,6 +1375,30 @@ static void unpin_guc_id(struct intel_guc *guc, struct intel_context *ce)
>   	spin_unlock_irqrestore(&guc->submission_state.lock, flags);
>   }
>   
> +static int __guc_action_register_multi_lrc(struct intel_guc *guc,
> +					   struct intel_context *ce,
> +					   u32 guc_id,
> +					   u32 offset,
> +					   bool loop)
> +{
> +	struct intel_context *child;
> +	u32 action[4 + MAX_ENGINE_INSTANCE];
> +	int len = 0;
> +
> +	GEM_BUG_ON(ce->guc_number_children > MAX_ENGINE_INSTANCE);
> +
> +	action[len++] = INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC;
> +	action[len++] = guc_id;
> +	action[len++] = ce->guc_number_children + 1;
> +	action[len++] = offset;
> +	for_each_child(ce, child) {
> +		offset += sizeof(struct guc_lrc_desc);
> +		action[len++] = offset;
> +	}
> +
> +	return guc_submission_send_busy_loop(guc, action, len, 0, loop);
> +}
> +
>   static int __guc_action_register_context(struct intel_guc *guc,
>   					 u32 guc_id,
>   					 u32 offset,
> @@ -1364,9 +1421,15 @@ static int register_context(struct intel_context *ce, bool loop)
>   		ce->guc_id.id * sizeof(struct guc_lrc_desc);
>   	int ret;
>   
> +	GEM_BUG_ON(intel_context_is_child(ce));
>   	trace_intel_context_register(ce);
>   
> -	ret = __guc_action_register_context(guc, ce->guc_id.id, offset, loop);
> +	if (intel_context_is_parent(ce))
> +		ret = __guc_action_register_multi_lrc(guc, ce, ce->guc_id.id,
> +						      offset, loop);
> +	else
> +		ret = __guc_action_register_context(guc, ce->guc_id.id, offset,
> +						    loop);
>   	if (likely(!ret)) {
>   		unsigned long flags;
>   
> @@ -1396,6 +1459,7 @@ static int deregister_context(struct intel_context *ce, u32 guc_id, bool loop)
>   {
>   	struct intel_guc *guc = ce_to_guc(ce);
>   
> +	GEM_BUG_ON(intel_context_is_child(ce));
>   	trace_intel_context_deregister(ce);
>   
>   	return __guc_action_deregister_context(guc, guc_id, loop);
> @@ -1423,6 +1487,7 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop)
>   	struct guc_lrc_desc *desc;
>   	bool context_registered;
>   	intel_wakeref_t wakeref;
> +	struct intel_context *child;
>   	int ret = 0;
>   
>   	GEM_BUG_ON(!engine->mask);
> @@ -1448,6 +1513,42 @@ static int guc_lrc_desc_pin(struct intel_context *ce, bool loop)
>   	desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
>   	guc_context_policy_init(engine, desc);
>   
> +	/*
> +	 * Context is a parent, we need to register a process descriptor
> +	 * describing a work queue and register all child contexts.
Technically, this should say 'If the context is a parent'. Or just move 
it to be inside the if block.

> +	 */
> +	if (intel_context_is_parent(ce)) {
> +		struct guc_process_desc *pdesc;
> +
> +		ce->guc_wqi_tail = 0;
> +		ce->guc_wqi_head = 0;
> +
> +		desc->process_desc = i915_ggtt_offset(ce->state) +
> +			__get_process_desc_offset(ce);
> +		desc->wq_addr = i915_ggtt_offset(ce->state) +
> +			__get_wq_offset(ce);
> +		desc->wq_size = GUC_WQ_SIZE;
> +
> +		pdesc = __get_process_desc(ce);
> +		memset(pdesc, 0, sizeof(*(pdesc)));
> +		pdesc->stage_id = ce->guc_id.id;
> +		pdesc->wq_base_addr = desc->wq_addr;
> +		pdesc->wq_size_bytes = desc->wq_size;
> +		pdesc->priority = GUC_CLIENT_PRIORITY_KMD_NORMAL;
Should this not be inherited from the ce? And same below. Or are we not 
using this priority in that way?

John.

> +		pdesc->wq_status = WQ_STATUS_ACTIVE;
> +
> +		for_each_child(ce, child) {
> +			desc = __get_lrc_desc(guc, child->guc_id.id);
> +
> +			desc->engine_class =
> +				engine_class_to_guc_class(engine->class);
> +			desc->hw_context_desc = child->lrc.lrca;
> +			desc->priority = GUC_CLIENT_PRIORITY_KMD_NORMAL;
> +			desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
> +			guc_context_policy_init(engine, desc);
> +		}
> +	}
> +
>   	/*
>   	 * The context_lookup xarray is used to determine if the hardware
>   	 * context is currently registered. There are two cases in which it
> @@ -2858,6 +2959,12 @@ g2h_context_lookup(struct intel_guc *guc, u32 desc_idx)
>   		return NULL;
>   	}
>   
> +	if (unlikely(intel_context_is_child(ce))) {
> +		drm_err(&guc_to_gt(guc)->i915->drm,
> +			"Context is child, desc_idx %u", desc_idx);
> +		return NULL;
> +	}
> +
>   	return ce;
>   }
>   


  reply	other threads:[~2021-09-15 19:21 UTC|newest]

Thread overview: 145+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-20 22:44 [PATCH 00/27] Parallel submission aka multi-bb execbuf Matthew Brost
2021-08-20 22:44 ` [Intel-gfx] " Matthew Brost
2021-08-20 22:44 ` [PATCH 01/27] drm/i915/guc: Squash Clean up GuC CI failures, simplify locking, and kernel DOC Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-08-20 22:44 ` [PATCH 02/27] drm/i915/guc: Allow flexible number of context ids Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-09 22:13   ` John Harrison
2021-09-10  0:14     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 03/27] drm/i915/guc: Connect the number of guc_ids to debugfs Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-09 22:16   ` John Harrison
2021-09-10  0:16     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 04/27] drm/i915/guc: Take GT PM ref when deregistering context Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-09 22:28   ` John Harrison
2021-09-10  0:21     ` Matthew Brost
2021-09-13  9:55   ` Tvrtko Ursulin
2021-09-13 17:12     ` Matthew Brost
2021-09-14  8:41       ` Tvrtko Ursulin
2021-08-20 22:44 ` [PATCH 05/27] drm/i915: Add GT PM unpark worker Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-09 22:36   ` John Harrison
2021-09-10  0:34     ` Matthew Brost
2021-09-10  8:36   ` Tvrtko Ursulin
2021-09-10 20:09     ` Matthew Brost
2021-09-13 10:33       ` Tvrtko Ursulin
2021-09-13 17:20         ` Matthew Brost
2021-08-20 22:44 ` [PATCH 06/27] drm/i915/guc: Take engine PM when a context is pinned with GuC submission Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-09 22:46   ` John Harrison
2021-09-10  0:41     ` Matthew Brost
2021-09-13 22:26       ` John Harrison
2021-09-14  1:12         ` Matthew Brost
2021-08-20 22:44 ` [PATCH 07/27] drm/i915/guc: Don't call switch_to_kernel_context " Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-09 22:51   ` John Harrison
2021-09-13 16:54     ` Matthew Brost
2021-09-13 22:38       ` John Harrison
2021-09-14  5:02         ` Matthew Brost
2021-09-13 16:55     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 08/27] drm/i915: Add logical engine mapping Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-10 11:12   ` Tvrtko Ursulin
2021-09-10 19:49     ` Matthew Brost
2021-09-13  9:24       ` Tvrtko Ursulin
2021-09-13 16:50         ` Matthew Brost
2021-09-14  8:34           ` Tvrtko Ursulin
2021-09-14 18:04             ` Matthew Brost
2021-09-15  8:24               ` Tvrtko Ursulin
2021-09-15 16:58                 ` Matthew Brost
2021-09-16  8:31                   ` Tvrtko Ursulin
2021-08-20 22:44 ` [PATCH 09/27] drm/i915: Expose logical engine instance to user Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-13 23:06   ` John Harrison
2021-09-14  1:08     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 10/27] drm/i915/guc: Introduce context parent-child relationship Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-13 23:19   ` John Harrison
2021-09-14  1:18     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 11/27] drm/i915/guc: Implement parallel context pin / unpin functions Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-08-20 22:44 ` [PATCH 12/27] drm/i915/guc: Add multi-lrc context registration Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-15 19:21   ` John Harrison [this message]
2021-09-15 19:31     ` Matthew Brost
2021-09-15 20:23       ` John Harrison
2021-09-15 20:33         ` Matthew Brost
2021-08-20 22:44 ` [PATCH 13/27] drm/i915/guc: Ensure GuC schedule operations do not operate on child contexts Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-15 19:24   ` John Harrison
2021-09-15 19:34     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 14/27] drm/i915/guc: Assign contexts in parent-child relationship consecutive guc_ids Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-15 20:04   ` John Harrison
2021-09-15 20:55     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 15/27] drm/i915/guc: Implement multi-lrc submission Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-08-21 14:04   ` kernel test robot
2021-08-21 14:04     ` kernel test robot
2021-08-21 14:04     ` kernel test robot
2021-08-22  2:18   ` kernel test robot
2021-08-22  2:18     ` kernel test robot
2021-08-22  2:18     ` [Intel-gfx] " kernel test robot
2021-09-20 21:48   ` John Harrison
2021-09-22 16:25     ` Matthew Brost
2021-09-22 20:15       ` John Harrison
2021-09-23  2:44         ` Matthew Brost
2021-08-20 22:44 ` [PATCH 16/27] drm/i915/guc: Insert submit fences between requests in parent-child relationship Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-20 21:57   ` John Harrison
2021-08-20 22:44 ` [PATCH 17/27] drm/i915/guc: Implement multi-lrc reset Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-20 22:44   ` John Harrison
2021-09-22 16:16     ` Matthew Brost
2021-08-20 22:44 ` [Intel-gfx] [PATCH 18/27] drm/i915/guc: Update debugfs for GuC multi-lrc Matthew Brost
2021-08-20 22:44   ` Matthew Brost
2021-09-20 22:48   ` [Intel-gfx] " John Harrison
2021-09-21 19:13     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 19/27] drm/i915: Fix bug in user proto-context creation that leaked contexts Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-20 22:57   ` John Harrison
2021-09-21 14:49     ` Tvrtko Ursulin
2021-09-21 19:28       ` Matthew Brost
2021-09-21 19:28     ` Matthew Brost
2021-08-20 22:44 ` [Intel-gfx] [PATCH 20/27] drm/i915/guc: Connect UAPI to GuC multi-lrc interface Matthew Brost
2021-08-20 22:44   ` Matthew Brost
2021-08-29  4:00   ` [Intel-gfx] " kernel test robot
2021-08-29  4:00     ` kernel test robot
2021-08-29 19:59   ` kernel test robot
2021-08-29 19:59     ` kernel test robot
2021-09-21  0:09   ` John Harrison
2021-09-22 16:38     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 21/27] drm/i915/doc: Update parallel submit doc to point to i915_drm.h Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-21  0:12   ` John Harrison
2021-08-20 22:44 ` [PATCH 22/27] drm/i915/guc: Add basic GuC multi-lrc selftest Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-28 20:47   ` John Harrison
2021-08-20 22:44 ` [PATCH 23/27] drm/i915/guc: Implement no mid batch preemption for multi-lrc Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-10 11:25   ` Tvrtko Ursulin
2021-09-10 20:49     ` Matthew Brost
2021-09-13 10:52       ` Tvrtko Ursulin
2021-09-28 22:20   ` John Harrison
2021-09-28 22:33     ` Matthew Brost
2021-09-28 23:33       ` John Harrison
2021-09-29  0:22         ` Matthew Brost
2021-08-20 22:44 ` [PATCH 24/27] drm/i915: Multi-BB execbuf Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-08-21 19:01   ` kernel test robot
2021-08-21 19:01     ` kernel test robot
2021-08-30  3:46   ` kernel test robot
2021-08-30  3:46     ` kernel test robot
2021-09-30 22:16   ` Matthew Brost
2021-08-20 22:44 ` [PATCH 25/27] drm/i915/guc: Handle errors in multi-lrc requests Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-09-29 20:44   ` John Harrison
2021-09-29 20:58     ` Matthew Brost
2021-08-20 22:44 ` [PATCH 26/27] drm/i915: Enable multi-bb execbuf Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-08-20 22:44 ` [PATCH 27/27] drm/i915/execlists: Weak parallel submission support for execlists Matthew Brost
2021-08-20 22:44   ` [Intel-gfx] " Matthew Brost
2021-08-20 23:13 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for Parallel submission aka multi-bb execbuf (rev3) Patchwork
2021-08-20 23:14 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-08-20 23:45 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork

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=64a5c154-1a00-820e-2b30-d95af73937d7@intel.com \
    --to=john.c.harrison@intel.com \
    --cc=daniel.vetter@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=matthew.brost@intel.com \
    --cc=tony.ye@intel.com \
    --cc=zhengguo.xu@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.