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