1204076Spjd/* 2204076Spjd * Copyright (c) 2005 Topspin Communications. All rights reserved. 3204076Spjd * 4204076Spjd * This software is available to you under a choice of one of two 5204076Spjd * licenses. You may choose to be licensed under the terms of the GNU 6204076Spjd * General Public License (GPL) Version 2, available from the file 7204076Spjd * COPYING in the main directory of this source tree, or the 8204076Spjd * OpenIB.org BSD license below: 9204076Spjd * 10204076Spjd * Redistribution and use in source and binary forms, with or 11204076Spjd * without modification, are permitted provided that the following 12204076Spjd * conditions are met: 13204076Spjd * 14204076Spjd * - Redistributions of source code must retain the above 15204076Spjd * copyright notice, this list of conditions and the following 16204076Spjd * disclaimer. 17204076Spjd * 18204076Spjd * - Redistributions in binary form must reproduce the above 19204076Spjd * copyright notice, this list of conditions and the following 20204076Spjd * disclaimer in the documentation and/or other materials 21204076Spjd * provided with the distribution. 22204076Spjd * 23204076Spjd * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24204076Spjd * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25204076Spjd * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26204076Spjd * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27204076Spjd * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28204076Spjd * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29204076Spjd * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30204076Spjd * SOFTWARE. 31204076Spjd */ 32204076Spjd 33204076Spjd#if HAVE_CONFIG_H 34204076Spjd# include <config.h> 35204076Spjd#endif /* HAVE_CONFIG_H */ 36204076Spjd 37204076Spjd#include <stdlib.h> 38204076Spjd#include <netinet/in.h> 39204076Spjd#include <pthread.h> 40204076Spjd#include <string.h> 41204076Spjd 42204076Spjd#include "mthca.h" 43204076Spjd 44204076Spjdstruct mthca_ah_page { 45204076Spjd struct mthca_ah_page *prev, *next; 46225787Spjd struct mthca_buf buf; 47204076Spjd struct ibv_mr *mr; 48225787Spjd int use_cnt; 49225787Spjd unsigned free[0]; 50225787Spjd}; 51225787Spjd 52225787Spjdstatic struct mthca_ah_page *__add_page(struct mthca_pd *pd, int page_size, int per_page) 53225787Spjd{ 54225787Spjd struct mthca_ah_page *page; 55225787Spjd int i; 56225787Spjd 57225787Spjd page = malloc(sizeof *page + per_page * sizeof (int)); 58214283Spjd if (!page) 59214283Spjd return NULL; 60214282Spjd 61214282Spjd if (mthca_alloc_buf(&page->buf, page_size, page_size)) { 62214282Spjd free(page); 63214282Spjd return NULL; 64214282Spjd } 65214282Spjd 66214282Spjd page->mr = mthca_reg_mr(&pd->ibv_pd, page->buf.buf, page_size, 0); 67214282Spjd if (!page->mr) { 68214282Spjd mthca_free_buf(&page->buf); 69214282Spjd free(page); 70214282Spjd return NULL; 71214282Spjd } 72214282Spjd 73214282Spjd page->mr->context = pd->ibv_pd.context; 74214282Spjd 75214282Spjd page->use_cnt = 0; 76214282Spjd for (i = 0; i < per_page; ++i) 77214282Spjd page->free[i] = ~0; 78214282Spjd 79214282Spjd page->prev = NULL; 80214282Spjd page->next = pd->ah_list; 81214282Spjd pd->ah_list = page; 82214282Spjd if (page->next) 83214282Spjd page->next->prev = page; 84214282Spjd 85214282Spjd return page; 86214282Spjd} 87204076Spjd 88204076Spjdint mthca_alloc_av(struct mthca_pd *pd, struct ibv_ah_attr *attr, 89204076Spjd struct mthca_ah *ah) 90204076Spjd{ 91204076Spjd if (mthca_is_memfree(pd->ibv_pd.context)) { 92204076Spjd ah->av = malloc(sizeof *ah->av); 93204076Spjd if (!ah->av) 94204076Spjd return -1; 95204076Spjd } else { 96204076Spjd struct mthca_ah_page *page; 97204076Spjd int ps; 98204076Spjd int pp; 99204076Spjd int i, j; 100204076Spjd 101204076Spjd ps = to_mdev(pd->ibv_pd.context->device)->page_size; 102204076Spjd pp = ps / (sizeof *ah->av * 8 * sizeof (int)); 103204076Spjd 104204076Spjd pthread_mutex_lock(&pd->ah_mutex); 105204076Spjd for (page = pd->ah_list; page; page = page->next) 106204076Spjd if (page->use_cnt < ps / sizeof *ah->av) 107204076Spjd for (i = 0; i < pp; ++i) 108204076Spjd if (page->free[i]) 109204076Spjd goto found; 110225787Spjd 111225787Spjd page = __add_page(pd, ps, pp); 112204076Spjd if (!page) { 113204076Spjd pthread_mutex_unlock(&pd->ah_mutex); 114204076Spjd return -1; 115204076Spjd } 116204076Spjd 117204076Spjd found: 118204076Spjd ++page->use_cnt; 119204076Spjd 120204076Spjd for (i = 0, j = -1; i < pp; ++i) 121204076Spjd if (page->free[i]) { 122204076Spjd j = ffs(page->free[i]); 123204076Spjd page->free[i] &= ~(1 << (j - 1)); 124204076Spjd ah->av = page->buf.buf + 125204076Spjd (i * 8 * sizeof (int) + (j - 1)) * sizeof *ah->av; 126204076Spjd break; 127204076Spjd } 128204076Spjd 129204076Spjd ah->key = page->mr->lkey; 130204076Spjd ah->page = page; 131204076Spjd 132204076Spjd pthread_mutex_unlock(&pd->ah_mutex); 133204076Spjd } 134204076Spjd 135204076Spjd memset(ah->av, 0, sizeof *ah->av); 136204076Spjd 137204076Spjd ah->av->port_pd = htonl(pd->pdn | (attr->port_num << 24)); 138204076Spjd ah->av->g_slid = attr->src_path_bits; 139204076Spjd ah->av->dlid = htons(attr->dlid); 140204076Spjd ah->av->msg_sr = (3 << 4) | /* 2K message */ 141204076Spjd attr->static_rate; 142204076Spjd ah->av->sl_tclass_flowlabel = htonl(attr->sl << 28); 143204076Spjd if (attr->is_global) { 144204076Spjd ah->av->g_slid |= 0x80; 145204076Spjd /* XXX get gid_table length */ 146204076Spjd ah->av->gid_index = (attr->port_num - 1) * 32 + 147204076Spjd attr->grh.sgid_index; 148204076Spjd ah->av->hop_limit = attr->grh.hop_limit; 149204076Spjd ah->av->sl_tclass_flowlabel |= 150204076Spjd htonl((attr->grh.traffic_class << 20) | 151204076Spjd attr->grh.flow_label); 152204076Spjd memcpy(ah->av->dgid, attr->grh.dgid.raw, 16); 153204076Spjd } else { 154204076Spjd /* Arbel workaround -- low byte of GID must be 2 */ 155204076Spjd ah->av->dgid[3] = htonl(2); 156204076Spjd } 157204076Spjd 158204076Spjd return 0; 159204076Spjd} 160204076Spjd 161204076Spjdvoid mthca_free_av(struct mthca_ah *ah) 162204076Spjd{ 163204076Spjd if (mthca_is_memfree(ah->ibv_ah.context)) { 164204076Spjd free(ah->av); 165204076Spjd } else { 166204076Spjd struct mthca_pd *pd = to_mpd(ah->ibv_ah.pd); 167204076Spjd struct mthca_ah_page *page; 168204076Spjd int i; 169204076Spjd 170204076Spjd pthread_mutex_lock(&pd->ah_mutex); 171204076Spjd 172204076Spjd page = ah->page; 173204076Spjd i = ((void *) ah->av - page->buf.buf) / sizeof *ah->av; 174204076Spjd page->free[i / (8 * sizeof (int))] |= 1 << (i % (8 * sizeof (int))); 175204076Spjd 176204076Spjd if (!--page->use_cnt) { 177204076Spjd if (page->prev) 178204076Spjd page->prev->next = page->next; 179204076Spjd else 180204076Spjd pd->ah_list = page->next; 181204076Spjd if (page->next) 182204076Spjd page->next->prev = page->prev; 183204076Spjd 184204076Spjd mthca_dereg_mr(page->mr); 185204076Spjd mthca_free_buf(&page->buf); 186204076Spjd free(page); 187204076Spjd } 188204076Spjd 189204076Spjd pthread_mutex_unlock(&pd->ah_mutex); 190204076Spjd } 191204076Spjd} 192204076Spjd