1219820Sjeff/* 2219820Sjeff * Copyright (c) 2005 Topspin Communications. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff */ 32219820Sjeff 33219820Sjeff#if HAVE_CONFIG_H 34219820Sjeff# include <config.h> 35219820Sjeff#endif /* HAVE_CONFIG_H */ 36219820Sjeff 37219820Sjeff#include <stdlib.h> 38219820Sjeff#include <netinet/in.h> 39219820Sjeff#include <pthread.h> 40219820Sjeff#include <string.h> 41219820Sjeff 42219820Sjeff#include "mlx4.h" 43219820Sjeff 44219820Sjeffstruct mlx4_db_page { 45219820Sjeff struct mlx4_db_page *prev, *next; 46219820Sjeff struct mlx4_buf buf; 47219820Sjeff int num_db; 48219820Sjeff int use_cnt; 49219820Sjeff unsigned long free[0]; 50219820Sjeff}; 51219820Sjeff 52219820Sjeffstatic const int db_size[] = { 53219820Sjeff [MLX4_DB_TYPE_CQ] = 8, 54219820Sjeff [MLX4_DB_TYPE_RQ] = 4, 55219820Sjeff}; 56219820Sjeff 57219820Sjeffstatic struct mlx4_db_page *__add_page(struct mlx4_context *context, 58219820Sjeff enum mlx4_db_type type) 59219820Sjeff{ 60219820Sjeff struct mlx4_db_page *page; 61219820Sjeff int ps = to_mdev(context->ibv_ctx.device)->page_size; 62219820Sjeff int pp; 63219820Sjeff int i; 64219820Sjeff 65219820Sjeff pp = ps / db_size[type]; 66219820Sjeff 67219820Sjeff page = malloc(sizeof *page + pp / 8); 68219820Sjeff if (!page) 69219820Sjeff return NULL; 70219820Sjeff 71219820Sjeff if (mlx4_alloc_buf(&page->buf, ps, ps)) { 72219820Sjeff free(page); 73219820Sjeff return NULL; 74219820Sjeff } 75219820Sjeff 76219820Sjeff page->num_db = pp; 77219820Sjeff page->use_cnt = 0; 78219820Sjeff for (i = 0; i < pp / (sizeof (long) * 8); ++i) 79219820Sjeff page->free[i] = ~0; 80219820Sjeff 81219820Sjeff page->prev = NULL; 82219820Sjeff page->next = context->db_list[type]; 83219820Sjeff context->db_list[type] = page; 84219820Sjeff if (page->next) 85219820Sjeff page->next->prev = page; 86219820Sjeff 87219820Sjeff return page; 88219820Sjeff} 89219820Sjeff 90219820Sjeffuint32_t *mlx4_alloc_db(struct mlx4_context *context, enum mlx4_db_type type) 91219820Sjeff{ 92219820Sjeff struct mlx4_db_page *page; 93219820Sjeff uint32_t *db = NULL; 94219820Sjeff int i, j; 95219820Sjeff 96219820Sjeff pthread_mutex_lock(&context->db_list_mutex); 97219820Sjeff 98219820Sjeff for (page = context->db_list[type]; page; page = page->next) 99219820Sjeff if (page->use_cnt < page->num_db) 100219820Sjeff goto found; 101219820Sjeff 102219820Sjeff page = __add_page(context, type); 103219820Sjeff if (!page) 104219820Sjeff goto out; 105219820Sjeff 106219820Sjefffound: 107219820Sjeff ++page->use_cnt; 108219820Sjeff 109219820Sjeff for (i = 0; !page->free[i]; ++i) 110219820Sjeff /* nothing */; 111219820Sjeff 112219820Sjeff j = ffsl(page->free[i]); 113219820Sjeff page->free[i] &= ~(1UL << (j - 1)); 114219820Sjeff db = page->buf.buf + (i * 8 * sizeof (long) + (j - 1)) * db_size[type]; 115219820Sjeff 116219820Sjeffout: 117219820Sjeff pthread_mutex_unlock(&context->db_list_mutex); 118219820Sjeff 119219820Sjeff return db; 120219820Sjeff} 121219820Sjeff 122219820Sjeffvoid mlx4_free_db(struct mlx4_context *context, enum mlx4_db_type type, uint32_t *db) 123219820Sjeff{ 124219820Sjeff struct mlx4_db_page *page; 125219820Sjeff uintptr_t ps = to_mdev(context->ibv_ctx.device)->page_size; 126219820Sjeff int i; 127219820Sjeff 128219820Sjeff pthread_mutex_lock(&context->db_list_mutex); 129219820Sjeff 130219820Sjeff for (page = context->db_list[type]; page; page = page->next) 131219820Sjeff if (((uintptr_t) db & ~(ps - 1)) == (uintptr_t) page->buf.buf) 132219820Sjeff break; 133219820Sjeff 134219820Sjeff if (!page) 135219820Sjeff goto out; 136219820Sjeff 137219820Sjeff i = ((void *) db - page->buf.buf) / db_size[type]; 138219820Sjeff page->free[i / (8 * sizeof (long))] |= 1UL << (i % (8 * sizeof (long))); 139219820Sjeff 140219820Sjeff if (!--page->use_cnt) { 141219820Sjeff if (page->prev) 142219820Sjeff page->prev->next = page->next; 143219820Sjeff else 144219820Sjeff context->db_list[type] = page->next; 145219820Sjeff if (page->next) 146219820Sjeff page->next->prev = page->prev; 147219820Sjeff 148219820Sjeff mlx4_free_buf(&page->buf); 149219820Sjeff free(page); 150219820Sjeff } 151219820Sjeff 152219820Sjeffout: 153219820Sjeff pthread_mutex_unlock(&context->db_list_mutex); 154219820Sjeff} 155