All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andres Rodriguez <andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: "Alex Deucher"
	<alexdeucher-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	"Christian König"
	<deathsimple-ANTagKRnAhcb1SvskN2V4Q@public.gmane.org>
Cc: amd-gfx list <amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org>
Subject: Re: [PATCH 16/21] drm/amdgpu: implement lru amdgpu_queue_mgr policy for compute v3
Date: Fri, 3 Mar 2017 12:15:09 -0500	[thread overview]
Message-ID: <cca32fc8-e57a-aba8-e6d6-7bc692a3813e@gmail.com> (raw)
In-Reply-To: <CADnq5_MH2YunUwH79zTaGA2+UGGDQwHZGjN3WqmHsg8EC4-SvQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>



On 3/3/2017 10:20 AM, Alex Deucher wrote:
> On Fri, Mar 3, 2017 at 8:23 AM, Christian König <deathsimple@vodafone.de> wrote:
>> Am 02.03.2017 um 22:44 schrieb Andres Rodriguez:
>>>
>>> Use an LRU policy to map usermode rings to HW compute queues.
>>>
>>> Most compute clients use one queue, and usually the first queue
>>> available. This results in poor pipe/queue work distribution when
>>> multiple compute apps are running. In most cases pipe 0 queue 0 is
>>> the only queue that gets used.
>>>
>>> In order to better distribute work across multiple HW queues, we adopt
>>> a policy to map the usermode ring ids to the LRU HW queue.
>>>
>>> This fixes a large majority of multi-app compute workloads sharing the
>>> same HW queue, even though 7 other queues are available.
>>>
>>> v2: use ring->funcs->type instead of ring->hw_ip
>>> v3: remove amdgpu_queue_mapper_funcs
>>>
>>> Signed-off-by: Andres Rodriguez <andresx7@gmail.com>
>>> ---
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  3 ++
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c    |  3 ++
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c | 38 +++++++++++++++++-
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c      | 57
>>> +++++++++++++++++++++++++++
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h      |  4 ++
>>>   5 files changed, 104 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>>> index d3f87f4..088aa4a 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>>> @@ -1501,20 +1501,23 @@ struct amdgpu_device {
>>>         struct kfd_dev          *kfd;
>>>         struct amdgpu_virt      virt;
>>>         /* link all shadow bo */
>>>         struct list_head                shadow_list;
>>>         struct mutex                    shadow_list_lock;
>>>         /* link all gtt */
>>>         spinlock_t                      gtt_list_lock;
>>>         struct list_head                gtt_list;
>>> +       /* keep an lru list of rings by HW IP */
>>> +       struct list_head                ring_lru_list;
>>> +       struct mutex                    ring_lru_list_lock;
>>
>>
>> No need for a mutex, a spinlock should do as well.
>>
>>
>>>         /* record hw reset is performed */
>>>         bool has_hw_reset;
>>>     };
>>>     static inline struct amdgpu_device *amdgpu_ttm_adev(struct
>>> ttm_bo_device *bdev)
>>>   {
>>>         return container_of(bdev, struct amdgpu_device, mman.bdev);
>>>   }
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> index 6abb238..954e3b9 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> @@ -1712,20 +1712,23 @@ int amdgpu_device_init(struct amdgpu_device *adev,
>>>         spin_lock_init(&adev->gc_cac_idx_lock);
>>>         spin_lock_init(&adev->audio_endpt_idx_lock);
>>>         spin_lock_init(&adev->mm_stats.lock);
>>>         INIT_LIST_HEAD(&adev->shadow_list);
>>>         mutex_init(&adev->shadow_list_lock);
>>>         INIT_LIST_HEAD(&adev->gtt_list);
>>>         spin_lock_init(&adev->gtt_list_lock);
>>>   +     INIT_LIST_HEAD(&adev->ring_lru_list);
>>> +       mutex_init(&adev->ring_lru_list_lock);
>>> +
>>>         if (adev->asic_type >= CHIP_BONAIRE) {
>>>                 adev->rmmio_base = pci_resource_start(adev->pdev, 5);
>>>                 adev->rmmio_size = pci_resource_len(adev->pdev, 5);
>>>         } else {
>>>                 adev->rmmio_base = pci_resource_start(adev->pdev, 2);
>>>                 adev->rmmio_size = pci_resource_len(adev->pdev, 2);
>>>         }
>>>         adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size);
>>>         if (adev->rmmio == NULL) {
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c
>>> index cafe913..e6e4fba 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c
>>> @@ -84,20 +84,54 @@ static int amdgpu_identity_map(struct amdgpu_device
>>> *adev,
>>>                 break;
>>>         default:
>>>                 *out_ring = NULL;
>>>                 DRM_ERROR("unknown HW IP type: %d\n", mapper->hw_ip);
>>>                 return -EINVAL;
>>>         }
>>>         return update_cached_map(mapper, ring, *out_ring);
>>>   }
>>>   +static enum amdgpu_ring_type amdgpu_hw_ip_to_ring_type(int hw_ip)
>>> +{
>>> +       switch (hw_ip) {
>>> +       case AMDGPU_HW_IP_GFX:
>>> +               return AMDGPU_RING_TYPE_GFX;
>>> +       case AMDGPU_HW_IP_COMPUTE:
>>> +               return AMDGPU_RING_TYPE_COMPUTE;
>>> +       case AMDGPU_HW_IP_DMA:
>>> +               return AMDGPU_RING_TYPE_SDMA;
>>> +       case AMDGPU_HW_IP_UVD:
>>> +               return AMDGPU_RING_TYPE_UVD;
>>> +       case AMDGPU_HW_IP_VCE:
>>> +               return AMDGPU_RING_TYPE_VCE;
>>> +       default:
>>> +               DRM_ERROR("Invalid HW IP specified %d\n", hw_ip);
>>> +               return -1;
>>> +       }
>>> +}
>>> +
>>> +static int amdgpu_lru_map(struct amdgpu_device *adev,
>>> +                         struct amdgpu_queue_mapper *mapper,
>>> +                         int user_ring,
>>> +                         struct amdgpu_ring **out_ring)
>>> +{
>>> +       int r;
>>> +       int ring_type = amdgpu_hw_ip_to_ring_type(mapper->hw_ip);
>>> +
>>> +       r = amdgpu_ring_lru_get(adev, ring_type, out_ring);
>>> +       if (r)
>>> +               return r;
>>> +
>>> +       return update_cached_map(mapper, user_ring, *out_ring);
>>> +}
>>> +
>>>   int amdgpu_queue_mgr_init(struct amdgpu_device *adev,
>>>                           struct amdgpu_queue_mgr *mgr)
>>>   {
>>>         int i;
>>>         if (!adev || !mgr)
>>>                 return -EINVAL;
>>>         memset(mgr, 0, sizeof(*mgr));
>>>   @@ -138,26 +172,28 @@ int amdgpu_queue_mgr_map(struct amdgpu_device
>>> *adev,
>>>         *out_ring = get_cached_map(mapper, ring);
>>>         if (*out_ring) {
>>>                 /* cache hit */
>>>                 r = 0;
>>>                 goto out_unlock;
>>>         }
>>>         switch (mapper->hw_ip) {
>>>         case AMDGPU_HW_IP_GFX:
>>> -       case AMDGPU_HW_IP_COMPUTE:
>>>         case AMDGPU_HW_IP_DMA:
>>>         case AMDGPU_HW_IP_UVD:
>>>         case AMDGPU_HW_IP_VCE:
>>>                 r = amdgpu_identity_map(adev, mapper, ring, out_ring);
>>>                 break;
>>> +       case AMDGPU_HW_IP_COMPUTE:
>>
>>
>> I'm pretty close to say add AMDGPU_HW_IP_DMA to that as well. What do you
>> think?
>
> Well, there are cases where you would want to utilize both upstream
> and downstream bandwidth in parallel which would require the UMD to be
> able to select two different SDMA rings.
>
> Alex
>

If we provide an explicit guarantee that the mappings will be 1:1, then 
we should be able to switch SDMA to lru as well. That would result in 
only two possible mappings:
     - 1->1, 1->2
     - 1->2, 2->1

This way whenever the UMD picks two separate rings they will always get 
separate rings.

I think there might be a corner case right now that we can hit that 
results in a many to one mapping. Let me double check that.

Once we have the 1:1 guarantee, I think there could be some improvements 
to having SDMA on LRU.

Andres

>>
>>
>>> +               r = amdgpu_lru_map(adev, mapper, ring, out_ring);
>>> +               break;
>>>         default:
>>>                 *out_ring = NULL;
>>>                 r = -EINVAL;
>>>                 DRM_ERROR("unknown HW IP type: %d\n", mapper->hw_ip);
>>>         }
>>>     out_unlock:
>>>         mutex_unlock(&mapper->lock);
>>>         return r;
>>>   }
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>> index 43cd539..31c6274 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>>> @@ -173,20 +173,22 @@ void amdgpu_ring_commit(struct amdgpu_ring *ring)
>>>         count = ring->funcs->align_mask + 1 -
>>>                 (ring->wptr & ring->funcs->align_mask);
>>>         count %= ring->funcs->align_mask + 1;
>>>         ring->funcs->insert_nop(ring, count);
>>>         mb();
>>>         amdgpu_ring_set_wptr(ring);
>>>         if (ring->funcs->end_use)
>>>                 ring->funcs->end_use(ring);
>>> +
>>> +       amdgpu_ring_lru_touch(ring->adev, ring);
>>>   }
>>>     /**
>>>    * amdgpu_ring_undo - reset the wptr
>>>    *
>>>    * @ring: amdgpu_ring structure holding ring information
>>>    *
>>>    * Reset the driver's copy of the wptr (all asics).
>>>    */
>>>   void amdgpu_ring_undo(struct amdgpu_ring *ring)
>>> @@ -272,20 +274,22 @@ int amdgpu_ring_init(struct amdgpu_device *adev,
>>> struct amdgpu_ring *ring,
>>>                                             &ring->gpu_addr,
>>>                                             (void **)&ring->ring);
>>>                 if (r) {
>>>                         dev_err(adev->dev, "(%d) ring create failed\n",
>>> r);
>>>                         return r;
>>>                 }
>>>                 memset((void *)ring->ring, 0, ring->ring_size);
>>>         }
>>>         ring->ptr_mask = (ring->ring_size / 4) - 1;
>>>         ring->max_dw = max_dw;
>>> +       INIT_LIST_HEAD(&ring->lru_list);
>>> +       amdgpu_ring_lru_touch(adev, ring);
>>>         if (amdgpu_debugfs_ring_init(adev, ring)) {
>>>                 DRM_ERROR("Failed to register debugfs file for rings
>>> !\n");
>>>         }
>>>         return 0;
>>>   }
>>>     /**
>>>    * amdgpu_ring_fini - tear down the driver ring struct.
>>>    *
>>> @@ -305,20 +309,73 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring)
>>>         amdgpu_bo_free_kernel(&ring->ring_obj,
>>>                               &ring->gpu_addr,
>>>                               (void **)&ring->ring);
>>>         amdgpu_debugfs_ring_fini(ring);
>>>         ring->adev->rings[ring->idx] = NULL;
>>>   }
>>>   +/**
>>> + * amdgpu_ring_lru_get - get the least recently used ring for a HW IP
>>> block
>>> + *
>>> + * @adev: amdgpu_device pointer
>>> + * @type: amdgpu_ring_type enum
>>> + * @ring: output ring
>>> + *
>>> + * Retreive the amdgpu_ring structure for the least recently used ring of
>>> + * a specific IP block (all asics).
>>> + * Returns 0 on success, error on failure.
>>> + */
>>> +int amdgpu_ring_lru_get(struct amdgpu_device *adev, int type,
>>> +                       struct amdgpu_ring **ring)
>>> +{
>>> +       struct amdgpu_ring *entry;
>>> +
>>> +       /* List is sorted in LRU order, find first entry corresponding
>>> +        * to the desired HW IP */
>>> +       *ring = NULL;
>>> +       mutex_lock(&adev->ring_lru_list_lock);
>>> +       list_for_each_entry(entry, &adev->ring_lru_list, lru_list) {
>>> +               if (entry->funcs->type == type) {
>>> +                       *ring = entry;
>>> +                       break;
>>> +               }
>>> +       }
>>> +       mutex_unlock(&adev->ring_lru_list_lock);
>>> +
>>> +       if (!*ring) {
>>> +               DRM_ERROR("Ring LRU contains no entries for ring
>>> type:%d\n", type);
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       amdgpu_ring_lru_touch(adev, entry);
>>
>>
>> That takes the LRU lock twice, but do this only once.
>>
>> Regards,
>> Christian.
>>
>>
>>> +       return 0;
>>> +}
>>> +
>>> +/**
>>> + * amdgpu_ring_lru_touch - mark a ring as recently being used
>>> + *
>>> + * @adev: amdgpu_device pointer
>>> + * @ring: ring to touch
>>> + *
>>> + * Move @ring to the the tail of the lru list
>>> + */
>>> +void amdgpu_ring_lru_touch(struct amdgpu_device *adev, struct amdgpu_ring
>>> *ring)
>>> +{
>>> +       /* list_move_tail handles the case where ring isn't part of the
>>> list */
>>> +       mutex_lock(&adev->ring_lru_list_lock);
>>> +       list_move_tail(&ring->lru_list, &adev->ring_lru_list);
>>> +       mutex_unlock(&adev->ring_lru_list_lock);
>>> +}
>>> +
>>>   /*
>>>    * Debugfs info
>>>    */
>>>   #if defined(CONFIG_DEBUG_FS)
>>>     /* Layout of file is 12 bytes consisting of
>>>    * - rptr
>>>    * - wptr
>>>    * - driver's copy of wptr
>>>    *
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>> index 35da5c5..b51bdcd 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>>> @@ -137,20 +137,21 @@ struct amdgpu_ring_funcs {
>>>         void (*emit_cntxcntl) (struct amdgpu_ring *ring, uint32_t flags);
>>>         void (*emit_rreg)(struct amdgpu_ring *ring, uint32_t reg);
>>>         void (*emit_wreg)(struct amdgpu_ring *ring, uint32_t reg, uint32_t
>>> val);
>>>   };
>>>     struct amdgpu_ring {
>>>         struct amdgpu_device            *adev;
>>>         const struct amdgpu_ring_funcs  *funcs;
>>>         struct amdgpu_fence_driver      fence_drv;
>>>         struct amd_gpu_scheduler        sched;
>>> +       struct list_head                lru_list;
>>>         struct amdgpu_bo        *ring_obj;
>>>         volatile uint32_t       *ring;
>>>         unsigned                rptr_offs;
>>>         unsigned                wptr;
>>>         unsigned                wptr_old;
>>>         unsigned                ring_size;
>>>         unsigned                max_dw;
>>>         int                     count_dw;
>>>         uint64_t                gpu_addr;
>>> @@ -179,12 +180,15 @@ int amdgpu_ring_is_valid_index(struct amdgpu_device
>>> *adev,
>>>                                int hw_ip, int ring);
>>>   int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw);
>>>   void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count);
>>>   void amdgpu_ring_generic_pad_ib(struct amdgpu_ring *ring, struct
>>> amdgpu_ib *ib);
>>>   void amdgpu_ring_commit(struct amdgpu_ring *ring);
>>>   void amdgpu_ring_undo(struct amdgpu_ring *ring);
>>>   int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring
>>> *ring,
>>>                      unsigned ring_size, struct amdgpu_irq_src *irq_src,
>>>                      unsigned irq_type);
>>>   void amdgpu_ring_fini(struct amdgpu_ring *ring);
>>> +int amdgpu_ring_lru_get(struct amdgpu_device *adev, int hw_ip,
>>> +                       struct amdgpu_ring **ring);
>>> +void amdgpu_ring_lru_touch(struct amdgpu_device *adev, struct amdgpu_ring
>>> *ring);
>>>     #endif
>>
>>
>>
>> _______________________________________________
>> amd-gfx mailing list
>> amd-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

  parent reply	other threads:[~2017-03-03 17:15 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-02 21:44 [PATCH] Add support for high priority scheduling in amdgpu v4 Andres Rodriguez
     [not found] ` <20170302214448.4146-1-andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-03-02 21:44   ` [PATCH 01/21] drm/amdgpu: refactor MQD/HQD initialization Andres Rodriguez
     [not found]     ` <20170302214448.4146-2-andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-03-03  8:39       ` Oded Gabbay
2017-03-02 21:44   ` [PATCH 02/21] drm/amdgpu: doorbell registers need only be set once v2 Andres Rodriguez
2017-03-02 21:44   ` [PATCH 03/21] drm/amdgpu: detect timeout error when deactivating hqd Andres Rodriguez
2017-03-02 21:44   ` [PATCH 04/21] drm/amdgpu: remove duplicate definition of cik_mqd Andres Rodriguez
2017-03-02 21:44   ` [PATCH 05/21] drm/amdgpu: unify MQD programming sequence for kfd and amdgpu Andres Rodriguez
2017-03-02 21:44   ` [PATCH 06/21] drm/amdgpu: rename rdev to adev Andres Rodriguez
2017-03-02 21:44   ` [PATCH 07/21] drm/amdgpu: take ownership of per-pipe configuration Andres Rodriguez
2017-03-02 21:44   ` [PATCH 08/21] drm/radeon: take ownership of pipe initialization Andres Rodriguez
2017-03-02 21:44   ` [PATCH 09/21] drm/amdgpu: allow split of queues with kfd at queue granularity Andres Rodriguez
2017-03-02 21:44   ` [PATCH 10/21] drm/amdgpu: teach amdgpu how to enable interrupts for any pipe Andres Rodriguez
2017-03-02 21:44   ` [PATCH 11/21] drm/amdkfd: allow split HQD on per-queue granularity v4 Andres Rodriguez
2017-03-02 21:44   ` [PATCH 12/21] drm/amdgpu: remove duplicate magic constants from amdgpu_amdkfd_gfx*.c Andres Rodriguez
2017-03-02 21:44   ` [PATCH 13/21] drm/amdgpu: allocate queues horizontally across pipes Andres Rodriguez
2017-03-02 21:44   ` [PATCH 14/21] drm/amdgpu: new queue policy, take first 2 queues of each pipe Andres Rodriguez
2017-03-02 21:44   ` [PATCH 15/21] drm/amdgpu: untie user ring ids from kernel ring ids v2 Andres Rodriguez
     [not found]     ` <20170302214448.4146-16-andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-03-03 13:11       ` Christian König
2017-03-02 21:44   ` [PATCH 16/21] drm/amdgpu: implement lru amdgpu_queue_mgr policy for compute v3 Andres Rodriguez
     [not found]     ` <20170302214448.4146-17-andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-03-03 13:23       ` Christian König
     [not found]         ` <6532497e-050d-42f2-808c-f398c4af2dc6-ANTagKRnAhcb1SvskN2V4Q@public.gmane.org>
2017-03-03 15:20           ` Alex Deucher
     [not found]             ` <CADnq5_MH2YunUwH79zTaGA2+UGGDQwHZGjN3WqmHsg8EC4-SvQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-03-03 17:15               ` Andres Rodriguez [this message]
2017-03-03 16:38           ` William Lewis
2017-03-02 21:44   ` [PATCH 17/21] drm/amdgpu: add parameter to allocate high priority contexts v6 Andres Rodriguez
     [not found]     ` <20170302214448.4146-18-andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-03-03 13:25       ` Christian König
2017-03-02 21:44   ` [PATCH 18/21] drm/amdgpu: add framework for HW specific priority settings v3 Andres Rodriguez
     [not found]     ` <20170302214448.4146-19-andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-03-03 13:46       ` Christian König
2017-03-02 21:44   ` [PATCH 19/21] drm/amdgpu: implement ring set_priority for gfx_v8 compute v3 Andres Rodriguez
     [not found]     ` <20170302214448.4146-20-andresx7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-03-03 13:48       ` Christian König
2017-03-02 21:44   ` [PATCH 20/21] drm/amdgpu: condense mqd programming sequence Andres Rodriguez
2017-03-02 21:44   ` [PATCH 21/21] drm/amdgpu: workaround tonga HW bug in HQD " Andres Rodriguez
2017-03-03 13:51   ` [PATCH] Add support for high priority scheduling in amdgpu v4 Christian König
     [not found]     ` <f946ac29-6501-d550-2df0-515e0439bc8c-ANTagKRnAhcb1SvskN2V4Q@public.gmane.org>
2017-03-03 14:52       ` Andres Rodriguez

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=cca32fc8-e57a-aba8-e6d6-7bc692a3813e@gmail.com \
    --to=andresx7-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
    --cc=alexdeucher-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org \
    --cc=deathsimple-ANTagKRnAhcb1SvskN2V4Q@public.gmane.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.