[PATCH 15/21] drm/amdgpu: untie user ring ids from kernel ring ids v3

Andres Rodriguez andresx7 at gmail.com
Tue Mar 7 16:20:01 UTC 2017



On 2017-03-07 05:31 AM, Christian König wrote:
> Am 07.03.2017 um 02:10 schrieb Andres Rodriguez:
>> Add amdgpu_queue_mgr, a mechanism that allows disjointing usermode's
>> ring ids from the kernel's ring ids.
>>
>> The queue manager maintains a per-file descriptor map of user ring ids
>> to amdgpu_ring pointers. Once a map is created it is permanent (this is
>> required to maintain FIFO execution guarantees for a context's ring).
>>
>> Different queue map policies can be configured for each HW IP.
>> Currently all HW IPs use the identity mapper, i.e. kernel ring id is
>> equal to the user ring id.
>>
>> The purpose of this mechanism is to distribute the load across multiple
>> queues more effectively for HW IPs that support multiple rings.
>> Userspace clients are unable to check whether a specific resource is in
>> use by a different client. Therefore, it is up to the kernel driver to
>> make the optimal choice.
>>
>> v2: remove amdgpu_queue_mapper_funcs
>> v3: made amdgpu_queue_mgr per context instead of per-fd
>>
>> Signed-off-by: Andres Rodriguez <andresx7 at gmail.com>
>
> One nit pick and three problems in the error code path below.
>
>> ---
>>   drivers/gpu/drm/amd/amdgpu/Makefile           |   2 +-
>>   drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  27 ++-
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c        |  95 +++--------
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c       |   6 +
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c | 230 
>> ++++++++++++++++++++++++++
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c      |  45 +++++
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h      |   2 +
>>   7 files changed, 328 insertions(+), 79 deletions(-)
>>   create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile 
>> b/drivers/gpu/drm/amd/amdgpu/Makefile
>> index 2814aad..0081d0c 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/Makefile
>> +++ b/drivers/gpu/drm/amd/amdgpu/Makefile
>> @@ -17,21 +17,21 @@ amdgpu-y := amdgpu_drv.o
>>   amdgpu-y += amdgpu_device.o amdgpu_kms.o \
>>       amdgpu_atombios.o atombios_crtc.o amdgpu_connectors.o \
>>       atom.o amdgpu_fence.o amdgpu_ttm.o amdgpu_object.o amdgpu_gart.o \
>>       amdgpu_encoders.o amdgpu_display.o amdgpu_i2c.o \
>>       amdgpu_fb.o amdgpu_gem.o amdgpu_ring.o \
>>       amdgpu_cs.o amdgpu_bios.o amdgpu_benchmark.o amdgpu_test.o \
>>       amdgpu_pm.o atombios_dp.o amdgpu_afmt.o amdgpu_trace_points.o \
>>       atombios_encoders.o amdgpu_sa.o atombios_i2c.o \
>>       amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
>>       amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
>> -    amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o
>> +    amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_queue_mgr.o
>>     # add asic specific block
>>   amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
>>       ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o 
>> vce_v2_0.o \
>>       amdgpu_amdkfd_gfx_v7.o
>>     amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o 
>> si_ih.o si_dma.o dce_v6_0.o si_dpm.o si_smc.o
>>     amdgpu-y += \
>>       vi.o mxgpu_vi.o
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> index 377f58a..734d941 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> @@ -648,32 +648,56 @@ int amdgpu_job_alloc(struct amdgpu_device 
>> *adev, unsigned num_ibs,
>>   int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned 
>> size,
>>                    struct amdgpu_job **job);
>>     void amdgpu_job_free_resources(struct amdgpu_job *job);
>>   void amdgpu_job_free(struct amdgpu_job *job);
>>   int amdgpu_job_submit(struct amdgpu_job *job, struct amdgpu_ring 
>> *ring,
>>                 struct amd_sched_entity *entity, void *owner,
>>                 struct dma_fence **f);
>>     /*
>> + * Queue manager
>> + */
>> +struct amdgpu_queue_mapper {
>> +    int         hw_ip;
>> +    struct mutex    lock;
>> +    /* protected by lock */
>> +    struct amdgpu_ring *queue_map[AMDGPU_MAX_RINGS];
>> +};
>> +
>> +struct amdgpu_queue_mgr {
>> +    struct amdgpu_queue_mapper mapper[AMDGPU_MAX_IP_NUM];
>> +};
>> +
>> +int amdgpu_queue_mgr_init(struct amdgpu_device *adev,
>> +              struct amdgpu_queue_mgr *mgr);
>> +int amdgpu_queue_mgr_fini(struct amdgpu_device *adev,
>> +              struct amdgpu_queue_mgr *mgr);
>> +int amdgpu_queue_mgr_map(struct amdgpu_device *adev,
>> +             struct amdgpu_queue_mgr *mgr,
>> +             int hw_ip, int instance, int ring,
>> +             struct amdgpu_ring **out_ring);
>> +
>> +/*
>
> Not completely mandatory, but would be nice to amdgpu_queue_mgr.h 
> instead of amdgpu.h.
The dependency on AMDGPU_MAX_IP_NUM creates a circular dependency if the 
data structures are declared in a separate header file. And having just 
the function definitions in amdgpu_queue_mgr.h seemed like adding a 
third header style into the mixing pot which I didn't really want to do.

-Andres
>
>>    * context related structures
>>    */
>>     struct amdgpu_ctx_ring {
>>       uint64_t        sequence;
>>       struct dma_fence    **fences;
>>       struct amd_sched_entity    entity;
>>   };
>>     struct amdgpu_ctx {
>>       struct kref        refcount;
>>       struct amdgpu_device    *adev;
>> +    struct amdgpu_queue_mgr queue_mgr;
>>       unsigned        reset_counter;
>>       spinlock_t        ring_lock;
>>       struct dma_fence    **fences;
>>       struct amdgpu_ctx_ring    rings[AMDGPU_MAX_RINGS];
>>       bool preamble_presented;
>>   };
>>     struct amdgpu_ctx_mgr {
>>       struct amdgpu_device    *adev;
>>       struct mutex        lock;
>> @@ -1723,23 +1747,20 @@ static inline bool 
>> amdgpu_is_mec_queue_enabled(struct amdgpu_device *adev,
>>   #define amdgpu_gds_switch(adev, r, v, d, w, a) 
>> (adev)->gds.funcs->patch_gds_switch((r), (v), (d), (w), (a))
>>     /* Common functions */
>>   int amdgpu_gpu_reset(struct amdgpu_device *adev);
>>   bool amdgpu_need_backup(struct amdgpu_device *adev);
>>   void amdgpu_pci_config_reset(struct amdgpu_device *adev);
>>   bool amdgpu_need_post(struct amdgpu_device *adev);
>>   void amdgpu_update_display_priority(struct amdgpu_device *adev);
>>     int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data);
>> -int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
>> -               u32 ip_instance, u32 ring,
>> -               struct amdgpu_ring **out_ring);
>>   void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 
>> num_bytes);
>>   void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 
>> domain);
>>   bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo);
>>   int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page 
>> **pages);
>>   int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
>>                        uint32_t flags);
>>   bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm);
>>   struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm);
>>   bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long 
>> start,
>>                     unsigned long end);
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
>> index 57301f5..67de115 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
>> @@ -23,76 +23,20 @@
>>    *
>>    * Authors:
>>    *    Jerome Glisse <glisse at freedesktop.org>
>>    */
>>   #include <linux/pagemap.h>
>>   #include <drm/drmP.h>
>>   #include <drm/amdgpu_drm.h>
>>   #include "amdgpu.h"
>>   #include "amdgpu_trace.h"
>>   -int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
>> -               u32 ip_instance, u32 ring,
>> -               struct amdgpu_ring **out_ring)
>> -{
>> -    /* Right now all IPs have only one instance - multiple rings. */
>> -    if (ip_instance != 0) {
>> -        DRM_ERROR("invalid ip instance: %d\n", ip_instance);
>> -        return -EINVAL;
>> -    }
>> -
>> -    switch (ip_type) {
>> -    default:
>> -        DRM_ERROR("unknown ip type: %d\n", ip_type);
>> -        return -EINVAL;
>> -    case AMDGPU_HW_IP_GFX:
>> -        if (ring < adev->gfx.num_gfx_rings) {
>> -            *out_ring = &adev->gfx.gfx_ring[ring];
>> -        } else {
>> -            DRM_ERROR("only %d gfx rings are supported now\n",
>> -                  adev->gfx.num_gfx_rings);
>> -            return -EINVAL;
>> -        }
>> -        break;
>> -    case AMDGPU_HW_IP_COMPUTE:
>> -        if (ring < adev->gfx.num_compute_rings) {
>> -            *out_ring = &adev->gfx.compute_ring[ring];
>> -        } else {
>> -            DRM_ERROR("only %d compute rings are supported now\n",
>> -                  adev->gfx.num_compute_rings);
>> -            return -EINVAL;
>> -        }
>> -        break;
>> -    case AMDGPU_HW_IP_DMA:
>> -        if (ring < adev->sdma.num_instances) {
>> -            *out_ring = &adev->sdma.instance[ring].ring;
>> -        } else {
>> -            DRM_ERROR("only %d SDMA rings are supported\n",
>> -                  adev->sdma.num_instances);
>> -            return -EINVAL;
>> -        }
>> -        break;
>> -    case AMDGPU_HW_IP_UVD:
>> -        *out_ring = &adev->uvd.ring;
>> -        break;
>> -    case AMDGPU_HW_IP_VCE:
>> -        if (ring < adev->vce.num_rings){
>> -            *out_ring = &adev->vce.ring[ring];
>> -        } else {
>> -            DRM_ERROR("only %d VCE rings are supported\n", 
>> adev->vce.num_rings);
>> -            return -EINVAL;
>> -        }
>> -        break;
>> -    }
>> -    return 0;
>> -}
>> -
>>   static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
>>                         struct drm_amdgpu_cs_chunk_fence *data,
>>                         uint32_t *offset)
>>   {
>>       struct drm_gem_object *gobj;
>>       unsigned long size;
>>         gobj = drm_gem_object_lookup(p->filp, data->handle);
>>       if (gobj == NULL)
>>           return -EINVAL;
>> @@ -868,23 +812,22 @@ static int amdgpu_cs_ib_fill(struct 
>> amdgpu_device *adev,
>>           struct drm_amdgpu_cs_chunk_ib *chunk_ib;
>>           struct amdgpu_ring *ring;
>>             chunk = &parser->chunks[i];
>>           ib = &parser->job->ibs[j];
>>           chunk_ib = (struct drm_amdgpu_cs_chunk_ib *)chunk->kdata;
>>             if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB)
>>               continue;
>>   -        r = amdgpu_cs_get_ring(adev, chunk_ib->ip_type,
>> -                       chunk_ib->ip_instance, chunk_ib->ring,
>> -                       &ring);
>> +        r = amdgpu_queue_mgr_map(adev, &parser->ctx->queue_mgr, 
>> chunk_ib->ip_type,
>> +                     chunk_ib->ip_instance, chunk_ib->ring, &ring);
>>           if (r)
>>               return r;
>>             if (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) {
>>               parser->job->preamble_status |= 
>> AMDGPU_PREAMBLE_IB_PRESENT;
>>               if (!parser->ctx->preamble_presented) {
>>                   parser->job->preamble_status |= 
>> AMDGPU_PREAMBLE_IB_PRESENT_FIRST;
>>                   parser->ctx->preamble_presented = true;
>>               }
>>           }
>> @@ -972,30 +915,31 @@ static int amdgpu_cs_dependencies(struct 
>> amdgpu_device *adev,
>>             deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata;
>>           num_deps = chunk->length_dw * 4 /
>>               sizeof(struct drm_amdgpu_cs_chunk_dep);
>>             for (j = 0; j < num_deps; ++j) {
>>               struct amdgpu_ring *ring;
>>               struct amdgpu_ctx *ctx;
>>               struct dma_fence *fence;
>>   -            r = amdgpu_cs_get_ring(adev, deps[j].ip_type,
>> -                           deps[j].ip_instance,
>> -                           deps[j].ring, &ring);
>> -            if (r)
>> -                return r;
>> -
>>               ctx = amdgpu_ctx_get(fpriv, deps[j].ctx_id);
>>               if (ctx == NULL)
>>                   return -EINVAL;
>>   +            r = amdgpu_queue_mgr_map(adev, &ctx->queue_mgr,
>> +                         deps[j].ip_type,
>> +                         deps[j].ip_instance,
>> +                         deps[j].ring, &ring);
>> +            if (r)
>> +                return r;
>> +
>
> You need to call amdgpu_ctx_put() in the error path here. Otherwise we 
> won't unlock the ctx any more if that fails.
>
>>               fence = amdgpu_ctx_get_fence(ctx, ring,
>>                                deps[j].handle);
>>               if (IS_ERR(fence)) {
>>                   r = PTR_ERR(fence);
>>                   amdgpu_ctx_put(ctx);
>>                   return r;
>>                 } else if (fence) {
>>                   r = amdgpu_sync_fence(adev, &p->job->sync,
>>                                 fence);
>> @@ -1107,29 +1051,30 @@ int amdgpu_cs_wait_ioctl(struct drm_device 
>> *dev, void *data,
>>                struct drm_file *filp)
>>   {
>>       union drm_amdgpu_wait_cs *wait = data;
>>       struct amdgpu_device *adev = dev->dev_private;
>>       unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout);
>>       struct amdgpu_ring *ring = NULL;
>>       struct amdgpu_ctx *ctx;
>>       struct dma_fence *fence;
>>       long r;
>>   -    r = amdgpu_cs_get_ring(adev, wait->in.ip_type, 
>> wait->in.ip_instance,
>> -                   wait->in.ring, &ring);
>> -    if (r)
>> -        return r;
>> -
>>       ctx = amdgpu_ctx_get(filp->driver_priv, wait->in.ctx_id);
>>       if (ctx == NULL)
>>           return -EINVAL;
>>   +    r = amdgpu_queue_mgr_map(adev, &ctx->queue_mgr,
>> +                 wait->in.ip_type, wait->in.ip_instance,
>> +                 wait->in.ring, &ring);
>> +    if (r)
>> +        return r;
>> +
>
> Dito.
>
>>       fence = amdgpu_ctx_get_fence(ctx, ring, wait->in.handle);
>>       if (IS_ERR(fence))
>>           r = PTR_ERR(fence);
>>       else if (fence) {
>>           r = dma_fence_wait_timeout(fence, true, timeout);
>>           dma_fence_put(fence);
>>       } else
>>           r = 1;
>>         amdgpu_ctx_put(ctx);
>> @@ -1151,29 +1096,29 @@ int amdgpu_cs_wait_ioctl(struct drm_device 
>> *dev, void *data,
>>    */
>>   static struct dma_fence *amdgpu_cs_get_fence(struct amdgpu_device 
>> *adev,
>>                            struct drm_file *filp,
>>                            struct drm_amdgpu_fence *user)
>>   {
>>       struct amdgpu_ring *ring;
>>       struct amdgpu_ctx *ctx;
>>       struct dma_fence *fence;
>>       int r;
>>   -    r = amdgpu_cs_get_ring(adev, user->ip_type, user->ip_instance,
>> -                   user->ring, &ring);
>> -    if (r)
>> -        return ERR_PTR(r);
>> -
>>       ctx = amdgpu_ctx_get(filp->driver_priv, user->ctx_id);
>>       if (ctx == NULL)
>>           return ERR_PTR(-EINVAL);
>>   +    r = amdgpu_queue_mgr_map(adev, &ctx->queue_mgr, user->ip_type,
>> +                 user->ip_instance, user->ring, &ring);
>> +    if (r)
>> +        return ERR_PTR(r);
>> +
>
> And once more here.
>
> With those fixed the patch is Reviewed-by: Christian König 
> <christian.koenig at amd.com>.
>
> Regards,
> Christian.
>
>>       fence = amdgpu_ctx_get_fence(ctx, ring, user->seq_no);
>>       amdgpu_ctx_put(ctx);
>>         return fence;
>>   }
>>     /**
>>    * amdgpu_cs_wait_all_fence - wait on all fences to signal
>>    *
>>    * @adev: amdgpu device
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
>> index 400c66b..3ddc8db 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
>> @@ -51,20 +51,24 @@ static int amdgpu_ctx_init(struct amdgpu_device 
>> *adev, struct amdgpu_ctx *ctx)
>>           struct amdgpu_ring *ring = adev->rings[i];
>>           struct amd_sched_rq *rq;
>>             rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_NORMAL];
>>           r = amd_sched_entity_init(&ring->sched, &ctx->rings[i].entity,
>>                         rq, amdgpu_sched_jobs);
>>           if (r)
>>               goto failed;
>>       }
>>   +    r = amdgpu_queue_mgr_init(adev, &ctx->queue_mgr);
>> +    if (r)
>> +        goto failed;
>> +
>>       return 0;
>>     failed:
>>       for (j = 0; j < i; j++)
>> amd_sched_entity_fini(&adev->rings[j]->sched,
>>                         &ctx->rings[j].entity);
>>       kfree(ctx->fences);
>>       ctx->fences = NULL;
>>       return r;
>>   }
>> @@ -79,20 +83,22 @@ static void amdgpu_ctx_fini(struct amdgpu_ctx *ctx)
>>         for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
>>           for (j = 0; j < amdgpu_sched_jobs; ++j)
>>               dma_fence_put(ctx->rings[i].fences[j]);
>>       kfree(ctx->fences);
>>       ctx->fences = NULL;
>>         for (i = 0; i < adev->num_rings; i++)
>> amd_sched_entity_fini(&adev->rings[i]->sched,
>>                         &ctx->rings[i].entity);
>> +
>> +    amdgpu_queue_mgr_fini(adev, &ctx->queue_mgr);
>>   }
>>     static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
>>                   struct amdgpu_fpriv *fpriv,
>>                   uint32_t *id)
>>   {
>>       struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
>>       struct amdgpu_ctx *ctx;
>>       int r;
>>   diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c
>> new file mode 100644
>> index 0000000..3e9ac80
>> --- /dev/null
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c
>> @@ -0,0 +1,230 @@
>> +/*
>> + * Copyright 2017 Valve Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person 
>> obtaining a
>> + * copy of this software and associated documentation files (the 
>> "Software"),
>> + * to deal in the Software without restriction, including without 
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom 
>> the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be 
>> included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO 
>> EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, 
>> DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
>> OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
>> USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + * Authors: Andres Rodriguez
>> + */
>> +
>> +#include "amdgpu.h"
>> +#include "amdgpu_ring.h"
>> +
>> +static int amdgpu_queue_mapper_init(struct amdgpu_queue_mapper *mapper,
>> +                    int hw_ip)
>> +{
>> +    if (!mapper)
>> +        return -EINVAL;
>> +
>> +    if (hw_ip > AMDGPU_MAX_IP_NUM)
>> +        return -EINVAL;
>> +
>> +    mapper->hw_ip = hw_ip;
>> +    mutex_init(&mapper->lock);
>> +
>> +    memset(mapper->queue_map, 0, sizeof(mapper->queue_map));
>> +
>> +    return 0;
>> +}
>> +
>> +static struct amdgpu_ring *amdgpu_get_cached_map(struct 
>> amdgpu_queue_mapper *mapper,
>> +                      int ring)
>> +{
>> +    return mapper->queue_map[ring];
>> +}
>> +
>> +static int amdgpu_update_cached_map(struct amdgpu_queue_mapper *mapper,
>> +                 int ring, struct amdgpu_ring *pring)
>> +{
>> +    if (WARN_ON(mapper->queue_map[ring])) {
>> +        DRM_ERROR("Un-expected ring re-map\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    mapper->queue_map[ring] = pring;
>> +
>> +    return 0;
>> +}
>> +
>> +static int amdgpu_identity_map(struct amdgpu_device *adev,
>> +                   struct amdgpu_queue_mapper *mapper,
>> +                   int ring,
>> +                   struct amdgpu_ring **out_ring)
>> +{
>> +    switch (mapper->hw_ip) {
>> +    case AMDGPU_HW_IP_GFX:
>> +        *out_ring = &adev->gfx.gfx_ring[ring];
>> +        break;
>> +    case AMDGPU_HW_IP_COMPUTE:
>> +        *out_ring = &adev->gfx.compute_ring[ring];
>> +        break;
>> +    case AMDGPU_HW_IP_DMA:
>> +        *out_ring = &adev->sdma.instance[ring].ring;
>> +        break;
>> +    case AMDGPU_HW_IP_UVD:
>> +        *out_ring = &adev->uvd.ring;
>> +        break;
>> +    case AMDGPU_HW_IP_VCE:
>> +        *out_ring = &adev->vce.ring[ring];
>> +        break;
>> +    default:
>> +        *out_ring = NULL;
>> +        DRM_ERROR("unknown HW IP type: %d\n", mapper->hw_ip);
>> +        return -EINVAL;
>> +    }
>> +
>> +    return amdgpu_update_cached_map(mapper, ring, *out_ring);
>> +}
>> +
>> +/**
>> + * amdgpu_queue_mgr_init - init an amdgpu_queue_mgr struct
>> + *
>> + * @adev: amdgpu_device pointer
>> + * @mgr: amdgpu_queue_mgr structure holding queue information
>> + *
>> + * Initialize the the selected @mgr (all asics).
>> + *
>> + * Returns 0 on success, error on failure.
>> + */
>> +int amdgpu_queue_mgr_init(struct amdgpu_device *adev,
>> +              struct amdgpu_queue_mgr *mgr)
>> +{
>> +    int i, r;
>> +
>> +    if (!adev || !mgr)
>> +        return -EINVAL;
>> +
>> +    memset(mgr, 0, sizeof(*mgr));
>> +
>> +    for (i = 0; i < AMDGPU_MAX_IP_NUM; ++i) {
>> +        r = amdgpu_queue_mapper_init(&mgr->mapper[i], i);
>> +        if (r)
>> +            return r;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>> + * amdgpu_queue_mgr_fini - de-initialize an amdgpu_queue_mgr struct
>> + *
>> + * @adev: amdgpu_device pointer
>> + * @mgr: amdgpu_queue_mgr structure holding queue information
>> + *
>> + * De-initialize the the selected @mgr (all asics).
>> + *
>> + * Returns 0 on success, error on failure.
>> + */
>> +int amdgpu_queue_mgr_fini(struct amdgpu_device *adev,
>> +              struct amdgpu_queue_mgr *mgr)
>> +{
>> +    return 0;
>> +}
>> +
>> +/**
>> + * amdgpu_queue_mgr_map - Map a userspace ring id to an amdgpu_ring
>> + *
>> + * @adev: amdgpu_device pointer
>> + * @mgr: amdgpu_queue_mgr structure holding queue information
>> + * @hw_ip: HW IP enum
>> + * @instance: HW instance
>> + * @ring: user ring id
>> + * @our_ring: pointer to mapped amdgpu_ring
>> + *
>> + * Map a userspace ring id to an appropriate kernel ring. Different
>> + * policies are configurable at a HW IP level.
>> + *
>> + * Returns 0 on success, error on failure.
>> + */
>> +int amdgpu_queue_mgr_map(struct amdgpu_device *adev,
>> +             struct amdgpu_queue_mgr *mgr,
>> +             int hw_ip, int instance, int ring,
>> +             struct amdgpu_ring **out_ring)
>> +{
>> +    int r, ip_num_rings;
>> +    struct amdgpu_queue_mapper *mapper = &mgr->mapper[hw_ip];
>> +
>> +    if (!adev || !mgr || !out_ring)
>> +        return -EINVAL;
>> +
>> +    if (hw_ip >= AMDGPU_MAX_IP_NUM)
>> +        return -EINVAL;
>> +
>> +    if (ring >= AMDGPU_MAX_RINGS)
>> +        return -EINVAL;
>> +
>> +    /* Right now all IPs have only one instance - multiple rings. */
>> +    if (instance != 0) {
>> +        DRM_ERROR("invalid ip instance: %d\n", instance);
>> +        return -EINVAL;
>> +    }
>> +
>> +    switch (hw_ip) {
>> +    case AMDGPU_HW_IP_GFX:
>> +        ip_num_rings = adev->gfx.num_gfx_rings;
>> +        break;
>> +    case AMDGPU_HW_IP_COMPUTE:
>> +        ip_num_rings = adev->gfx.num_compute_rings;
>> +        break;
>> +    case AMDGPU_HW_IP_DMA:
>> +        ip_num_rings = adev->sdma.num_instances;
>> +        break;
>> +    case AMDGPU_HW_IP_UVD:
>> +        ip_num_rings = 1;
>> +        break;
>> +    case AMDGPU_HW_IP_VCE:
>> +        ip_num_rings = adev->vce.num_rings;
>> +        break;
>> +    default:
>> +        DRM_ERROR("unknown ip type: %d\n", hw_ip);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (ring >= ip_num_rings) {
>> +        DRM_ERROR("Ring index:%d exceeds maximum:%d for ip:%d\n",
>> +                ring, ip_num_rings, hw_ip);
>> +        return -EINVAL;
>> +    }
>> +
>> +    mutex_lock(&mapper->lock);
>> +
>> +    *out_ring = amdgpu_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;
>> +    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 7c842b7..43cd539 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
>> @@ -45,20 +45,65 @@
>>    * pointers are equal, the ring is idle.  When the host
>>    * writes commands to the ring buffer, it increments the
>>    * wptr.  The GPU then starts fetching commands and executes
>>    * them until the pointers are equal again.
>>    */
>>   static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
>>                       struct amdgpu_ring *ring);
>>   static void amdgpu_debugfs_ring_fini(struct amdgpu_ring *ring);
>>     /**
>> + * amdgpu_ring_is_valid_index - check if a ring idex is valid for a 
>> HW IP
>> + *
>> + * @adev: amdgpu_device pointer
>> + * @ip_type: The HW IP to check against
>> + * @ring: the ring index
>> + *
>> + * Check if @ring is a valid index for @ip_type (all asics).
>> + * Returns 0 on success, error on failure.
>> + */
>> +int amdgpu_ring_is_valid_index(struct amdgpu_device *adev,
>> +                   int ip_type, int ring)
>> +{
>> +    int ip_num_rings;
>> +
>> +    switch (ip_type) {
>> +    case AMDGPU_HW_IP_GFX:
>> +        ip_num_rings = adev->gfx.num_gfx_rings;
>> +        break;
>> +    case AMDGPU_HW_IP_COMPUTE:
>> +        ip_num_rings = adev->gfx.num_compute_rings;
>> +        break;
>> +    case AMDGPU_HW_IP_DMA:
>> +        ip_num_rings = adev->sdma.num_instances;
>> +        break;
>> +    case AMDGPU_HW_IP_UVD:
>> +        ip_num_rings = 1;
>> +        break;
>> +    case AMDGPU_HW_IP_VCE:
>> +        ip_num_rings = adev->vce.num_rings;
>> +        break;
>> +    default:
>> +        DRM_ERROR("unknown ip type: %d\n", ip_type);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (ring >= ip_num_rings) {
>> +        DRM_ERROR("Ring index:%d exceeds maximum:%d for ip:%d\n",
>> +                ring, ip_num_rings, ip_type);
>> +        return -EINVAL;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>>    * amdgpu_ring_alloc - allocate space on the ring buffer
>>    *
>>    * @adev: amdgpu_device pointer
>>    * @ring: amdgpu_ring structure holding ring information
>>    * @ndw: number of dwords to allocate in the ring buffer
>>    *
>>    * Allocate @ndw dwords in the ring buffer (all asics).
>>    * Returns 0 on success, error on failure.
>>    */
>>   int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw)
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h 
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>> index 2345b398..35da5c5 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
>> @@ -168,20 +168,22 @@ struct amdgpu_ring {
>>       uint64_t        current_ctx;
>>       char            name[16];
>>       unsigned        cond_exe_offs;
>>       u64            cond_exe_gpu_addr;
>>       volatile u32        *cond_exe_cpu_addr;
>>   #if defined(CONFIG_DEBUG_FS)
>>       struct dentry *ent;
>>   #endif
>>   };
>>   +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);
>
>



More information about the amd-gfx mailing list