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