linux/drivers/misc/ocxl/pasid.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2// Copyright 2017 IBM Corp.
   3#include "ocxl_internal.h"
   4
   5
   6struct id_range {
   7        struct list_head list;
   8        u32 start;
   9        u32 end;
  10};
  11
  12#ifdef DEBUG
  13static void dump_list(struct list_head *head, char *type_str)
  14{
  15        struct id_range *cur;
  16
  17        pr_debug("%s ranges allocated:\n", type_str);
  18        list_for_each_entry(cur, head, list) {
  19                pr_debug("Range %d->%d\n", cur->start, cur->end);
  20        }
  21}
  22#endif
  23
  24static int range_alloc(struct list_head *head, u32 size, int max_id,
  25                char *type_str)
  26{
  27        struct list_head *pos;
  28        struct id_range *cur, *new;
  29        int rc, last_end;
  30
  31        new = kmalloc(sizeof(struct id_range), GFP_KERNEL);
  32        if (!new)
  33                return -ENOMEM;
  34
  35        pos = head;
  36        last_end = -1;
  37        list_for_each_entry(cur, head, list) {
  38                if ((cur->start - last_end) > size)
  39                        break;
  40                last_end = cur->end;
  41                pos = &cur->list;
  42        }
  43
  44        new->start = last_end + 1;
  45        new->end = new->start + size - 1;
  46
  47        if (new->end > max_id) {
  48                kfree(new);
  49                rc = -ENOSPC;
  50        } else {
  51                list_add(&new->list, pos);
  52                rc = new->start;
  53        }
  54
  55#ifdef DEBUG
  56        dump_list(head, type_str);
  57#endif
  58        return rc;
  59}
  60
  61static void range_free(struct list_head *head, u32 start, u32 size,
  62                char *type_str)
  63{
  64        bool found = false;
  65        struct id_range *cur, *tmp;
  66
  67        list_for_each_entry_safe(cur, tmp, head, list) {
  68                if (cur->start == start && cur->end == (start + size - 1)) {
  69                        found = true;
  70                        list_del(&cur->list);
  71                        kfree(cur);
  72                        break;
  73                }
  74        }
  75        WARN_ON(!found);
  76#ifdef DEBUG
  77        dump_list(head, type_str);
  78#endif
  79}
  80
  81int ocxl_pasid_afu_alloc(struct ocxl_fn *fn, u32 size)
  82{
  83        int max_pasid;
  84
  85        if (fn->config.max_pasid_log < 0)
  86                return -ENOSPC;
  87        max_pasid = 1 << fn->config.max_pasid_log;
  88        return range_alloc(&fn->pasid_list, size, max_pasid, "afu pasid");
  89}
  90
  91void ocxl_pasid_afu_free(struct ocxl_fn *fn, u32 start, u32 size)
  92{
  93        return range_free(&fn->pasid_list, start, size, "afu pasid");
  94}
  95
  96int ocxl_actag_afu_alloc(struct ocxl_fn *fn, u32 size)
  97{
  98        int max_actag;
  99
 100        max_actag = fn->actag_enabled;
 101        return range_alloc(&fn->actag_list, size, max_actag, "afu actag");
 102}
 103
 104void ocxl_actag_afu_free(struct ocxl_fn *fn, u32 start, u32 size)
 105{
 106        return range_free(&fn->actag_list, start, size, "afu actag");
 107}
 108