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