linux/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
<<
>>
Prefs
   1/*
   2 * Copyright 2014 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 */
  23
  24#include <linux/slab.h>
  25#include <linux/list.h>
  26#include "kfd_device_queue_manager.h"
  27#include "kfd_priv.h"
  28#include "kfd_kernel_queue.h"
  29
  30static inline struct process_queue_node *get_queue_by_qid(
  31                        struct process_queue_manager *pqm, unsigned int qid)
  32{
  33        struct process_queue_node *pqn;
  34
  35        list_for_each_entry(pqn, &pqm->queues, process_queue_list) {
  36                if ((pqn->q && pqn->q->properties.queue_id == qid) ||
  37                    (pqn->kq && pqn->kq->queue->properties.queue_id == qid))
  38                        return pqn;
  39        }
  40
  41        return NULL;
  42}
  43
  44static int find_available_queue_slot(struct process_queue_manager *pqm,
  45                                        unsigned int *qid)
  46{
  47        unsigned long found;
  48
  49        found = find_first_zero_bit(pqm->queue_slot_bitmap,
  50                        KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
  51
  52        pr_debug("The new slot id %lu\n", found);
  53
  54        if (found >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) {
  55                pr_info("Cannot open more queues for process with pasid %d\n",
  56                                pqm->process->pasid);
  57                return -ENOMEM;
  58        }
  59
  60        set_bit(found, pqm->queue_slot_bitmap);
  61        *qid = found;
  62
  63        return 0;
  64}
  65
  66int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p)
  67{
  68        INIT_LIST_HEAD(&pqm->queues);
  69        pqm->queue_slot_bitmap =
  70                        kzalloc(DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
  71                                        BITS_PER_BYTE), GFP_KERNEL);
  72        if (!pqm->queue_slot_bitmap)
  73                return -ENOMEM;
  74        pqm->process = p;
  75
  76        return 0;
  77}
  78
  79void pqm_uninit(struct process_queue_manager *pqm)
  80{
  81        int retval;
  82        struct process_queue_node *pqn, *next;
  83
  84        list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) {
  85                retval = pqm_destroy_queue(
  86                                pqm,
  87                                (pqn->q != NULL) ?
  88                                        pqn->q->properties.queue_id :
  89                                        pqn->kq->queue->properties.queue_id);
  90
  91                if (retval != 0) {
  92                        pr_err("failed to destroy queue\n");
  93                        return;
  94                }
  95        }
  96        kfree(pqm->queue_slot_bitmap);
  97        pqm->queue_slot_bitmap = NULL;
  98}
  99
 100static int create_cp_queue(struct process_queue_manager *pqm,
 101                                struct kfd_dev *dev, struct queue **q,
 102                                struct queue_properties *q_properties,
 103                                struct file *f, unsigned int qid)
 104{
 105        int retval;
 106
 107        /* Doorbell initialized in user space*/
 108        q_properties->doorbell_ptr = NULL;
 109
 110        q_properties->doorbell_off =
 111                        kfd_queue_id_to_doorbell(dev, pqm->process, qid);
 112
 113        /* let DQM handle it*/
 114        q_properties->vmid = 0;
 115        q_properties->queue_id = qid;
 116
 117        retval = init_queue(q, q_properties);
 118        if (retval != 0)
 119                return retval;
 120
 121        (*q)->device = dev;
 122        (*q)->process = pqm->process;
 123
 124        pr_debug("PQM After init queue");
 125
 126        return retval;
 127}
 128
 129int pqm_create_queue(struct process_queue_manager *pqm,
 130                            struct kfd_dev *dev,
 131                            struct file *f,
 132                            struct queue_properties *properties,
 133                            unsigned int flags,
 134                            enum kfd_queue_type type,
 135                            unsigned int *qid)
 136{
 137        int retval;
 138        struct kfd_process_device *pdd;
 139        struct queue_properties q_properties;
 140        struct queue *q;
 141        struct process_queue_node *pqn;
 142        struct kernel_queue *kq;
 143        int num_queues = 0;
 144        struct queue *cur;
 145
 146        memcpy(&q_properties, properties, sizeof(struct queue_properties));
 147        q = NULL;
 148        kq = NULL;
 149
 150        pdd = kfd_get_process_device_data(dev, pqm->process);
 151        if (!pdd) {
 152                pr_err("Process device data doesn't exist\n");
 153                return -1;
 154        }
 155
 156        /*
 157         * for debug process, verify that it is within the static queues limit
 158         * currently limit is set to half of the total avail HQD slots
 159         * If we are just about to create DIQ, the is_debug flag is not set yet
 160         * Hence we also check the type as well
 161         */
 162        if ((pdd->qpd.is_debug) ||
 163                (type == KFD_QUEUE_TYPE_DIQ)) {
 164                list_for_each_entry(cur, &pdd->qpd.queues_list, list)
 165                        num_queues++;
 166                if (num_queues >= dev->device_info->max_no_of_hqd/2)
 167                        return -ENOSPC;
 168        }
 169
 170        retval = find_available_queue_slot(pqm, qid);
 171        if (retval != 0)
 172                return retval;
 173
 174        if (list_empty(&pqm->queues)) {
 175                pdd->qpd.pqm = pqm;
 176                dev->dqm->ops.register_process(dev->dqm, &pdd->qpd);
 177        }
 178
 179        pqn = kzalloc(sizeof(*pqn), GFP_KERNEL);
 180        if (!pqn) {
 181                retval = -ENOMEM;
 182                goto err_allocate_pqn;
 183        }
 184
 185        switch (type) {
 186        case KFD_QUEUE_TYPE_SDMA:
 187        case KFD_QUEUE_TYPE_COMPUTE:
 188                /* check if there is over subscription */
 189                if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
 190                ((dev->dqm->processes_count >= VMID_PER_DEVICE) ||
 191                (dev->dqm->queue_count >= get_queues_num(dev->dqm)))) {
 192                        pr_err("Over-subscription is not allowed in radeon_kfd.sched_policy == 1\n");
 193                        retval = -EPERM;
 194                        goto err_create_queue;
 195                }
 196
 197                retval = create_cp_queue(pqm, dev, &q, &q_properties, f, *qid);
 198                if (retval != 0)
 199                        goto err_create_queue;
 200                pqn->q = q;
 201                pqn->kq = NULL;
 202                retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd,
 203                                                &q->properties.vmid);
 204                pr_debug("DQM returned %d for create_queue\n", retval);
 205                print_queue(q);
 206                break;
 207        case KFD_QUEUE_TYPE_DIQ:
 208                kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_DIQ);
 209                if (!kq) {
 210                        retval = -ENOMEM;
 211                        goto err_create_queue;
 212                }
 213                kq->queue->properties.queue_id = *qid;
 214                pqn->kq = kq;
 215                pqn->q = NULL;
 216                retval = dev->dqm->ops.create_kernel_queue(dev->dqm,
 217                                                        kq, &pdd->qpd);
 218                break;
 219        default:
 220                WARN(1, "Invalid queue type %d", type);
 221                retval = -EINVAL;
 222        }
 223
 224        if (retval != 0) {
 225                pr_err("DQM create queue failed\n");
 226                goto err_create_queue;
 227        }
 228
 229        pr_debug("PQM After DQM create queue\n");
 230
 231        list_add(&pqn->process_queue_list, &pqm->queues);
 232
 233        if (q) {
 234                *properties = q->properties;
 235                pr_debug("PQM done creating queue\n");
 236                print_queue_properties(properties);
 237        }
 238
 239        return retval;
 240
 241err_create_queue:
 242        kfree(pqn);
 243err_allocate_pqn:
 244        /* check if queues list is empty unregister process from device */
 245        clear_bit(*qid, pqm->queue_slot_bitmap);
 246        if (list_empty(&pqm->queues))
 247                dev->dqm->ops.unregister_process(dev->dqm, &pdd->qpd);
 248        return retval;
 249}
 250
 251int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
 252{
 253        struct process_queue_node *pqn;
 254        struct kfd_process_device *pdd;
 255        struct device_queue_manager *dqm;
 256        struct kfd_dev *dev;
 257        int retval;
 258
 259        dqm = NULL;
 260
 261        retval = 0;
 262
 263        pqn = get_queue_by_qid(pqm, qid);
 264        if (!pqn) {
 265                pr_err("Queue id does not match any known queue\n");
 266                return -EINVAL;
 267        }
 268
 269        dev = NULL;
 270        if (pqn->kq)
 271                dev = pqn->kq->dev;
 272        if (pqn->q)
 273                dev = pqn->q->device;
 274        if (WARN_ON(!dev))
 275                return -ENODEV;
 276
 277        pdd = kfd_get_process_device_data(dev, pqm->process);
 278        if (!pdd) {
 279                pr_err("Process device data doesn't exist\n");
 280                return -1;
 281        }
 282
 283        if (pqn->kq) {
 284                /* destroy kernel queue (DIQ) */
 285                dqm = pqn->kq->dev->dqm;
 286                dqm->ops.destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
 287                kernel_queue_uninit(pqn->kq);
 288        }
 289
 290        if (pqn->q) {
 291                dqm = pqn->q->device->dqm;
 292                retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q);
 293                if (retval != 0)
 294                        return retval;
 295
 296                uninit_queue(pqn->q);
 297        }
 298
 299        list_del(&pqn->process_queue_list);
 300        kfree(pqn);
 301        clear_bit(qid, pqm->queue_slot_bitmap);
 302
 303        if (list_empty(&pqm->queues))
 304                dqm->ops.unregister_process(dqm, &pdd->qpd);
 305
 306        return retval;
 307}
 308
 309int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,
 310                        struct queue_properties *p)
 311{
 312        int retval;
 313        struct process_queue_node *pqn;
 314
 315        pqn = get_queue_by_qid(pqm, qid);
 316        if (!pqn) {
 317                pr_debug("No queue %d exists for update operation\n", qid);
 318                return -EFAULT;
 319        }
 320
 321        pqn->q->properties.queue_address = p->queue_address;
 322        pqn->q->properties.queue_size = p->queue_size;
 323        pqn->q->properties.queue_percent = p->queue_percent;
 324        pqn->q->properties.priority = p->priority;
 325
 326        retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
 327                                                        pqn->q);
 328        if (retval != 0)
 329                return retval;
 330
 331        return 0;
 332}
 333
 334struct kernel_queue *pqm_get_kernel_queue(
 335                                        struct process_queue_manager *pqm,
 336                                        unsigned int qid)
 337{
 338        struct process_queue_node *pqn;
 339
 340        pqn = get_queue_by_qid(pqm, qid);
 341        if (pqn && pqn->kq)
 342                return pqn->kq;
 343
 344        return NULL;
 345}
 346
 347
 348