xref: /openbmc/linux/drivers/misc/ocxl/pasid.c (revision 5ef3166e)
15ef3166eSFrederic Barrat // SPDX-License-Identifier: GPL-2.0+
25ef3166eSFrederic Barrat // Copyright 2017 IBM Corp.
35ef3166eSFrederic Barrat #include "ocxl_internal.h"
45ef3166eSFrederic Barrat 
55ef3166eSFrederic Barrat 
65ef3166eSFrederic Barrat struct id_range {
75ef3166eSFrederic Barrat 	struct list_head list;
85ef3166eSFrederic Barrat 	u32 start;
95ef3166eSFrederic Barrat 	u32 end;
105ef3166eSFrederic Barrat };
115ef3166eSFrederic Barrat 
125ef3166eSFrederic Barrat #ifdef DEBUG
dump_list(struct list_head * head,char * type_str)135ef3166eSFrederic Barrat static void dump_list(struct list_head *head, char *type_str)
145ef3166eSFrederic Barrat {
155ef3166eSFrederic Barrat 	struct id_range *cur;
165ef3166eSFrederic Barrat 
175ef3166eSFrederic Barrat 	pr_debug("%s ranges allocated:\n", type_str);
185ef3166eSFrederic Barrat 	list_for_each_entry(cur, head, list) {
195ef3166eSFrederic Barrat 		pr_debug("Range %d->%d\n", cur->start, cur->end);
205ef3166eSFrederic Barrat 	}
215ef3166eSFrederic Barrat }
225ef3166eSFrederic Barrat #endif
235ef3166eSFrederic Barrat 
range_alloc(struct list_head * head,u32 size,int max_id,char * type_str)245ef3166eSFrederic Barrat static int range_alloc(struct list_head *head, u32 size, int max_id,
255ef3166eSFrederic Barrat 		char *type_str)
265ef3166eSFrederic Barrat {
275ef3166eSFrederic Barrat 	struct list_head *pos;
285ef3166eSFrederic Barrat 	struct id_range *cur, *new;
295ef3166eSFrederic Barrat 	int rc, last_end;
305ef3166eSFrederic Barrat 
315ef3166eSFrederic Barrat 	new = kmalloc(sizeof(struct id_range), GFP_KERNEL);
325ef3166eSFrederic Barrat 	if (!new)
335ef3166eSFrederic Barrat 		return -ENOMEM;
345ef3166eSFrederic Barrat 
355ef3166eSFrederic Barrat 	pos = head;
365ef3166eSFrederic Barrat 	last_end = -1;
375ef3166eSFrederic Barrat 	list_for_each_entry(cur, head, list) {
385ef3166eSFrederic Barrat 		if ((cur->start - last_end) > size)
395ef3166eSFrederic Barrat 			break;
405ef3166eSFrederic Barrat 		last_end = cur->end;
415ef3166eSFrederic Barrat 		pos = &cur->list;
425ef3166eSFrederic Barrat 	}
435ef3166eSFrederic Barrat 
445ef3166eSFrederic Barrat 	new->start = last_end + 1;
455ef3166eSFrederic Barrat 	new->end = new->start + size - 1;
465ef3166eSFrederic Barrat 
475ef3166eSFrederic Barrat 	if (new->end > max_id) {
485ef3166eSFrederic Barrat 		kfree(new);
495ef3166eSFrederic Barrat 		rc = -ENOSPC;
505ef3166eSFrederic Barrat 	} else {
515ef3166eSFrederic Barrat 		list_add(&new->list, pos);
525ef3166eSFrederic Barrat 		rc = new->start;
535ef3166eSFrederic Barrat 	}
545ef3166eSFrederic Barrat 
555ef3166eSFrederic Barrat #ifdef DEBUG
565ef3166eSFrederic Barrat 	dump_list(head, type_str);
575ef3166eSFrederic Barrat #endif
585ef3166eSFrederic Barrat 	return rc;
595ef3166eSFrederic Barrat }
605ef3166eSFrederic Barrat 
range_free(struct list_head * head,u32 start,u32 size,char * type_str)615ef3166eSFrederic Barrat static void range_free(struct list_head *head, u32 start, u32 size,
625ef3166eSFrederic Barrat 		char *type_str)
635ef3166eSFrederic Barrat {
645ef3166eSFrederic Barrat 	bool found = false;
655ef3166eSFrederic Barrat 	struct id_range *cur, *tmp;
665ef3166eSFrederic Barrat 
675ef3166eSFrederic Barrat 	list_for_each_entry_safe(cur, tmp, head, list) {
685ef3166eSFrederic Barrat 		if (cur->start == start && cur->end == (start + size - 1)) {
695ef3166eSFrederic Barrat 			found = true;
705ef3166eSFrederic Barrat 			list_del(&cur->list);
715ef3166eSFrederic Barrat 			kfree(cur);
725ef3166eSFrederic Barrat 			break;
735ef3166eSFrederic Barrat 		}
745ef3166eSFrederic Barrat 	}
755ef3166eSFrederic Barrat 	WARN_ON(!found);
765ef3166eSFrederic Barrat #ifdef DEBUG
775ef3166eSFrederic Barrat 	dump_list(head, type_str);
785ef3166eSFrederic Barrat #endif
795ef3166eSFrederic Barrat }
805ef3166eSFrederic Barrat 
ocxl_pasid_afu_alloc(struct ocxl_fn * fn,u32 size)815ef3166eSFrederic Barrat int ocxl_pasid_afu_alloc(struct ocxl_fn *fn, u32 size)
825ef3166eSFrederic Barrat {
835ef3166eSFrederic Barrat 	int max_pasid;
845ef3166eSFrederic Barrat 
855ef3166eSFrederic Barrat 	if (fn->config.max_pasid_log < 0)
865ef3166eSFrederic Barrat 		return -ENOSPC;
875ef3166eSFrederic Barrat 	max_pasid = 1 << fn->config.max_pasid_log;
885ef3166eSFrederic Barrat 	return range_alloc(&fn->pasid_list, size, max_pasid, "afu pasid");
895ef3166eSFrederic Barrat }
905ef3166eSFrederic Barrat 
ocxl_pasid_afu_free(struct ocxl_fn * fn,u32 start,u32 size)915ef3166eSFrederic Barrat void ocxl_pasid_afu_free(struct ocxl_fn *fn, u32 start, u32 size)
925ef3166eSFrederic Barrat {
935ef3166eSFrederic Barrat 	return range_free(&fn->pasid_list, start, size, "afu pasid");
945ef3166eSFrederic Barrat }
955ef3166eSFrederic Barrat 
ocxl_actag_afu_alloc(struct ocxl_fn * fn,u32 size)965ef3166eSFrederic Barrat int ocxl_actag_afu_alloc(struct ocxl_fn *fn, u32 size)
975ef3166eSFrederic Barrat {
985ef3166eSFrederic Barrat 	int max_actag;
995ef3166eSFrederic Barrat 
1005ef3166eSFrederic Barrat 	max_actag = fn->actag_enabled;
1015ef3166eSFrederic Barrat 	return range_alloc(&fn->actag_list, size, max_actag, "afu actag");
1025ef3166eSFrederic Barrat }
1035ef3166eSFrederic Barrat 
ocxl_actag_afu_free(struct ocxl_fn * fn,u32 start,u32 size)1045ef3166eSFrederic Barrat void ocxl_actag_afu_free(struct ocxl_fn *fn, u32 start, u32 size)
1055ef3166eSFrederic Barrat {
1065ef3166eSFrederic Barrat 	return range_free(&fn->actag_list, start, size, "afu actag");
1075ef3166eSFrederic Barrat }
108