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