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 "mthca.h" 43219820Sjeff 44219820Sjeff#define MTHCA_FREE_MAP_SIZE (MTHCA_DB_REC_PER_PAGE / (SIZEOF_LONG * 8)) 45219820Sjeff 46219820Sjeffstruct mthca_db_page { 47219820Sjeff unsigned long free[MTHCA_FREE_MAP_SIZE]; 48219820Sjeff struct mthca_buf db_rec; 49219820Sjeff}; 50219820Sjeff 51219820Sjeffstruct mthca_db_table { 52219820Sjeff int npages; 53219820Sjeff int max_group1; 54219820Sjeff int min_group2; 55219820Sjeff pthread_mutex_t mutex; 56219820Sjeff struct mthca_db_page page[]; 57219820Sjeff}; 58219820Sjeff 59219820Sjeffint mthca_alloc_db(struct mthca_db_table *db_tab, enum mthca_db_type type, 60219820Sjeff uint32_t **db) 61219820Sjeff{ 62219820Sjeff int i, j, k; 63219820Sjeff int group, start, end, dir; 64219820Sjeff int ret = 0; 65219820Sjeff 66219820Sjeff pthread_mutex_lock(&db_tab->mutex); 67219820Sjeff 68219820Sjeff switch (type) { 69219820Sjeff case MTHCA_DB_TYPE_CQ_ARM: 70219820Sjeff case MTHCA_DB_TYPE_SQ: 71219820Sjeff group = 0; 72219820Sjeff start = 0; 73219820Sjeff end = db_tab->max_group1; 74219820Sjeff dir = 1; 75219820Sjeff break; 76219820Sjeff 77219820Sjeff case MTHCA_DB_TYPE_CQ_SET_CI: 78219820Sjeff case MTHCA_DB_TYPE_RQ: 79219820Sjeff case MTHCA_DB_TYPE_SRQ: 80219820Sjeff group = 1; 81219820Sjeff start = db_tab->npages - 1; 82219820Sjeff end = db_tab->min_group2; 83219820Sjeff dir = -1; 84219820Sjeff break; 85219820Sjeff 86219820Sjeff default: 87219820Sjeff ret = -1; 88219820Sjeff goto out; 89219820Sjeff } 90219820Sjeff 91219820Sjeff for (i = start; i != end; i += dir) 92219820Sjeff if (db_tab->page[i].db_rec.buf) 93219820Sjeff for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) 94219820Sjeff if (db_tab->page[i].free[j]) 95219820Sjeff goto found; 96219820Sjeff 97219820Sjeff if (db_tab->max_group1 >= db_tab->min_group2 - 1) { 98219820Sjeff ret = -1; 99219820Sjeff goto out; 100219820Sjeff } 101219820Sjeff 102219820Sjeff if (mthca_alloc_buf(&db_tab->page[i].db_rec, 103219820Sjeff MTHCA_DB_REC_PAGE_SIZE, 104219820Sjeff MTHCA_DB_REC_PAGE_SIZE)) { 105219820Sjeff ret = -1; 106219820Sjeff goto out; 107219820Sjeff } 108219820Sjeff 109219820Sjeff memset(db_tab->page[i].db_rec.buf, 0, MTHCA_DB_REC_PAGE_SIZE); 110219820Sjeff memset(db_tab->page[i].free, 0xff, sizeof db_tab->page[i].free); 111219820Sjeff 112219820Sjeff if (group == 0) 113219820Sjeff ++db_tab->max_group1; 114219820Sjeff else 115219820Sjeff --db_tab->min_group2; 116219820Sjeff 117219820Sjefffound: 118219820Sjeff for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) { 119219820Sjeff k = ffsl(db_tab->page[i].free[j]); 120219820Sjeff if (k) 121219820Sjeff break; 122219820Sjeff } 123219820Sjeff 124219820Sjeff if (!k) { 125219820Sjeff ret = -1; 126219820Sjeff goto out; 127219820Sjeff } 128219820Sjeff 129219820Sjeff --k; 130219820Sjeff db_tab->page[i].free[j] &= ~(1UL << k); 131219820Sjeff 132219820Sjeff j = j * SIZEOF_LONG * 8 + k; 133219820Sjeff if (group == 1) 134219820Sjeff j = MTHCA_DB_REC_PER_PAGE - 1 - j; 135219820Sjeff 136219820Sjeff ret = i * MTHCA_DB_REC_PER_PAGE + j; 137219820Sjeff *db = db_tab->page[i].db_rec.buf + j * 8; 138219820Sjeff 139219820Sjeffout: 140219820Sjeff pthread_mutex_unlock(&db_tab->mutex); 141219820Sjeff return ret; 142219820Sjeff} 143219820Sjeff 144219820Sjeffvoid mthca_set_db_qn(uint32_t *db, enum mthca_db_type type, uint32_t qn) 145219820Sjeff{ 146219820Sjeff db[1] = htonl((qn << 8) | (type << 5)); 147219820Sjeff} 148219820Sjeff 149219820Sjeffvoid mthca_free_db(struct mthca_db_table *db_tab, enum mthca_db_type type, int db_index) 150219820Sjeff{ 151219820Sjeff int i, j; 152219820Sjeff struct mthca_db_page *page; 153219820Sjeff 154219820Sjeff i = db_index / MTHCA_DB_REC_PER_PAGE; 155219820Sjeff j = db_index % MTHCA_DB_REC_PER_PAGE; 156219820Sjeff 157219820Sjeff page = db_tab->page + i; 158219820Sjeff 159219820Sjeff pthread_mutex_lock(&db_tab->mutex); 160219820Sjeff *(uint64_t *) (page->db_rec.buf + j * 8) = 0; 161219820Sjeff 162219820Sjeff if (i >= db_tab->min_group2) 163219820Sjeff j = MTHCA_DB_REC_PER_PAGE - 1 - j; 164219820Sjeff 165219820Sjeff page->free[j / (SIZEOF_LONG * 8)] |= 1UL << (j % (SIZEOF_LONG * 8)); 166219820Sjeff 167219820Sjeff pthread_mutex_unlock(&db_tab->mutex); 168219820Sjeff} 169219820Sjeff 170219820Sjeffstruct mthca_db_table *mthca_alloc_db_tab(int uarc_size) 171219820Sjeff{ 172219820Sjeff struct mthca_db_table *db_tab; 173219820Sjeff int npages; 174219820Sjeff int i; 175219820Sjeff 176219820Sjeff npages = uarc_size / MTHCA_DB_REC_PAGE_SIZE; 177219820Sjeff db_tab = malloc(sizeof (struct mthca_db_table) + 178219820Sjeff npages * sizeof (struct mthca_db_page)); 179219820Sjeff 180219820Sjeff pthread_mutex_init(&db_tab->mutex, NULL); 181219820Sjeff 182219820Sjeff db_tab->npages = npages; 183219820Sjeff db_tab->max_group1 = 0; 184219820Sjeff db_tab->min_group2 = npages - 1; 185219820Sjeff 186219820Sjeff for (i = 0; i < npages; ++i) 187219820Sjeff db_tab->page[i].db_rec.buf = NULL; 188219820Sjeff 189219820Sjeff return db_tab; 190219820Sjeff} 191219820Sjeff 192219820Sjeffvoid mthca_free_db_tab(struct mthca_db_table *db_tab) 193219820Sjeff{ 194219820Sjeff int i; 195219820Sjeff 196219820Sjeff if (!db_tab) 197219820Sjeff return; 198219820Sjeff 199219820Sjeff for (i = 0; i < db_tab->npages; ++i) 200219820Sjeff if (db_tab->page[i].db_rec.buf) 201219820Sjeff mthca_free_buf(&db_tab->page[i].db_rec); 202219820Sjeff 203219820Sjeff free(db_tab); 204219820Sjeff} 205