1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1997-1998 by Sun Microsystems, Inc. 24 * All rights reserved. 25 * Copyright 2026 Oxide Computer Company 26 */ 27 28 #ifndef _SYS_MEMLIST_IMPL_H 29 #define _SYS_MEMLIST_IMPL_H 30 31 /* 32 * Common memlist routines. 33 */ 34 35 #include <sys/memlist.h> 36 #include <sys/mutex.h> 37 38 #ifdef __cplusplus 39 extern "C" { 40 #endif 41 42 struct memlist_pool { 43 memlist_t *mp_freelist; 44 uint_t mp_freelist_count; 45 kmutex_t mp_freelist_mutex; 46 uint_t mp_flags; 47 }; 48 49 #define MEMLP_FL_EARLYBOOT 1 50 /* 51 * A pool that is not really a pool: entries come from kmem on demand and go 52 * back to it when freed, so allocation is unbounded and cannot fail rather 53 * than being served from a freelist that has to be stocked in advance. For 54 * consumers that run late enough to call kmem and do not know ahead of time 55 * how many entries they will need. 56 * 57 * Such a pool holds no state, so a single one serves everybody: see 58 * memlist_kmem_pool below. Its entries must never be mixed with a real 59 * pool's, since freeing them is kmem_free() rather than a freelist push. 60 * Use xmemlist_dup instead to copy entries to a memlist backed by a different 61 * pool. 62 */ 63 #define MEMLP_FL_KMEM 2 64 65 extern memlist_pool_t memlist_kmem_pool; 66 67 extern struct memlist *memlist_get_one(void); 68 extern void memlist_free_one(struct memlist *); 69 extern void memlist_free_list(struct memlist *); 70 extern void memlist_free_block(caddr_t, size_t); 71 extern void memlist_insert(struct memlist *, struct memlist **); 72 extern void memlist_del(struct memlist *, struct memlist **); 73 extern struct memlist *memlist_find(struct memlist *, uint64_t); 74 75 extern struct memlist *xmemlist_get_one(struct memlist_pool *); 76 extern void xmemlist_free_one(struct memlist_pool *, struct memlist *); 77 extern void xmemlist_free_list(struct memlist_pool *, struct memlist *); 78 extern void xmemlist_free_block(struct memlist_pool *, caddr_t, size_t); 79 80 #define MEML_SPANOP_OK 0 81 #define MEML_SPANOP_ESPAN 1 82 #define MEML_SPANOP_EALLOC 2 83 #define MEML_SPANOP_EOVERFLOW 3 84 85 /* 86 * Optional for span operations: allow munging (relaxed coalescing). When set, 87 * the span to be added or deleted from the list may overlap multiple existing 88 * entries and/or addresses not contained within the list. See notes in 89 * memlist_new.c. 90 */ 91 #define MEML_FL_RELAXED 1 92 93 extern int memlist_add_span(uint64_t, uint64_t, struct memlist **); 94 extern int memlist_delete_span(uint64_t, uint64_t, struct memlist **); 95 extern int xmemlist_add_span(struct memlist_pool *, uint64_t, uint64_t, 96 struct memlist **, uint64_t); 97 extern int xmemlist_delete_span(struct memlist_pool *, uint64_t, uint64_t, 98 struct memlist **, uint64_t); 99 100 /* 101 * Copy a list into the given pool, for handing it from one pool's ownership to 102 * another's. Returns NULL if that pool runs out. 103 */ 104 extern struct memlist *xmemlist_dup(memlist_pool_t *, const struct memlist *); 105 106 /* 107 * Free a whole list back to its pool and clear the caller's pointer to it. 108 */ 109 extern void xmemlist_free_all(memlist_pool_t *, struct memlist **); 110 111 /* 112 * Add every span of one list to another: their union, given MEML_FL_RELAXED. 113 * merge() leaves the source alone while subsume() empties it into the pool. 114 * 115 * Both stop at the first span that cannot be added, so on failure the 116 * destination holds what was transferred before it and, for subsume(), the 117 * source holds the rest. 118 */ 119 extern int xmemlist_merge(memlist_pool_t *, const struct memlist *, 120 struct memlist **, uint64_t); 121 extern int xmemlist_subsume(memlist_pool_t *, struct memlist **, 122 struct memlist **, uint64_t); 123 124 /* 125 * Delete every span of one list from another: their difference. The list being 126 * subtracted is untouched and need not belong to this pool. 127 * 128 * This will stop at the first failure to delete a span: no such span exists 129 * (if MEML_FL_RELAXED wasn't passed) or failed to allocate an entry for a newly 130 * split off span. In either case, the list under mutation holds whatever it 131 * started with less the spans successfully deleted. 132 */ 133 extern int xmemlist_delete_list(memlist_pool_t *, struct memlist **, 134 const struct memlist *, uint64_t); 135 136 /* 137 * Find the first span of the given size and alignment without modifying the 138 * list, for asking whether an allocation would succeed. Returns 139 * MEML_SPANOP_ESPAN if there is no such span, otherwise MEML_SPANOP_OK with the 140 * address a claim would hand back. Any non-zero alignment value must be a 141 * power-of-two. The address out parameter may be NULL if the specific address 142 * is not needed but just that such a span exists. 143 */ 144 extern int memlist_find_span(const struct memlist *, uint64_t, uint64_t, 145 uint64_t *); 146 147 /* 148 * These routines first try to find a span of the given size and alignment 149 * (in the entry beginning exactly at the given address for the _at form) and 150 * then call xmemlist_delete_span (with MEML_FL_RELAXED) to remove said span. 151 * If no such span is not found, MEML_SPANOP_ESPAN is returned with the list 152 * remaining untouched. If a span is found and successfully deleted from the 153 * list, the starting address is returned. Any non-zero alignment value must be 154 * a power-of-two. 155 */ 156 extern int xmemlist_claim_span(memlist_pool_t *, struct memlist **, uint64_t, 157 uint64_t, uint64_t *); 158 extern int xmemlist_claim_span_at(memlist_pool_t *, struct memlist **, 159 uint64_t, uint64_t, uint64_t, uint64_t *); 160 161 /* 162 * Convenience methods for tracking available/in-use address space. These are 163 * wrappers around the above xmemlist_* operations making use of the kmem pool 164 * and relaxed semantics. 165 * 166 * Fixing the pool and the flags is what makes most of these infallible, so they 167 * return nothing: relaxed semantics rule out MEML_SPANOP_ESPAN, and a 168 * kmem-backed pool sleeps for memory rather than returning MEML_SPANOP_EALLOC. 169 */ 170 extern void memlist_rsrc_add(struct memlist **, uint64_t, uint64_t); 171 extern void memlist_rsrc_delete(struct memlist **, uint64_t, uint64_t); 172 extern void memlist_rsrc_delete_list(struct memlist **, const struct memlist *); 173 extern void memlist_rsrc_merge(const struct memlist *, struct memlist **); 174 extern void memlist_rsrc_subsume(struct memlist **, struct memlist **); 175 extern int memlist_rsrc_claim(struct memlist **, uint64_t, uint64_t, 176 uint64_t *); 177 extern int memlist_rsrc_claim_at(struct memlist **, uint64_t, uint64_t, 178 uint64_t, uint64_t *); 179 extern struct memlist *memlist_rsrc_dup(const struct memlist *); 180 extern void memlist_rsrc_free(struct memlist **); 181 182 #ifdef __cplusplus 183 } 184 #endif 185 186 #endif /* _SYS_MEMLIST_IMPL_H */ 187