1 /* 2 * Copyright (c) 2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "qdf_flex_mem.h" 20 #include "qdf_list.h" 21 #include "qdf_lock.h" 22 #include "qdf_mem.h" 23 #include "qdf_trace.h" 24 #include "qdf_util.h" 25 26 void qdf_flex_mem_init(struct qdf_flex_mem_pool *pool) 27 { 28 qdf_spinlock_create(&pool->lock); 29 } 30 31 void qdf_flex_mem_deinit(struct qdf_flex_mem_pool *pool) 32 { 33 qdf_spinlock_destroy(&pool->lock); 34 } 35 36 static struct qdf_flex_mem_segment *qdf_flex_mem_seg_alloc(uint16_t item_size) 37 { 38 size_t bytes_size = item_size * QDF_FM_BITMAP_BITS; 39 size_t total_size = sizeof(struct qdf_flex_mem_segment) + bytes_size; 40 struct qdf_flex_mem_segment *seg; 41 42 seg = qdf_mem_malloc(total_size); 43 if (!seg) 44 return NULL; 45 46 seg->dynamic = true; 47 seg->bytes = (uint8_t *)(seg + 1); 48 49 return seg; 50 } 51 52 static void *__qdf_flex_mem_alloc(struct qdf_flex_mem_pool *pool) 53 { 54 struct qdf_flex_mem_segment *seg; 55 56 qdf_list_for_each(&pool->seg_list, seg, node) { 57 int index; 58 void *ptr; 59 60 index = qdf_ffz(seg->used_bitmap); 61 if (index < 0) 62 continue; 63 64 QDF_BUG(index < QDF_FM_BITMAP_BITS); 65 66 seg->used_bitmap ^= (QDF_FM_BITMAP)1 << index; 67 ptr = &seg->bytes[index * pool->item_size]; 68 qdf_mem_zero(ptr, pool->item_size); 69 70 return ptr; 71 } 72 73 seg = qdf_flex_mem_seg_alloc(pool->item_size); 74 if (!seg) 75 return NULL; 76 77 seg->used_bitmap = 1; 78 qdf_list_insert_back(&pool->seg_list, &seg->node); 79 80 return seg->bytes; 81 } 82 83 void *qdf_flex_mem_alloc(struct qdf_flex_mem_pool *pool) 84 { 85 void *ptr; 86 87 QDF_BUG(pool); 88 if (!pool) 89 return NULL; 90 91 qdf_spin_lock_bh(&pool->lock); 92 ptr = __qdf_flex_mem_alloc(pool); 93 qdf_spin_unlock_bh(&pool->lock); 94 95 return ptr; 96 } 97 98 static void qdf_flex_mem_seg_free(struct qdf_flex_mem_pool *pool, 99 struct qdf_flex_mem_segment *seg) 100 { 101 qdf_list_remove_node(&pool->seg_list, &seg->node); 102 qdf_mem_free(seg); 103 } 104 105 static void __qdf_flex_mem_free(struct qdf_flex_mem_pool *pool, void *ptr) 106 { 107 struct qdf_flex_mem_segment *seg; 108 void *low_addr; 109 void *high_addr; 110 unsigned long index; 111 112 qdf_list_for_each(&pool->seg_list, seg, node) { 113 low_addr = seg->bytes; 114 high_addr = low_addr + pool->item_size * QDF_FM_BITMAP_BITS; 115 116 if (ptr < low_addr || ptr > high_addr) 117 continue; 118 119 index = (ptr - low_addr) / pool->item_size; 120 QDF_BUG(index < QDF_FM_BITMAP_BITS); 121 122 seg->used_bitmap ^= (QDF_FM_BITMAP)1 << index; 123 if (!seg->used_bitmap && seg->dynamic) 124 qdf_flex_mem_seg_free(pool, seg); 125 126 return; 127 } 128 129 qdf_err("Failed to find pointer in segment pool"); 130 QDF_DEBUG_PANIC(); 131 } 132 133 void qdf_flex_mem_free(struct qdf_flex_mem_pool *pool, void *ptr) 134 { 135 QDF_BUG(pool); 136 if (!pool) 137 return; 138 139 QDF_BUG(ptr); 140 if (!ptr) 141 return; 142 143 qdf_spin_lock_bh(&pool->lock); 144 __qdf_flex_mem_free(pool, ptr); 145 qdf_spin_unlock_bh(&pool->lock); 146 } 147 148