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 44219820Sjeffstruct mthca_ah_page { 45219820Sjeff struct mthca_ah_page *prev, *next; 46219820Sjeff struct mthca_buf buf; 47219820Sjeff struct ibv_mr *mr; 48219820Sjeff int use_cnt; 49219820Sjeff unsigned free[0]; 50219820Sjeff}; 51219820Sjeff 52219820Sjeffstatic struct mthca_ah_page *__add_page(struct mthca_pd *pd, int page_size, int per_page) 53219820Sjeff{ 54219820Sjeff struct mthca_ah_page *page; 55219820Sjeff int i; 56219820Sjeff 57219820Sjeff page = malloc(sizeof *page + per_page * sizeof (int)); 58219820Sjeff if (!page) 59219820Sjeff return NULL; 60219820Sjeff 61219820Sjeff if (mthca_alloc_buf(&page->buf, page_size, page_size)) { 62219820Sjeff free(page); 63219820Sjeff return NULL; 64219820Sjeff } 65219820Sjeff 66219820Sjeff page->mr = mthca_reg_mr(&pd->ibv_pd, page->buf.buf, page_size, 0); 67219820Sjeff if (!page->mr) { 68219820Sjeff mthca_free_buf(&page->buf); 69219820Sjeff free(page); 70219820Sjeff return NULL; 71219820Sjeff } 72219820Sjeff 73219820Sjeff page->mr->context = pd->ibv_pd.context; 74219820Sjeff 75219820Sjeff page->use_cnt = 0; 76219820Sjeff for (i = 0; i < per_page; ++i) 77219820Sjeff page->free[i] = ~0; 78219820Sjeff 79219820Sjeff page->prev = NULL; 80219820Sjeff page->next = pd->ah_list; 81219820Sjeff pd->ah_list = page; 82219820Sjeff if (page->next) 83219820Sjeff page->next->prev = page; 84219820Sjeff 85219820Sjeff return page; 86219820Sjeff} 87219820Sjeff 88219820Sjeffint mthca_alloc_av(struct mthca_pd *pd, struct ibv_ah_attr *attr, 89219820Sjeff struct mthca_ah *ah) 90219820Sjeff{ 91219820Sjeff if (mthca_is_memfree(pd->ibv_pd.context)) { 92219820Sjeff ah->av = malloc(sizeof *ah->av); 93219820Sjeff if (!ah->av) 94219820Sjeff return -1; 95219820Sjeff } else { 96219820Sjeff struct mthca_ah_page *page; 97219820Sjeff int ps; 98219820Sjeff int pp; 99219820Sjeff int i, j; 100219820Sjeff 101219820Sjeff ps = to_mdev(pd->ibv_pd.context->device)->page_size; 102219820Sjeff pp = ps / (sizeof *ah->av * 8 * sizeof (int)); 103219820Sjeff 104219820Sjeff pthread_mutex_lock(&pd->ah_mutex); 105219820Sjeff for (page = pd->ah_list; page; page = page->next) 106219820Sjeff if (page->use_cnt < ps / sizeof *ah->av) 107219820Sjeff for (i = 0; i < pp; ++i) 108219820Sjeff if (page->free[i]) 109219820Sjeff goto found; 110219820Sjeff 111219820Sjeff page = __add_page(pd, ps, pp); 112219820Sjeff if (!page) { 113219820Sjeff pthread_mutex_unlock(&pd->ah_mutex); 114219820Sjeff return -1; 115219820Sjeff } 116219820Sjeff 117219820Sjeff found: 118219820Sjeff ++page->use_cnt; 119219820Sjeff 120219820Sjeff for (i = 0, j = -1; i < pp; ++i) 121219820Sjeff if (page->free[i]) { 122219820Sjeff j = ffs(page->free[i]); 123219820Sjeff page->free[i] &= ~(1 << (j - 1)); 124219820Sjeff ah->av = page->buf.buf + 125219820Sjeff (i * 8 * sizeof (int) + (j - 1)) * sizeof *ah->av; 126219820Sjeff break; 127219820Sjeff } 128219820Sjeff 129219820Sjeff ah->key = page->mr->lkey; 130219820Sjeff ah->page = page; 131219820Sjeff 132219820Sjeff pthread_mutex_unlock(&pd->ah_mutex); 133219820Sjeff } 134219820Sjeff 135219820Sjeff memset(ah->av, 0, sizeof *ah->av); 136219820Sjeff 137219820Sjeff ah->av->port_pd = htonl(pd->pdn | (attr->port_num << 24)); 138219820Sjeff ah->av->g_slid = attr->src_path_bits; 139219820Sjeff ah->av->dlid = htons(attr->dlid); 140219820Sjeff ah->av->msg_sr = (3 << 4) | /* 2K message */ 141219820Sjeff attr->static_rate; 142219820Sjeff ah->av->sl_tclass_flowlabel = htonl(attr->sl << 28); 143219820Sjeff if (attr->is_global) { 144219820Sjeff ah->av->g_slid |= 0x80; 145219820Sjeff /* XXX get gid_table length */ 146219820Sjeff ah->av->gid_index = (attr->port_num - 1) * 32 + 147219820Sjeff attr->grh.sgid_index; 148219820Sjeff ah->av->hop_limit = attr->grh.hop_limit; 149219820Sjeff ah->av->sl_tclass_flowlabel |= 150219820Sjeff htonl((attr->grh.traffic_class << 20) | 151219820Sjeff attr->grh.flow_label); 152219820Sjeff memcpy(ah->av->dgid, attr->grh.dgid.raw, 16); 153219820Sjeff } else { 154219820Sjeff /* Arbel workaround -- low byte of GID must be 2 */ 155219820Sjeff ah->av->dgid[3] = htonl(2); 156219820Sjeff } 157219820Sjeff 158219820Sjeff return 0; 159219820Sjeff} 160219820Sjeff 161219820Sjeffvoid mthca_free_av(struct mthca_ah *ah) 162219820Sjeff{ 163219820Sjeff if (mthca_is_memfree(ah->ibv_ah.context)) { 164219820Sjeff free(ah->av); 165219820Sjeff } else { 166219820Sjeff struct mthca_pd *pd = to_mpd(ah->ibv_ah.pd); 167219820Sjeff struct mthca_ah_page *page; 168219820Sjeff int i; 169219820Sjeff 170219820Sjeff pthread_mutex_lock(&pd->ah_mutex); 171219820Sjeff 172219820Sjeff page = ah->page; 173219820Sjeff i = ((void *) ah->av - page->buf.buf) / sizeof *ah->av; 174219820Sjeff page->free[i / (8 * sizeof (int))] |= 1 << (i % (8 * sizeof (int))); 175219820Sjeff 176219820Sjeff if (!--page->use_cnt) { 177219820Sjeff if (page->prev) 178219820Sjeff page->prev->next = page->next; 179219820Sjeff else 180219820Sjeff pd->ah_list = page->next; 181219820Sjeff if (page->next) 182219820Sjeff page->next->prev = page->prev; 183219820Sjeff 184219820Sjeff mthca_dereg_mr(page->mr); 185219820Sjeff mthca_free_buf(&page->buf); 186219820Sjeff free(page); 187219820Sjeff } 188219820Sjeff 189219820Sjeff pthread_mutex_unlock(&pd->ah_mutex); 190219820Sjeff } 191219820Sjeff} 192