1f7de1545SJordan Crouse /* Copyright (c) 2017 The Linux Foundation. All rights reserved. 2f7de1545SJordan Crouse * 3f7de1545SJordan Crouse * This program is free software; you can redistribute it and/or modify 4f7de1545SJordan Crouse * it under the terms of the GNU General Public License version 2 and 5f7de1545SJordan Crouse * only version 2 as published by the Free Software Foundation. 6f7de1545SJordan Crouse * 7f7de1545SJordan Crouse * This program is distributed in the hope that it will be useful, 8f7de1545SJordan Crouse * but WITHOUT ANY WARRANTY; without even the implied warranty of 9f7de1545SJordan Crouse * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10f7de1545SJordan Crouse * GNU General Public License for more details. 11f7de1545SJordan Crouse * 12f7de1545SJordan Crouse */ 13f7de1545SJordan Crouse 14f7de1545SJordan Crouse #include <linux/kref.h> 15f7de1545SJordan Crouse #include "msm_gpu.h" 16f7de1545SJordan Crouse 17f7de1545SJordan Crouse void msm_submitqueue_destroy(struct kref *kref) 18f7de1545SJordan Crouse { 19f7de1545SJordan Crouse struct msm_gpu_submitqueue *queue = container_of(kref, 20f7de1545SJordan Crouse struct msm_gpu_submitqueue, ref); 21f7de1545SJordan Crouse 22f7de1545SJordan Crouse kfree(queue); 23f7de1545SJordan Crouse } 24f7de1545SJordan Crouse 25f7de1545SJordan Crouse struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_file_private *ctx, 26f7de1545SJordan Crouse u32 id) 27f7de1545SJordan Crouse { 28f7de1545SJordan Crouse struct msm_gpu_submitqueue *entry; 29f7de1545SJordan Crouse 30f7de1545SJordan Crouse if (!ctx) 31f7de1545SJordan Crouse return NULL; 32f7de1545SJordan Crouse 33f7de1545SJordan Crouse read_lock(&ctx->queuelock); 34f7de1545SJordan Crouse 35f7de1545SJordan Crouse list_for_each_entry(entry, &ctx->submitqueues, node) { 36f7de1545SJordan Crouse if (entry->id == id) { 37f7de1545SJordan Crouse kref_get(&entry->ref); 38f7de1545SJordan Crouse read_unlock(&ctx->queuelock); 39f7de1545SJordan Crouse 40f7de1545SJordan Crouse return entry; 41f7de1545SJordan Crouse } 42f7de1545SJordan Crouse } 43f7de1545SJordan Crouse 44f7de1545SJordan Crouse read_unlock(&ctx->queuelock); 45f7de1545SJordan Crouse return NULL; 46f7de1545SJordan Crouse } 47f7de1545SJordan Crouse 48f7de1545SJordan Crouse void msm_submitqueue_close(struct msm_file_private *ctx) 49f7de1545SJordan Crouse { 50f7de1545SJordan Crouse struct msm_gpu_submitqueue *entry, *tmp; 51f7de1545SJordan Crouse 52f7de1545SJordan Crouse if (!ctx) 53f7de1545SJordan Crouse return; 54f7de1545SJordan Crouse 55f7de1545SJordan Crouse /* 56f7de1545SJordan Crouse * No lock needed in close and there won't 57f7de1545SJordan Crouse * be any more user ioctls coming our way 58f7de1545SJordan Crouse */ 59f7de1545SJordan Crouse list_for_each_entry_safe(entry, tmp, &ctx->submitqueues, node) 60f7de1545SJordan Crouse msm_submitqueue_put(entry); 61f7de1545SJordan Crouse } 62f7de1545SJordan Crouse 63f97decacSJordan Crouse int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx, 64f97decacSJordan Crouse u32 prio, u32 flags, u32 *id) 65f7de1545SJordan Crouse { 66f97decacSJordan Crouse struct msm_drm_private *priv = drm->dev_private; 67f7de1545SJordan Crouse struct msm_gpu_submitqueue *queue; 68f7de1545SJordan Crouse 69f7de1545SJordan Crouse if (!ctx) 70f7de1545SJordan Crouse return -ENODEV; 71f7de1545SJordan Crouse 72f7de1545SJordan Crouse queue = kzalloc(sizeof(*queue), GFP_KERNEL); 73f7de1545SJordan Crouse 74f7de1545SJordan Crouse if (!queue) 75f7de1545SJordan Crouse return -ENOMEM; 76f7de1545SJordan Crouse 77f7de1545SJordan Crouse kref_init(&queue->ref); 78f7de1545SJordan Crouse queue->flags = flags; 79f97decacSJordan Crouse 80f97decacSJordan Crouse if (priv->gpu) { 81f97decacSJordan Crouse if (prio >= priv->gpu->nr_rings) 82f97decacSJordan Crouse return -EINVAL; 83f97decacSJordan Crouse 84f7de1545SJordan Crouse queue->prio = prio; 85f97decacSJordan Crouse } 86f7de1545SJordan Crouse 87f7de1545SJordan Crouse write_lock(&ctx->queuelock); 88f7de1545SJordan Crouse 89f7de1545SJordan Crouse queue->id = ctx->queueid++; 90f7de1545SJordan Crouse 91f7de1545SJordan Crouse if (id) 92f7de1545SJordan Crouse *id = queue->id; 93f7de1545SJordan Crouse 94f7de1545SJordan Crouse list_add_tail(&queue->node, &ctx->submitqueues); 95f7de1545SJordan Crouse 96f7de1545SJordan Crouse write_unlock(&ctx->queuelock); 97f7de1545SJordan Crouse 98f7de1545SJordan Crouse return 0; 99f7de1545SJordan Crouse } 100f7de1545SJordan Crouse 101f97decacSJordan Crouse int msm_submitqueue_init(struct drm_device *drm, struct msm_file_private *ctx) 102f7de1545SJordan Crouse { 103f97decacSJordan Crouse struct msm_drm_private *priv = drm->dev_private; 104f97decacSJordan Crouse int default_prio; 105f97decacSJordan Crouse 106f7de1545SJordan Crouse if (!ctx) 107f7de1545SJordan Crouse return 0; 108f7de1545SJordan Crouse 109f97decacSJordan Crouse /* 110f97decacSJordan Crouse * Select priority 2 as the "default priority" unless nr_rings is less 111f97decacSJordan Crouse * than 2 and then pick the lowest pirority 112f97decacSJordan Crouse */ 113f97decacSJordan Crouse default_prio = priv->gpu ? 114f97decacSJordan Crouse clamp_t(uint32_t, 2, 0, priv->gpu->nr_rings - 1) : 0; 115f97decacSJordan Crouse 116f7de1545SJordan Crouse INIT_LIST_HEAD(&ctx->submitqueues); 117f7de1545SJordan Crouse 118f7de1545SJordan Crouse rwlock_init(&ctx->queuelock); 119f7de1545SJordan Crouse 120f97decacSJordan Crouse return msm_submitqueue_create(drm, ctx, default_prio, 0, NULL); 121f7de1545SJordan Crouse } 122f7de1545SJordan Crouse 123f7de1545SJordan Crouse int msm_submitqueue_remove(struct msm_file_private *ctx, u32 id) 124f7de1545SJordan Crouse { 125f7de1545SJordan Crouse struct msm_gpu_submitqueue *entry; 126f7de1545SJordan Crouse 127f7de1545SJordan Crouse if (!ctx) 128f7de1545SJordan Crouse return 0; 129f7de1545SJordan Crouse 130f7de1545SJordan Crouse /* 131f7de1545SJordan Crouse * id 0 is the "default" queue and can't be destroyed 132f7de1545SJordan Crouse * by the user 133f7de1545SJordan Crouse */ 134f7de1545SJordan Crouse if (!id) 135f7de1545SJordan Crouse return -ENOENT; 136f7de1545SJordan Crouse 137f7de1545SJordan Crouse write_lock(&ctx->queuelock); 138f7de1545SJordan Crouse 139f7de1545SJordan Crouse list_for_each_entry(entry, &ctx->submitqueues, node) { 140f7de1545SJordan Crouse if (entry->id == id) { 141f7de1545SJordan Crouse list_del(&entry->node); 142f7de1545SJordan Crouse write_unlock(&ctx->queuelock); 143f7de1545SJordan Crouse 144f7de1545SJordan Crouse msm_submitqueue_put(entry); 145f7de1545SJordan Crouse return 0; 146f7de1545SJordan Crouse } 147f7de1545SJordan Crouse } 148f7de1545SJordan Crouse 149f7de1545SJordan Crouse write_unlock(&ctx->queuelock); 150f7de1545SJordan Crouse return -ENOENT; 151f7de1545SJordan Crouse } 152f7de1545SJordan Crouse 153