memfree.c revision 272461
1/* 2 * Copyright (c) 2005 Topspin Communications. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#if HAVE_CONFIG_H 34# include <config.h> 35#endif /* HAVE_CONFIG_H */ 36 37#include <stdlib.h> 38#include <netinet/in.h> 39#include <pthread.h> 40#include <string.h> 41 42#include "mthca.h" 43 44#define MTHCA_FREE_MAP_SIZE (MTHCA_DB_REC_PER_PAGE / (SIZEOF_LONG * 8)) 45 46struct mthca_db_page { 47 unsigned long free[MTHCA_FREE_MAP_SIZE]; 48 struct mthca_buf db_rec; 49}; 50 51struct mthca_db_table { 52 int npages; 53 int max_group1; 54 int min_group2; 55 pthread_mutex_t mutex; 56 struct mthca_db_page page[]; 57}; 58 59int mthca_alloc_db(struct mthca_db_table *db_tab, enum mthca_db_type type, 60 uint32_t **db) 61{ 62 int i, j, k; 63 int group, start, end, dir; 64 int ret = 0; 65 66 pthread_mutex_lock(&db_tab->mutex); 67 68 switch (type) { 69 case MTHCA_DB_TYPE_CQ_ARM: 70 case MTHCA_DB_TYPE_SQ: 71 group = 0; 72 start = 0; 73 end = db_tab->max_group1; 74 dir = 1; 75 break; 76 77 case MTHCA_DB_TYPE_CQ_SET_CI: 78 case MTHCA_DB_TYPE_RQ: 79 case MTHCA_DB_TYPE_SRQ: 80 group = 1; 81 start = db_tab->npages - 1; 82 end = db_tab->min_group2; 83 dir = -1; 84 break; 85 86 default: 87 ret = -1; 88 goto out; 89 } 90 91 for (i = start; i != end; i += dir) 92 if (db_tab->page[i].db_rec.buf) 93 for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) 94 if (db_tab->page[i].free[j]) 95 goto found; 96 97 if (db_tab->max_group1 >= db_tab->min_group2 - 1) { 98 ret = -1; 99 goto out; 100 } 101 102 if (mthca_alloc_buf(&db_tab->page[i].db_rec, 103 MTHCA_DB_REC_PAGE_SIZE, 104 MTHCA_DB_REC_PAGE_SIZE)) { 105 ret = -1; 106 goto out; 107 } 108 109 memset(db_tab->page[i].db_rec.buf, 0, MTHCA_DB_REC_PAGE_SIZE); 110 memset(db_tab->page[i].free, 0xff, sizeof db_tab->page[i].free); 111 112 if (group == 0) 113 ++db_tab->max_group1; 114 else 115 --db_tab->min_group2; 116 117found: 118 for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) { 119 k = ffsl(db_tab->page[i].free[j]); 120 if (k) 121 break; 122 } 123 124 if (!k) { 125 ret = -1; 126 goto out; 127 } 128 129 --k; 130 db_tab->page[i].free[j] &= ~(1UL << k); 131 132 j = j * SIZEOF_LONG * 8 + k; 133 if (group == 1) 134 j = MTHCA_DB_REC_PER_PAGE - 1 - j; 135 136 ret = i * MTHCA_DB_REC_PER_PAGE + j; 137 *db = db_tab->page[i].db_rec.buf + j * 8; 138 139out: 140 pthread_mutex_unlock(&db_tab->mutex); 141 return ret; 142} 143 144void mthca_set_db_qn(uint32_t *db, enum mthca_db_type type, uint32_t qn) 145{ 146 db[1] = htonl((qn << 8) | (type << 5)); 147} 148 149void mthca_free_db(struct mthca_db_table *db_tab, enum mthca_db_type type, int db_index) 150{ 151 int i, j; 152 struct mthca_db_page *page; 153 154 i = db_index / MTHCA_DB_REC_PER_PAGE; 155 j = db_index % MTHCA_DB_REC_PER_PAGE; 156 157 page = db_tab->page + i; 158 159 pthread_mutex_lock(&db_tab->mutex); 160 *(uint64_t *) (page->db_rec.buf + j * 8) = 0; 161 162 if (i >= db_tab->min_group2) 163 j = MTHCA_DB_REC_PER_PAGE - 1 - j; 164 165 page->free[j / (SIZEOF_LONG * 8)] |= 1UL << (j % (SIZEOF_LONG * 8)); 166 167 pthread_mutex_unlock(&db_tab->mutex); 168} 169 170struct mthca_db_table *mthca_alloc_db_tab(int uarc_size) 171{ 172 struct mthca_db_table *db_tab; 173 int npages; 174 int i; 175 176 npages = uarc_size / MTHCA_DB_REC_PAGE_SIZE; 177 db_tab = malloc(sizeof (struct mthca_db_table) + 178 npages * sizeof (struct mthca_db_page)); 179 180 pthread_mutex_init(&db_tab->mutex, NULL); 181 182 db_tab->npages = npages; 183 db_tab->max_group1 = 0; 184 db_tab->min_group2 = npages - 1; 185 186 for (i = 0; i < npages; ++i) 187 db_tab->page[i].db_rec.buf = NULL; 188 189 return db_tab; 190} 191 192void mthca_free_db_tab(struct mthca_db_table *db_tab) 193{ 194 int i; 195 196 if (!db_tab) 197 return; 198 199 for (i = 0; i < db_tab->npages; ++i) 200 if (db_tab->page[i].db_rec.buf) 201 mthca_free_buf(&db_tab->page[i].db_rec); 202 203 free(db_tab); 204} 205