18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2004 Topspin Communications.  All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
68c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
98c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
128c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
138c2ecf20Sopenharmony_ci *     conditions are met:
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
168c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
178c2ecf20Sopenharmony_ci *        disclaimer.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
208c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
218c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
228c2ecf20Sopenharmony_ci *        provided with the distribution.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
258c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
268c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
278c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
298c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
308c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
318c2ecf20Sopenharmony_ci * SOFTWARE.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <linux/string.h>
358c2ecf20Sopenharmony_ci#include <linux/slab.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h>
388c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include "mthca_dev.h"
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cienum {
438c2ecf20Sopenharmony_ci      MTHCA_RATE_TAVOR_FULL   = 0,
448c2ecf20Sopenharmony_ci      MTHCA_RATE_TAVOR_1X     = 1,
458c2ecf20Sopenharmony_ci      MTHCA_RATE_TAVOR_4X     = 2,
468c2ecf20Sopenharmony_ci      MTHCA_RATE_TAVOR_1X_DDR = 3
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cienum {
508c2ecf20Sopenharmony_ci      MTHCA_RATE_MEMFREE_FULL    = 0,
518c2ecf20Sopenharmony_ci      MTHCA_RATE_MEMFREE_QUARTER = 1,
528c2ecf20Sopenharmony_ci      MTHCA_RATE_MEMFREE_EIGHTH  = 2,
538c2ecf20Sopenharmony_ci      MTHCA_RATE_MEMFREE_HALF    = 3
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistruct mthca_av {
578c2ecf20Sopenharmony_ci	__be32 port_pd;
588c2ecf20Sopenharmony_ci	u8     reserved1;
598c2ecf20Sopenharmony_ci	u8     g_slid;
608c2ecf20Sopenharmony_ci	__be16 dlid;
618c2ecf20Sopenharmony_ci	u8     reserved2;
628c2ecf20Sopenharmony_ci	u8     gid_index;
638c2ecf20Sopenharmony_ci	u8     msg_sr;
648c2ecf20Sopenharmony_ci	u8     hop_limit;
658c2ecf20Sopenharmony_ci	__be32 sl_tclass_flowlabel;
668c2ecf20Sopenharmony_ci	__be32 dgid[4];
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic enum ib_rate memfree_rate_to_ib(u8 mthca_rate, u8 port_rate)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	switch (mthca_rate) {
728c2ecf20Sopenharmony_ci	case MTHCA_RATE_MEMFREE_EIGHTH:
738c2ecf20Sopenharmony_ci		return mult_to_ib_rate(port_rate >> 3);
748c2ecf20Sopenharmony_ci	case MTHCA_RATE_MEMFREE_QUARTER:
758c2ecf20Sopenharmony_ci		return mult_to_ib_rate(port_rate >> 2);
768c2ecf20Sopenharmony_ci	case MTHCA_RATE_MEMFREE_HALF:
778c2ecf20Sopenharmony_ci		return mult_to_ib_rate(port_rate >> 1);
788c2ecf20Sopenharmony_ci	case MTHCA_RATE_MEMFREE_FULL:
798c2ecf20Sopenharmony_ci	default:
808c2ecf20Sopenharmony_ci		return mult_to_ib_rate(port_rate);
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic enum ib_rate tavor_rate_to_ib(u8 mthca_rate, u8 port_rate)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	switch (mthca_rate) {
878c2ecf20Sopenharmony_ci	case MTHCA_RATE_TAVOR_1X:     return IB_RATE_2_5_GBPS;
888c2ecf20Sopenharmony_ci	case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS;
898c2ecf20Sopenharmony_ci	case MTHCA_RATE_TAVOR_4X:     return IB_RATE_10_GBPS;
908c2ecf20Sopenharmony_ci	default:		      return mult_to_ib_rate(port_rate);
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cienum ib_rate mthca_rate_to_ib(struct mthca_dev *dev, u8 mthca_rate, u8 port)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
978c2ecf20Sopenharmony_ci		/* Handle old Arbel FW */
988c2ecf20Sopenharmony_ci		if (dev->limits.stat_rate_support == 0x3 && mthca_rate)
998c2ecf20Sopenharmony_ci			return IB_RATE_2_5_GBPS;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		return memfree_rate_to_ib(mthca_rate, dev->rate[port - 1]);
1028c2ecf20Sopenharmony_ci	} else
1038c2ecf20Sopenharmony_ci		return tavor_rate_to_ib(mthca_rate, dev->rate[port - 1]);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic u8 ib_rate_to_memfree(u8 req_rate, u8 cur_rate)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	if (cur_rate <= req_rate)
1098c2ecf20Sopenharmony_ci		return 0;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/*
1128c2ecf20Sopenharmony_ci	 * Inter-packet delay (IPD) to get from rate X down to a rate
1138c2ecf20Sopenharmony_ci	 * no more than Y is (X - 1) / Y.
1148c2ecf20Sopenharmony_ci	 */
1158c2ecf20Sopenharmony_ci	switch ((cur_rate - 1) / req_rate) {
1168c2ecf20Sopenharmony_ci	case 0:	 return MTHCA_RATE_MEMFREE_FULL;
1178c2ecf20Sopenharmony_ci	case 1:	 return MTHCA_RATE_MEMFREE_HALF;
1188c2ecf20Sopenharmony_ci	case 2:
1198c2ecf20Sopenharmony_ci	case 3:	 return MTHCA_RATE_MEMFREE_QUARTER;
1208c2ecf20Sopenharmony_ci	default: return MTHCA_RATE_MEMFREE_EIGHTH;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic u8 ib_rate_to_tavor(u8 static_rate)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	switch (static_rate) {
1278c2ecf20Sopenharmony_ci	case IB_RATE_2_5_GBPS: return MTHCA_RATE_TAVOR_1X;
1288c2ecf20Sopenharmony_ci	case IB_RATE_5_GBPS:   return MTHCA_RATE_TAVOR_1X_DDR;
1298c2ecf20Sopenharmony_ci	case IB_RATE_10_GBPS:  return MTHCA_RATE_TAVOR_4X;
1308c2ecf20Sopenharmony_ci	default:	       return MTHCA_RATE_TAVOR_FULL;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciu8 mthca_get_rate(struct mthca_dev *dev, int static_rate, u8 port)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	u8 rate;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (!static_rate || ib_rate_to_mult(static_rate) >= dev->rate[port - 1])
1398c2ecf20Sopenharmony_ci		return 0;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev))
1428c2ecf20Sopenharmony_ci		rate = ib_rate_to_memfree(ib_rate_to_mult(static_rate),
1438c2ecf20Sopenharmony_ci					  dev->rate[port - 1]);
1448c2ecf20Sopenharmony_ci	else
1458c2ecf20Sopenharmony_ci		rate = ib_rate_to_tavor(static_rate);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (!(dev->limits.stat_rate_support & (1 << rate)))
1488c2ecf20Sopenharmony_ci		rate = 1;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return rate;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ciint mthca_create_ah(struct mthca_dev *dev,
1548c2ecf20Sopenharmony_ci		    struct mthca_pd *pd,
1558c2ecf20Sopenharmony_ci		    struct rdma_ah_attr *ah_attr,
1568c2ecf20Sopenharmony_ci		    struct mthca_ah *ah)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	u32 index = -1;
1598c2ecf20Sopenharmony_ci	struct mthca_av *av = NULL;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	ah->type = MTHCA_AH_PCI_POOL;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
1648c2ecf20Sopenharmony_ci		ah->av   = kmalloc(sizeof *ah->av, GFP_ATOMIC);
1658c2ecf20Sopenharmony_ci		if (!ah->av)
1668c2ecf20Sopenharmony_ci			return -ENOMEM;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		ah->type = MTHCA_AH_KMALLOC;
1698c2ecf20Sopenharmony_ci		av       = ah->av;
1708c2ecf20Sopenharmony_ci	} else if (!atomic_read(&pd->sqp_count) &&
1718c2ecf20Sopenharmony_ci		 !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
1728c2ecf20Sopenharmony_ci		index = mthca_alloc(&dev->av_table.alloc);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		/* fall back to allocate in host memory */
1758c2ecf20Sopenharmony_ci		if (index == -1)
1768c2ecf20Sopenharmony_ci			goto on_hca_fail;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		av = kmalloc(sizeof *av, GFP_ATOMIC);
1798c2ecf20Sopenharmony_ci		if (!av)
1808c2ecf20Sopenharmony_ci			goto on_hca_fail;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		ah->type = MTHCA_AH_ON_HCA;
1838c2ecf20Sopenharmony_ci		ah->avdma  = dev->av_table.ddr_av_base +
1848c2ecf20Sopenharmony_ci			index * MTHCA_AV_SIZE;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cion_hca_fail:
1888c2ecf20Sopenharmony_ci	if (ah->type == MTHCA_AH_PCI_POOL) {
1898c2ecf20Sopenharmony_ci		ah->av = dma_pool_zalloc(dev->av_table.pool,
1908c2ecf20Sopenharmony_ci					 GFP_ATOMIC, &ah->avdma);
1918c2ecf20Sopenharmony_ci		if (!ah->av)
1928c2ecf20Sopenharmony_ci			return -ENOMEM;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		av = ah->av;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	ah->key = pd->ntmr.ibmr.lkey;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	av->port_pd = cpu_to_be32(pd->pd_num |
2008c2ecf20Sopenharmony_ci				  (rdma_ah_get_port_num(ah_attr) << 24));
2018c2ecf20Sopenharmony_ci	av->g_slid  = rdma_ah_get_path_bits(ah_attr);
2028c2ecf20Sopenharmony_ci	av->dlid    = cpu_to_be16(rdma_ah_get_dlid(ah_attr));
2038c2ecf20Sopenharmony_ci	av->msg_sr  = (3 << 4) | /* 2K message */
2048c2ecf20Sopenharmony_ci		mthca_get_rate(dev, rdma_ah_get_static_rate(ah_attr),
2058c2ecf20Sopenharmony_ci			       rdma_ah_get_port_num(ah_attr));
2068c2ecf20Sopenharmony_ci	av->sl_tclass_flowlabel = cpu_to_be32(rdma_ah_get_sl(ah_attr) << 28);
2078c2ecf20Sopenharmony_ci	if (rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) {
2088c2ecf20Sopenharmony_ci		const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		av->g_slid |= 0x80;
2118c2ecf20Sopenharmony_ci		av->gid_index = (rdma_ah_get_port_num(ah_attr) - 1) *
2128c2ecf20Sopenharmony_ci				  dev->limits.gid_table_len +
2138c2ecf20Sopenharmony_ci				  grh->sgid_index;
2148c2ecf20Sopenharmony_ci		av->hop_limit = grh->hop_limit;
2158c2ecf20Sopenharmony_ci		av->sl_tclass_flowlabel |=
2168c2ecf20Sopenharmony_ci			cpu_to_be32((grh->traffic_class << 20) |
2178c2ecf20Sopenharmony_ci				    grh->flow_label);
2188c2ecf20Sopenharmony_ci		memcpy(av->dgid, grh->dgid.raw, 16);
2198c2ecf20Sopenharmony_ci	} else {
2208c2ecf20Sopenharmony_ci		/* Arbel workaround -- low byte of GID must be 2 */
2218c2ecf20Sopenharmony_ci		av->dgid[3] = cpu_to_be32(2);
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (0) {
2258c2ecf20Sopenharmony_ci		int j;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		mthca_dbg(dev, "Created UDAV at %p/%08lx:\n",
2288c2ecf20Sopenharmony_ci			  av, (unsigned long) ah->avdma);
2298c2ecf20Sopenharmony_ci		for (j = 0; j < 8; ++j)
2308c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "  [%2x] %08x\n",
2318c2ecf20Sopenharmony_ci			       j * 4, be32_to_cpu(((__be32 *) av)[j]));
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (ah->type == MTHCA_AH_ON_HCA) {
2358c2ecf20Sopenharmony_ci		memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE,
2368c2ecf20Sopenharmony_ci			    av, MTHCA_AV_SIZE);
2378c2ecf20Sopenharmony_ci		kfree(av);
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return 0;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ciint mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	switch (ah->type) {
2468c2ecf20Sopenharmony_ci	case MTHCA_AH_ON_HCA:
2478c2ecf20Sopenharmony_ci		mthca_free(&dev->av_table.alloc,
2488c2ecf20Sopenharmony_ci			   (ah->avdma - dev->av_table.ddr_av_base) /
2498c2ecf20Sopenharmony_ci			   MTHCA_AV_SIZE);
2508c2ecf20Sopenharmony_ci		break;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	case MTHCA_AH_PCI_POOL:
2538c2ecf20Sopenharmony_ci		dma_pool_free(dev->av_table.pool, ah->av, ah->avdma);
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	case MTHCA_AH_KMALLOC:
2578c2ecf20Sopenharmony_ci		kfree(ah->av);
2588c2ecf20Sopenharmony_ci		break;
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return 0;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ciint mthca_ah_grh_present(struct mthca_ah *ah)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	return !!(ah->av->g_slid & 0x80);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ciint mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
2708c2ecf20Sopenharmony_ci		  struct ib_ud_header *header)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	if (ah->type == MTHCA_AH_ON_HCA)
2738c2ecf20Sopenharmony_ci		return -EINVAL;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	header->lrh.service_level   = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
2768c2ecf20Sopenharmony_ci	header->lrh.destination_lid = ah->av->dlid;
2778c2ecf20Sopenharmony_ci	header->lrh.source_lid      = cpu_to_be16(ah->av->g_slid & 0x7f);
2788c2ecf20Sopenharmony_ci	if (mthca_ah_grh_present(ah)) {
2798c2ecf20Sopenharmony_ci		header->grh.traffic_class =
2808c2ecf20Sopenharmony_ci			(be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff;
2818c2ecf20Sopenharmony_ci		header->grh.flow_label    =
2828c2ecf20Sopenharmony_ci			ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff);
2838c2ecf20Sopenharmony_ci		header->grh.hop_limit     = ah->av->hop_limit;
2848c2ecf20Sopenharmony_ci		header->grh.source_gid = ah->ibah.sgid_attr->gid;
2858c2ecf20Sopenharmony_ci		memcpy(header->grh.destination_gid.raw,
2868c2ecf20Sopenharmony_ci		       ah->av->dgid, 16);
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ciint mthca_ah_query(struct ib_ah *ibah, struct rdma_ah_attr *attr)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct mthca_ah *ah   = to_mah(ibah);
2958c2ecf20Sopenharmony_ci	struct mthca_dev *dev = to_mdev(ibah->device);
2968c2ecf20Sopenharmony_ci	u8 port_num = be32_to_cpu(ah->av->port_pd) >> 24;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	/* Only implement for MAD and memfree ah for now. */
2998c2ecf20Sopenharmony_ci	if (ah->type == MTHCA_AH_ON_HCA)
3008c2ecf20Sopenharmony_ci		return -ENOSYS;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	memset(attr, 0, sizeof *attr);
3038c2ecf20Sopenharmony_ci	attr->type = ibah->type;
3048c2ecf20Sopenharmony_ci	rdma_ah_set_dlid(attr, be16_to_cpu(ah->av->dlid));
3058c2ecf20Sopenharmony_ci	rdma_ah_set_sl(attr, be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28);
3068c2ecf20Sopenharmony_ci	rdma_ah_set_port_num(attr, port_num);
3078c2ecf20Sopenharmony_ci	rdma_ah_set_static_rate(attr,
3088c2ecf20Sopenharmony_ci				mthca_rate_to_ib(dev, ah->av->msg_sr & 0x7,
3098c2ecf20Sopenharmony_ci						 port_num));
3108c2ecf20Sopenharmony_ci	rdma_ah_set_path_bits(attr, ah->av->g_slid & 0x7F);
3118c2ecf20Sopenharmony_ci	if (mthca_ah_grh_present(ah)) {
3128c2ecf20Sopenharmony_ci		u32 tc_fl = be32_to_cpu(ah->av->sl_tclass_flowlabel);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci		rdma_ah_set_grh(attr, NULL,
3158c2ecf20Sopenharmony_ci				tc_fl & 0xfffff,
3168c2ecf20Sopenharmony_ci				ah->av->gid_index &
3178c2ecf20Sopenharmony_ci				(dev->limits.gid_table_len - 1),
3188c2ecf20Sopenharmony_ci				ah->av->hop_limit,
3198c2ecf20Sopenharmony_ci				(tc_fl >> 20) & 0xff);
3208c2ecf20Sopenharmony_ci		rdma_ah_set_dgid_raw(attr, ah->av->dgid);
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return 0;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciint mthca_init_av_table(struct mthca_dev *dev)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	int err;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev))
3318c2ecf20Sopenharmony_ci		return 0;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	err = mthca_alloc_init(&dev->av_table.alloc,
3348c2ecf20Sopenharmony_ci			       dev->av_table.num_ddr_avs,
3358c2ecf20Sopenharmony_ci			       dev->av_table.num_ddr_avs - 1,
3368c2ecf20Sopenharmony_ci			       0);
3378c2ecf20Sopenharmony_ci	if (err)
3388c2ecf20Sopenharmony_ci		return err;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	dev->av_table.pool = dma_pool_create("mthca_av", &dev->pdev->dev,
3418c2ecf20Sopenharmony_ci					     MTHCA_AV_SIZE,
3428c2ecf20Sopenharmony_ci					     MTHCA_AV_SIZE, 0);
3438c2ecf20Sopenharmony_ci	if (!dev->av_table.pool)
3448c2ecf20Sopenharmony_ci		goto out_free_alloc;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
3478c2ecf20Sopenharmony_ci		dev->av_table.av_map = ioremap(pci_resource_start(dev->pdev, 4) +
3488c2ecf20Sopenharmony_ci					       dev->av_table.ddr_av_base -
3498c2ecf20Sopenharmony_ci					       dev->ddr_start,
3508c2ecf20Sopenharmony_ci					       dev->av_table.num_ddr_avs *
3518c2ecf20Sopenharmony_ci					       MTHCA_AV_SIZE);
3528c2ecf20Sopenharmony_ci		if (!dev->av_table.av_map)
3538c2ecf20Sopenharmony_ci			goto out_free_pool;
3548c2ecf20Sopenharmony_ci	} else
3558c2ecf20Sopenharmony_ci		dev->av_table.av_map = NULL;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	return 0;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci out_free_pool:
3608c2ecf20Sopenharmony_ci	dma_pool_destroy(dev->av_table.pool);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci out_free_alloc:
3638c2ecf20Sopenharmony_ci	mthca_alloc_cleanup(&dev->av_table.alloc);
3648c2ecf20Sopenharmony_ci	return -ENOMEM;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_civoid mthca_cleanup_av_table(struct mthca_dev *dev)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev))
3708c2ecf20Sopenharmony_ci		return;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (dev->av_table.av_map)
3738c2ecf20Sopenharmony_ci		iounmap(dev->av_table.av_map);
3748c2ecf20Sopenharmony_ci	dma_pool_destroy(dev->av_table.pool);
3758c2ecf20Sopenharmony_ci	mthca_alloc_cleanup(&dev->av_table.alloc);
3768c2ecf20Sopenharmony_ci}
377