1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright 2017 IBM Corp. 3 #include "ocxl_internal.h" 4 5 6 struct id_range { 7 struct list_head list; 8 u32 start; 9 u32 end; 10 }; 11 12 #ifdef DEBUG 13 static 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 24 static 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 61 static 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 81 int 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 91 void 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 96 int 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 104 void 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