linux/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
<<
>>
Prefs
   1/*
   2 * Copyright 2015 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: monk liu <monk.liu@amd.com>
  23 */
  24
  25#include <drm/drmP.h>
  26#include "amdgpu.h"
  27
  28static void amdgpu_ctx_do_release(struct kref *ref)
  29{
  30        struct amdgpu_ctx *ctx;
  31        struct amdgpu_ctx_mgr *mgr;
  32
  33        ctx = container_of(ref, struct amdgpu_ctx, refcount);
  34        mgr = &ctx->fpriv->ctx_mgr;
  35
  36        idr_remove(&mgr->ctx_handles, ctx->id);
  37        kfree(ctx);
  38}
  39
  40int amdgpu_ctx_alloc(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t *id, uint32_t flags)
  41{
  42        int r;
  43        struct amdgpu_ctx *ctx;
  44        struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
  45
  46        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
  47        if (!ctx)
  48                return -ENOMEM;
  49
  50        mutex_lock(&mgr->lock);
  51        r = idr_alloc(&mgr->ctx_handles, ctx, 0, 0, GFP_KERNEL);
  52        if (r < 0) {
  53                mutex_unlock(&mgr->lock);
  54                kfree(ctx);
  55                return r;
  56        }
  57        *id = (uint32_t)r;
  58
  59        memset(ctx, 0, sizeof(*ctx));
  60        ctx->id = *id;
  61        ctx->fpriv = fpriv;
  62        kref_init(&ctx->refcount);
  63        mutex_unlock(&mgr->lock);
  64
  65        return 0;
  66}
  67
  68int amdgpu_ctx_free(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t id)
  69{
  70        struct amdgpu_ctx *ctx;
  71        struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
  72
  73        mutex_lock(&mgr->lock);
  74        ctx = idr_find(&mgr->ctx_handles, id);
  75        if (ctx) {
  76                kref_put(&ctx->refcount, amdgpu_ctx_do_release);
  77                mutex_unlock(&mgr->lock);
  78                return 0;
  79        }
  80        mutex_unlock(&mgr->lock);
  81        return -EINVAL;
  82}
  83
  84static int amdgpu_ctx_query(struct amdgpu_device *adev,
  85                            struct amdgpu_fpriv *fpriv, uint32_t id,
  86                            union drm_amdgpu_ctx_out *out)
  87{
  88        struct amdgpu_ctx *ctx;
  89        struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
  90        unsigned reset_counter;
  91
  92        mutex_lock(&mgr->lock);
  93        ctx = idr_find(&mgr->ctx_handles, id);
  94        if (!ctx) {
  95                mutex_unlock(&mgr->lock);
  96                return -EINVAL;
  97        }
  98
  99        /* TODO: these two are always zero */
 100        out->state.flags = ctx->state.flags;
 101        out->state.hangs = ctx->state.hangs;
 102
 103        /* determine if a GPU reset has occured since the last call */
 104        reset_counter = atomic_read(&adev->gpu_reset_counter);
 105        /* TODO: this should ideally return NO, GUILTY, or INNOCENT. */
 106        if (ctx->reset_counter == reset_counter)
 107                out->state.reset_status = AMDGPU_CTX_NO_RESET;
 108        else
 109                out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET;
 110        ctx->reset_counter = reset_counter;
 111
 112        mutex_unlock(&mgr->lock);
 113        return 0;
 114}
 115
 116void amdgpu_ctx_fini(struct amdgpu_fpriv *fpriv)
 117{
 118        struct idr *idp;
 119        struct amdgpu_ctx *ctx;
 120        uint32_t id;
 121        struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
 122        idp = &mgr->ctx_handles;
 123
 124        idr_for_each_entry(idp,ctx,id) {
 125                if (kref_put(&ctx->refcount, amdgpu_ctx_do_release) != 1)
 126                        DRM_ERROR("ctx (id=%ul) is still alive\n",ctx->id);
 127        }
 128
 129        mutex_destroy(&mgr->lock);
 130}
 131
 132int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
 133                     struct drm_file *filp)
 134{
 135        int r;
 136        uint32_t id;
 137        uint32_t flags;
 138
 139        union drm_amdgpu_ctx *args = data;
 140        struct amdgpu_device *adev = dev->dev_private;
 141        struct amdgpu_fpriv *fpriv = filp->driver_priv;
 142
 143        r = 0;
 144        id = args->in.ctx_id;
 145        flags = args->in.flags;
 146
 147        switch (args->in.op) {
 148                case AMDGPU_CTX_OP_ALLOC_CTX:
 149                        r = amdgpu_ctx_alloc(adev, fpriv, &id, flags);
 150                        args->out.alloc.ctx_id = id;
 151                        break;
 152                case AMDGPU_CTX_OP_FREE_CTX:
 153                        r = amdgpu_ctx_free(adev, fpriv, id);
 154                        break;
 155                case AMDGPU_CTX_OP_QUERY_STATE:
 156                        r = amdgpu_ctx_query(adev, fpriv, id, &args->out);
 157                        break;
 158                default:
 159                        return -EINVAL;
 160        }
 161
 162        return r;
 163}
 164
 165struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
 166{
 167        struct amdgpu_ctx *ctx;
 168        struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
 169
 170        mutex_lock(&mgr->lock);
 171        ctx = idr_find(&mgr->ctx_handles, id);
 172        if (ctx)
 173                kref_get(&ctx->refcount);
 174        mutex_unlock(&mgr->lock);
 175        return ctx;
 176}
 177
 178int amdgpu_ctx_put(struct amdgpu_ctx *ctx)
 179{
 180        struct amdgpu_fpriv *fpriv;
 181        struct amdgpu_ctx_mgr *mgr;
 182
 183        if (ctx == NULL)
 184                return -EINVAL;
 185
 186        fpriv = ctx->fpriv;
 187        mgr = &fpriv->ctx_mgr;
 188        mutex_lock(&mgr->lock);
 189        kref_put(&ctx->refcount, amdgpu_ctx_do_release);
 190        mutex_unlock(&mgr->lock);
 191
 192        return 0;
 193}
 194