162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004 Topspin Communications.  All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This software is available to you under a choice of one of two
662306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
762306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
862306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
962306a36Sopenharmony_ci * OpenIB.org BSD license below:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1262306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1362306a36Sopenharmony_ci *     conditions are met:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1662306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1762306a36Sopenharmony_ci *        disclaimer.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2062306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2162306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2262306a36Sopenharmony_ci *        provided with the distribution.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2562306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2662306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2762306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2862306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2962306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3062306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3162306a36Sopenharmony_ci * SOFTWARE.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <linux/string.h>
3562306a36Sopenharmony_ci#include <linux/slab.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <rdma/ib_verbs.h>
3862306a36Sopenharmony_ci#include <rdma/ib_cache.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "mthca_dev.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cienum {
4362306a36Sopenharmony_ci      MTHCA_RATE_TAVOR_FULL   = 0,
4462306a36Sopenharmony_ci      MTHCA_RATE_TAVOR_1X     = 1,
4562306a36Sopenharmony_ci      MTHCA_RATE_TAVOR_4X     = 2,
4662306a36Sopenharmony_ci      MTHCA_RATE_TAVOR_1X_DDR = 3
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cienum {
5062306a36Sopenharmony_ci      MTHCA_RATE_MEMFREE_FULL    = 0,
5162306a36Sopenharmony_ci      MTHCA_RATE_MEMFREE_QUARTER = 1,
5262306a36Sopenharmony_ci      MTHCA_RATE_MEMFREE_EIGHTH  = 2,
5362306a36Sopenharmony_ci      MTHCA_RATE_MEMFREE_HALF    = 3
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct mthca_av {
5762306a36Sopenharmony_ci	__be32 port_pd;
5862306a36Sopenharmony_ci	u8     reserved1;
5962306a36Sopenharmony_ci	u8     g_slid;
6062306a36Sopenharmony_ci	__be16 dlid;
6162306a36Sopenharmony_ci	u8     reserved2;
6262306a36Sopenharmony_ci	u8     gid_index;
6362306a36Sopenharmony_ci	u8     msg_sr;
6462306a36Sopenharmony_ci	u8     hop_limit;
6562306a36Sopenharmony_ci	__be32 sl_tclass_flowlabel;
6662306a36Sopenharmony_ci	__be32 dgid[4];
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic enum ib_rate memfree_rate_to_ib(u8 mthca_rate, u8 port_rate)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	switch (mthca_rate) {
7262306a36Sopenharmony_ci	case MTHCA_RATE_MEMFREE_EIGHTH:
7362306a36Sopenharmony_ci		return mult_to_ib_rate(port_rate >> 3);
7462306a36Sopenharmony_ci	case MTHCA_RATE_MEMFREE_QUARTER:
7562306a36Sopenharmony_ci		return mult_to_ib_rate(port_rate >> 2);
7662306a36Sopenharmony_ci	case MTHCA_RATE_MEMFREE_HALF:
7762306a36Sopenharmony_ci		return mult_to_ib_rate(port_rate >> 1);
7862306a36Sopenharmony_ci	case MTHCA_RATE_MEMFREE_FULL:
7962306a36Sopenharmony_ci	default:
8062306a36Sopenharmony_ci		return mult_to_ib_rate(port_rate);
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic enum ib_rate tavor_rate_to_ib(u8 mthca_rate, u8 port_rate)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	switch (mthca_rate) {
8762306a36Sopenharmony_ci	case MTHCA_RATE_TAVOR_1X:     return IB_RATE_2_5_GBPS;
8862306a36Sopenharmony_ci	case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS;
8962306a36Sopenharmony_ci	case MTHCA_RATE_TAVOR_4X:     return IB_RATE_10_GBPS;
9062306a36Sopenharmony_ci	default:		      return mult_to_ib_rate(port_rate);
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cienum ib_rate mthca_rate_to_ib(struct mthca_dev *dev, u8 mthca_rate, u32 port)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	if (mthca_is_memfree(dev)) {
9762306a36Sopenharmony_ci		/* Handle old Arbel FW */
9862306a36Sopenharmony_ci		if (dev->limits.stat_rate_support == 0x3 && mthca_rate)
9962306a36Sopenharmony_ci			return IB_RATE_2_5_GBPS;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		return memfree_rate_to_ib(mthca_rate, dev->rate[port - 1]);
10262306a36Sopenharmony_ci	} else
10362306a36Sopenharmony_ci		return tavor_rate_to_ib(mthca_rate, dev->rate[port - 1]);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic u8 ib_rate_to_memfree(u8 req_rate, u8 cur_rate)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	if (cur_rate <= req_rate)
10962306a36Sopenharmony_ci		return 0;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * Inter-packet delay (IPD) to get from rate X down to a rate
11362306a36Sopenharmony_ci	 * no more than Y is (X - 1) / Y.
11462306a36Sopenharmony_ci	 */
11562306a36Sopenharmony_ci	switch ((cur_rate - 1) / req_rate) {
11662306a36Sopenharmony_ci	case 0:	 return MTHCA_RATE_MEMFREE_FULL;
11762306a36Sopenharmony_ci	case 1:	 return MTHCA_RATE_MEMFREE_HALF;
11862306a36Sopenharmony_ci	case 2:
11962306a36Sopenharmony_ci	case 3:	 return MTHCA_RATE_MEMFREE_QUARTER;
12062306a36Sopenharmony_ci	default: return MTHCA_RATE_MEMFREE_EIGHTH;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic u8 ib_rate_to_tavor(u8 static_rate)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	switch (static_rate) {
12762306a36Sopenharmony_ci	case IB_RATE_2_5_GBPS: return MTHCA_RATE_TAVOR_1X;
12862306a36Sopenharmony_ci	case IB_RATE_5_GBPS:   return MTHCA_RATE_TAVOR_1X_DDR;
12962306a36Sopenharmony_ci	case IB_RATE_10_GBPS:  return MTHCA_RATE_TAVOR_4X;
13062306a36Sopenharmony_ci	default:	       return MTHCA_RATE_TAVOR_FULL;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciu8 mthca_get_rate(struct mthca_dev *dev, int static_rate, u32 port)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	u8 rate;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (!static_rate || ib_rate_to_mult(static_rate) >= dev->rate[port - 1])
13962306a36Sopenharmony_ci		return 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (mthca_is_memfree(dev))
14262306a36Sopenharmony_ci		rate = ib_rate_to_memfree(ib_rate_to_mult(static_rate),
14362306a36Sopenharmony_ci					  dev->rate[port - 1]);
14462306a36Sopenharmony_ci	else
14562306a36Sopenharmony_ci		rate = ib_rate_to_tavor(static_rate);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (!(dev->limits.stat_rate_support & (1 << rate)))
14862306a36Sopenharmony_ci		rate = 1;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return rate;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciint mthca_create_ah(struct mthca_dev *dev,
15462306a36Sopenharmony_ci		    struct mthca_pd *pd,
15562306a36Sopenharmony_ci		    struct rdma_ah_attr *ah_attr,
15662306a36Sopenharmony_ci		    struct mthca_ah *ah)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	u32 index = -1;
15962306a36Sopenharmony_ci	struct mthca_av *av = NULL;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	ah->type = MTHCA_AH_PCI_POOL;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (mthca_is_memfree(dev)) {
16462306a36Sopenharmony_ci		ah->av   = kmalloc(sizeof *ah->av, GFP_ATOMIC);
16562306a36Sopenharmony_ci		if (!ah->av)
16662306a36Sopenharmony_ci			return -ENOMEM;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		ah->type = MTHCA_AH_KMALLOC;
16962306a36Sopenharmony_ci		av       = ah->av;
17062306a36Sopenharmony_ci	} else if (!atomic_read(&pd->sqp_count) &&
17162306a36Sopenharmony_ci		 !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
17262306a36Sopenharmony_ci		index = mthca_alloc(&dev->av_table.alloc);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		/* fall back to allocate in host memory */
17562306a36Sopenharmony_ci		if (index == -1)
17662306a36Sopenharmony_ci			goto on_hca_fail;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		av = kmalloc(sizeof *av, GFP_ATOMIC);
17962306a36Sopenharmony_ci		if (!av)
18062306a36Sopenharmony_ci			goto on_hca_fail;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		ah->type = MTHCA_AH_ON_HCA;
18362306a36Sopenharmony_ci		ah->avdma  = dev->av_table.ddr_av_base +
18462306a36Sopenharmony_ci			index * MTHCA_AV_SIZE;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cion_hca_fail:
18862306a36Sopenharmony_ci	if (ah->type == MTHCA_AH_PCI_POOL) {
18962306a36Sopenharmony_ci		ah->av = dma_pool_zalloc(dev->av_table.pool,
19062306a36Sopenharmony_ci					 GFP_ATOMIC, &ah->avdma);
19162306a36Sopenharmony_ci		if (!ah->av)
19262306a36Sopenharmony_ci			return -ENOMEM;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		av = ah->av;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	ah->key = pd->ntmr.ibmr.lkey;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	av->port_pd = cpu_to_be32(pd->pd_num |
20062306a36Sopenharmony_ci				  (rdma_ah_get_port_num(ah_attr) << 24));
20162306a36Sopenharmony_ci	av->g_slid  = rdma_ah_get_path_bits(ah_attr);
20262306a36Sopenharmony_ci	av->dlid    = cpu_to_be16(rdma_ah_get_dlid(ah_attr));
20362306a36Sopenharmony_ci	av->msg_sr  = (3 << 4) | /* 2K message */
20462306a36Sopenharmony_ci		mthca_get_rate(dev, rdma_ah_get_static_rate(ah_attr),
20562306a36Sopenharmony_ci			       rdma_ah_get_port_num(ah_attr));
20662306a36Sopenharmony_ci	av->sl_tclass_flowlabel = cpu_to_be32(rdma_ah_get_sl(ah_attr) << 28);
20762306a36Sopenharmony_ci	if (rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) {
20862306a36Sopenharmony_ci		const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		av->g_slid |= 0x80;
21162306a36Sopenharmony_ci		av->gid_index = (rdma_ah_get_port_num(ah_attr) - 1) *
21262306a36Sopenharmony_ci				  dev->limits.gid_table_len +
21362306a36Sopenharmony_ci				  grh->sgid_index;
21462306a36Sopenharmony_ci		av->hop_limit = grh->hop_limit;
21562306a36Sopenharmony_ci		av->sl_tclass_flowlabel |=
21662306a36Sopenharmony_ci			cpu_to_be32((grh->traffic_class << 20) |
21762306a36Sopenharmony_ci				    grh->flow_label);
21862306a36Sopenharmony_ci		memcpy(av->dgid, grh->dgid.raw, 16);
21962306a36Sopenharmony_ci	} else {
22062306a36Sopenharmony_ci		/* Arbel workaround -- low byte of GID must be 2 */
22162306a36Sopenharmony_ci		av->dgid[3] = cpu_to_be32(2);
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (0) {
22562306a36Sopenharmony_ci		int j;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		mthca_dbg(dev, "Created UDAV at %p/%08lx:\n",
22862306a36Sopenharmony_ci			  av, (unsigned long) ah->avdma);
22962306a36Sopenharmony_ci		for (j = 0; j < 8; ++j)
23062306a36Sopenharmony_ci			printk(KERN_DEBUG "  [%2x] %08x\n",
23162306a36Sopenharmony_ci			       j * 4, be32_to_cpu(((__be32 *) av)[j]));
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (ah->type == MTHCA_AH_ON_HCA) {
23562306a36Sopenharmony_ci		memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE,
23662306a36Sopenharmony_ci			    av, MTHCA_AV_SIZE);
23762306a36Sopenharmony_ci		kfree(av);
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	return 0;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ciint mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	switch (ah->type) {
24662306a36Sopenharmony_ci	case MTHCA_AH_ON_HCA:
24762306a36Sopenharmony_ci		mthca_free(&dev->av_table.alloc,
24862306a36Sopenharmony_ci			   (ah->avdma - dev->av_table.ddr_av_base) /
24962306a36Sopenharmony_ci			   MTHCA_AV_SIZE);
25062306a36Sopenharmony_ci		break;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	case MTHCA_AH_PCI_POOL:
25362306a36Sopenharmony_ci		dma_pool_free(dev->av_table.pool, ah->av, ah->avdma);
25462306a36Sopenharmony_ci		break;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	case MTHCA_AH_KMALLOC:
25762306a36Sopenharmony_ci		kfree(ah->av);
25862306a36Sopenharmony_ci		break;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ciint mthca_ah_grh_present(struct mthca_ah *ah)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	return !!(ah->av->g_slid & 0x80);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ciint mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
27062306a36Sopenharmony_ci		  struct ib_ud_header *header)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	if (ah->type == MTHCA_AH_ON_HCA)
27362306a36Sopenharmony_ci		return -EINVAL;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	header->lrh.service_level   = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
27662306a36Sopenharmony_ci	header->lrh.destination_lid = ah->av->dlid;
27762306a36Sopenharmony_ci	header->lrh.source_lid      = cpu_to_be16(ah->av->g_slid & 0x7f);
27862306a36Sopenharmony_ci	if (mthca_ah_grh_present(ah)) {
27962306a36Sopenharmony_ci		header->grh.traffic_class =
28062306a36Sopenharmony_ci			(be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff;
28162306a36Sopenharmony_ci		header->grh.flow_label    =
28262306a36Sopenharmony_ci			ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff);
28362306a36Sopenharmony_ci		header->grh.hop_limit     = ah->av->hop_limit;
28462306a36Sopenharmony_ci		header->grh.source_gid = ah->ibah.sgid_attr->gid;
28562306a36Sopenharmony_ci		memcpy(header->grh.destination_gid.raw,
28662306a36Sopenharmony_ci		       ah->av->dgid, 16);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return 0;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ciint mthca_ah_query(struct ib_ah *ibah, struct rdma_ah_attr *attr)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct mthca_ah *ah   = to_mah(ibah);
29562306a36Sopenharmony_ci	struct mthca_dev *dev = to_mdev(ibah->device);
29662306a36Sopenharmony_ci	u32 port_num = be32_to_cpu(ah->av->port_pd) >> 24;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Only implement for MAD and memfree ah for now. */
29962306a36Sopenharmony_ci	if (ah->type == MTHCA_AH_ON_HCA)
30062306a36Sopenharmony_ci		return -ENOSYS;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	memset(attr, 0, sizeof *attr);
30362306a36Sopenharmony_ci	attr->type = ibah->type;
30462306a36Sopenharmony_ci	rdma_ah_set_dlid(attr, be16_to_cpu(ah->av->dlid));
30562306a36Sopenharmony_ci	rdma_ah_set_sl(attr, be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28);
30662306a36Sopenharmony_ci	rdma_ah_set_port_num(attr, port_num);
30762306a36Sopenharmony_ci	rdma_ah_set_static_rate(attr,
30862306a36Sopenharmony_ci				mthca_rate_to_ib(dev, ah->av->msg_sr & 0x7,
30962306a36Sopenharmony_ci						 port_num));
31062306a36Sopenharmony_ci	rdma_ah_set_path_bits(attr, ah->av->g_slid & 0x7F);
31162306a36Sopenharmony_ci	if (mthca_ah_grh_present(ah)) {
31262306a36Sopenharmony_ci		u32 tc_fl = be32_to_cpu(ah->av->sl_tclass_flowlabel);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		rdma_ah_set_grh(attr, NULL,
31562306a36Sopenharmony_ci				tc_fl & 0xfffff,
31662306a36Sopenharmony_ci				ah->av->gid_index &
31762306a36Sopenharmony_ci				(dev->limits.gid_table_len - 1),
31862306a36Sopenharmony_ci				ah->av->hop_limit,
31962306a36Sopenharmony_ci				(tc_fl >> 20) & 0xff);
32062306a36Sopenharmony_ci		rdma_ah_set_dgid_raw(attr, ah->av->dgid);
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciint mthca_init_av_table(struct mthca_dev *dev)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	int err;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (mthca_is_memfree(dev))
33162306a36Sopenharmony_ci		return 0;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	err = mthca_alloc_init(&dev->av_table.alloc,
33462306a36Sopenharmony_ci			       dev->av_table.num_ddr_avs,
33562306a36Sopenharmony_ci			       dev->av_table.num_ddr_avs - 1,
33662306a36Sopenharmony_ci			       0);
33762306a36Sopenharmony_ci	if (err)
33862306a36Sopenharmony_ci		return err;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	dev->av_table.pool = dma_pool_create("mthca_av", &dev->pdev->dev,
34162306a36Sopenharmony_ci					     MTHCA_AV_SIZE,
34262306a36Sopenharmony_ci					     MTHCA_AV_SIZE, 0);
34362306a36Sopenharmony_ci	if (!dev->av_table.pool)
34462306a36Sopenharmony_ci		goto out_free_alloc;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) {
34762306a36Sopenharmony_ci		dev->av_table.av_map = ioremap(pci_resource_start(dev->pdev, 4) +
34862306a36Sopenharmony_ci					       dev->av_table.ddr_av_base -
34962306a36Sopenharmony_ci					       dev->ddr_start,
35062306a36Sopenharmony_ci					       dev->av_table.num_ddr_avs *
35162306a36Sopenharmony_ci					       MTHCA_AV_SIZE);
35262306a36Sopenharmony_ci		if (!dev->av_table.av_map)
35362306a36Sopenharmony_ci			goto out_free_pool;
35462306a36Sopenharmony_ci	} else
35562306a36Sopenharmony_ci		dev->av_table.av_map = NULL;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return 0;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci out_free_pool:
36062306a36Sopenharmony_ci	dma_pool_destroy(dev->av_table.pool);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci out_free_alloc:
36362306a36Sopenharmony_ci	mthca_alloc_cleanup(&dev->av_table.alloc);
36462306a36Sopenharmony_ci	return -ENOMEM;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_civoid mthca_cleanup_av_table(struct mthca_dev *dev)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	if (mthca_is_memfree(dev))
37062306a36Sopenharmony_ci		return;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (dev->av_table.av_map)
37362306a36Sopenharmony_ci		iounmap(dev->av_table.av_map);
37462306a36Sopenharmony_ci	dma_pool_destroy(dev->av_table.pool);
37562306a36Sopenharmony_ci	mthca_alloc_cleanup(&dev->av_table.alloc);
37662306a36Sopenharmony_ci}
377