162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2005 Cisco Systems.  All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1062306a36Sopenharmony_ci * OpenIB.org BSD license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1362306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1462306a36Sopenharmony_ci *     conditions are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1762306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1862306a36Sopenharmony_ci *        disclaimer.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2162306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2262306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2362306a36Sopenharmony_ci *        provided with the distribution.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3262306a36Sopenharmony_ci * SOFTWARE.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/mm.h>
3662306a36Sopenharmony_ci#include <linux/scatterlist.h>
3762306a36Sopenharmony_ci#include <linux/sched.h>
3862306a36Sopenharmony_ci#include <linux/slab.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include <asm/page.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include "mthca_memfree.h"
4362306a36Sopenharmony_ci#include "mthca_dev.h"
4462306a36Sopenharmony_ci#include "mthca_cmd.h"
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/*
4762306a36Sopenharmony_ci * We allocate in as big chunks as we can, up to a maximum of 256 KB
4862306a36Sopenharmony_ci * per chunk.
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_cienum {
5162306a36Sopenharmony_ci	MTHCA_ICM_ALLOC_SIZE   = 1 << 18,
5262306a36Sopenharmony_ci	MTHCA_TABLE_CHUNK_SIZE = 1 << 18
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistruct mthca_user_db_table {
5662306a36Sopenharmony_ci	struct mutex mutex;
5762306a36Sopenharmony_ci	struct {
5862306a36Sopenharmony_ci		u64                uvirt;
5962306a36Sopenharmony_ci		struct scatterlist mem;
6062306a36Sopenharmony_ci		int                refcount;
6162306a36Sopenharmony_ci	} page[];
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void mthca_free_icm_pages(struct mthca_dev *dev, struct mthca_icm_chunk *chunk)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	int i;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (chunk->nsg > 0)
6962306a36Sopenharmony_ci		dma_unmap_sg(&dev->pdev->dev, chunk->mem, chunk->npages,
7062306a36Sopenharmony_ci			     DMA_BIDIRECTIONAL);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	for (i = 0; i < chunk->npages; ++i)
7362306a36Sopenharmony_ci		__free_pages(sg_page(&chunk->mem[i]),
7462306a36Sopenharmony_ci			     get_order(chunk->mem[i].length));
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void mthca_free_icm_coherent(struct mthca_dev *dev, struct mthca_icm_chunk *chunk)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	int i;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	for (i = 0; i < chunk->npages; ++i) {
8262306a36Sopenharmony_ci		dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
8362306a36Sopenharmony_ci				  lowmem_page_address(sg_page(&chunk->mem[i])),
8462306a36Sopenharmony_ci				  sg_dma_address(&chunk->mem[i]));
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_civoid mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct mthca_icm_chunk *chunk, *tmp;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (!icm)
9362306a36Sopenharmony_ci		return;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
9662306a36Sopenharmony_ci		if (coherent)
9762306a36Sopenharmony_ci			mthca_free_icm_coherent(dev, chunk);
9862306a36Sopenharmony_ci		else
9962306a36Sopenharmony_ci			mthca_free_icm_pages(dev, chunk);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		kfree(chunk);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	kfree(icm);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct page *page;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * Use __GFP_ZERO because buggy firmware assumes ICM pages are
11362306a36Sopenharmony_ci	 * cleared, and subtle failures are seen if they aren't.
11462306a36Sopenharmony_ci	 */
11562306a36Sopenharmony_ci	page = alloc_pages(gfp_mask | __GFP_ZERO, order);
11662306a36Sopenharmony_ci	if (!page)
11762306a36Sopenharmony_ci		return -ENOMEM;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	sg_set_page(mem, page, PAGE_SIZE << order, 0);
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int mthca_alloc_icm_coherent(struct device *dev, struct scatterlist *mem,
12462306a36Sopenharmony_ci				    int order, gfp_t gfp_mask)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, &sg_dma_address(mem),
12762306a36Sopenharmony_ci				       gfp_mask);
12862306a36Sopenharmony_ci	if (!buf)
12962306a36Sopenharmony_ci		return -ENOMEM;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	sg_set_buf(mem, buf, PAGE_SIZE << order);
13262306a36Sopenharmony_ci	BUG_ON(mem->offset);
13362306a36Sopenharmony_ci	sg_dma_len(mem) = PAGE_SIZE << order;
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistruct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
13862306a36Sopenharmony_ci				  gfp_t gfp_mask, int coherent)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct mthca_icm *icm;
14162306a36Sopenharmony_ci	struct mthca_icm_chunk *chunk = NULL;
14262306a36Sopenharmony_ci	int cur_order;
14362306a36Sopenharmony_ci	int ret;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* We use sg_set_buf for coherent allocs, which assumes low memory */
14662306a36Sopenharmony_ci	BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM));
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
14962306a36Sopenharmony_ci	if (!icm)
15062306a36Sopenharmony_ci		return icm;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	icm->refcount = 0;
15362306a36Sopenharmony_ci	INIT_LIST_HEAD(&icm->chunk_list);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	cur_order = get_order(MTHCA_ICM_ALLOC_SIZE);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	while (npages > 0) {
15862306a36Sopenharmony_ci		if (!chunk) {
15962306a36Sopenharmony_ci			chunk = kmalloc(sizeof *chunk,
16062306a36Sopenharmony_ci					gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
16162306a36Sopenharmony_ci			if (!chunk)
16262306a36Sopenharmony_ci				goto fail;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci			sg_init_table(chunk->mem, MTHCA_ICM_CHUNK_LEN);
16562306a36Sopenharmony_ci			chunk->npages = 0;
16662306a36Sopenharmony_ci			chunk->nsg    = 0;
16762306a36Sopenharmony_ci			list_add_tail(&chunk->list, &icm->chunk_list);
16862306a36Sopenharmony_ci		}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		while (1 << cur_order > npages)
17162306a36Sopenharmony_ci			--cur_order;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		if (coherent)
17462306a36Sopenharmony_ci			ret = mthca_alloc_icm_coherent(&dev->pdev->dev,
17562306a36Sopenharmony_ci						       &chunk->mem[chunk->npages],
17662306a36Sopenharmony_ci						       cur_order, gfp_mask);
17762306a36Sopenharmony_ci		else
17862306a36Sopenharmony_ci			ret = mthca_alloc_icm_pages(&chunk->mem[chunk->npages],
17962306a36Sopenharmony_ci						    cur_order, gfp_mask);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		if (!ret) {
18262306a36Sopenharmony_ci			++chunk->npages;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci			if (coherent)
18562306a36Sopenharmony_ci				++chunk->nsg;
18662306a36Sopenharmony_ci			else if (chunk->npages == MTHCA_ICM_CHUNK_LEN) {
18762306a36Sopenharmony_ci				chunk->nsg =
18862306a36Sopenharmony_ci					dma_map_sg(&dev->pdev->dev, chunk->mem,
18962306a36Sopenharmony_ci						   chunk->npages,
19062306a36Sopenharmony_ci						   DMA_BIDIRECTIONAL);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci				if (chunk->nsg <= 0)
19362306a36Sopenharmony_ci					goto fail;
19462306a36Sopenharmony_ci			}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci			if (chunk->npages == MTHCA_ICM_CHUNK_LEN)
19762306a36Sopenharmony_ci				chunk = NULL;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci			npages -= 1 << cur_order;
20062306a36Sopenharmony_ci		} else {
20162306a36Sopenharmony_ci			--cur_order;
20262306a36Sopenharmony_ci			if (cur_order < 0)
20362306a36Sopenharmony_ci				goto fail;
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (!coherent && chunk) {
20862306a36Sopenharmony_ci		chunk->nsg = dma_map_sg(&dev->pdev->dev, chunk->mem,
20962306a36Sopenharmony_ci					chunk->npages, DMA_BIDIRECTIONAL);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		if (chunk->nsg <= 0)
21262306a36Sopenharmony_ci			goto fail;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return icm;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cifail:
21862306a36Sopenharmony_ci	mthca_free_icm(dev, icm, coherent);
21962306a36Sopenharmony_ci	return NULL;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciint mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
22562306a36Sopenharmony_ci	int ret = 0;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	mutex_lock(&table->mutex);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (table->icm[i]) {
23062306a36Sopenharmony_ci		++table->icm[i]->refcount;
23162306a36Sopenharmony_ci		goto out;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
23562306a36Sopenharmony_ci					(table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
23662306a36Sopenharmony_ci					__GFP_NOWARN, table->coherent);
23762306a36Sopenharmony_ci	if (!table->icm[i]) {
23862306a36Sopenharmony_ci		ret = -ENOMEM;
23962306a36Sopenharmony_ci		goto out;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (mthca_MAP_ICM(dev, table->icm[i],
24362306a36Sopenharmony_ci			  table->virt + i * MTHCA_TABLE_CHUNK_SIZE)) {
24462306a36Sopenharmony_ci		mthca_free_icm(dev, table->icm[i], table->coherent);
24562306a36Sopenharmony_ci		table->icm[i] = NULL;
24662306a36Sopenharmony_ci		ret = -ENOMEM;
24762306a36Sopenharmony_ci		goto out;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	++table->icm[i]->refcount;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ciout:
25362306a36Sopenharmony_ci	mutex_unlock(&table->mutex);
25462306a36Sopenharmony_ci	return ret;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_civoid mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	int i;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
26262306a36Sopenharmony_ci		return;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	mutex_lock(&table->mutex);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (--table->icm[i]->refcount == 0) {
26962306a36Sopenharmony_ci		mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
27062306a36Sopenharmony_ci				MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE);
27162306a36Sopenharmony_ci		mthca_free_icm(dev, table->icm[i], table->coherent);
27262306a36Sopenharmony_ci		table->icm[i] = NULL;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	mutex_unlock(&table->mutex);
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_civoid *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	int idx, offset, dma_offset, i;
28162306a36Sopenharmony_ci	struct mthca_icm_chunk *chunk;
28262306a36Sopenharmony_ci	struct mthca_icm *icm;
28362306a36Sopenharmony_ci	struct page *page = NULL;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (!table->lowmem)
28662306a36Sopenharmony_ci		return NULL;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	mutex_lock(&table->mutex);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	idx = (obj & (table->num_obj - 1)) * table->obj_size;
29162306a36Sopenharmony_ci	icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE];
29262306a36Sopenharmony_ci	dma_offset = offset = idx % MTHCA_TABLE_CHUNK_SIZE;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (!icm)
29562306a36Sopenharmony_ci		goto out;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	list_for_each_entry(chunk, &icm->chunk_list, list) {
29862306a36Sopenharmony_ci		for (i = 0; i < chunk->npages; ++i) {
29962306a36Sopenharmony_ci			if (dma_handle && dma_offset >= 0) {
30062306a36Sopenharmony_ci				if (sg_dma_len(&chunk->mem[i]) > dma_offset)
30162306a36Sopenharmony_ci					*dma_handle = sg_dma_address(&chunk->mem[i]) +
30262306a36Sopenharmony_ci						dma_offset;
30362306a36Sopenharmony_ci				dma_offset -= sg_dma_len(&chunk->mem[i]);
30462306a36Sopenharmony_ci			}
30562306a36Sopenharmony_ci			/* DMA mapping can merge pages but not split them,
30662306a36Sopenharmony_ci			 * so if we found the page, dma_handle has already
30762306a36Sopenharmony_ci			 * been assigned to. */
30862306a36Sopenharmony_ci			if (chunk->mem[i].length > offset) {
30962306a36Sopenharmony_ci				page = sg_page(&chunk->mem[i]);
31062306a36Sopenharmony_ci				goto out;
31162306a36Sopenharmony_ci			}
31262306a36Sopenharmony_ci			offset -= chunk->mem[i].length;
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ciout:
31762306a36Sopenharmony_ci	mutex_unlock(&table->mutex);
31862306a36Sopenharmony_ci	return page ? lowmem_page_address(page) + offset : NULL;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciint mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table,
32262306a36Sopenharmony_ci			  int start, int end)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	int inc = MTHCA_TABLE_CHUNK_SIZE / table->obj_size;
32562306a36Sopenharmony_ci	int i, err;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	for (i = start; i <= end; i += inc) {
32862306a36Sopenharmony_ci		err = mthca_table_get(dev, table, i);
32962306a36Sopenharmony_ci		if (err)
33062306a36Sopenharmony_ci			goto fail;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return 0;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cifail:
33662306a36Sopenharmony_ci	while (i > start) {
33762306a36Sopenharmony_ci		i -= inc;
33862306a36Sopenharmony_ci		mthca_table_put(dev, table, i);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return err;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_civoid mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
34562306a36Sopenharmony_ci			   int start, int end)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int i;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
35062306a36Sopenharmony_ci		return;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
35362306a36Sopenharmony_ci		mthca_table_put(dev, table, i);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistruct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
35762306a36Sopenharmony_ci					      u64 virt, int obj_size,
35862306a36Sopenharmony_ci					      int nobj, int reserved,
35962306a36Sopenharmony_ci					      int use_lowmem, int use_coherent)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct mthca_icm_table *table;
36262306a36Sopenharmony_ci	int obj_per_chunk;
36362306a36Sopenharmony_ci	int num_icm;
36462306a36Sopenharmony_ci	unsigned chunk_size;
36562306a36Sopenharmony_ci	int i;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	obj_per_chunk = MTHCA_TABLE_CHUNK_SIZE / obj_size;
36862306a36Sopenharmony_ci	num_icm = DIV_ROUND_UP(nobj, obj_per_chunk);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	table = kmalloc(struct_size(table, icm, num_icm), GFP_KERNEL);
37162306a36Sopenharmony_ci	if (!table)
37262306a36Sopenharmony_ci		return NULL;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	table->virt     = virt;
37562306a36Sopenharmony_ci	table->num_icm  = num_icm;
37662306a36Sopenharmony_ci	table->num_obj  = nobj;
37762306a36Sopenharmony_ci	table->obj_size = obj_size;
37862306a36Sopenharmony_ci	table->lowmem   = use_lowmem;
37962306a36Sopenharmony_ci	table->coherent = use_coherent;
38062306a36Sopenharmony_ci	mutex_init(&table->mutex);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	for (i = 0; i < num_icm; ++i)
38362306a36Sopenharmony_ci		table->icm[i] = NULL;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	for (i = 0; i * MTHCA_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
38662306a36Sopenharmony_ci		chunk_size = MTHCA_TABLE_CHUNK_SIZE;
38762306a36Sopenharmony_ci		if ((i + 1) * MTHCA_TABLE_CHUNK_SIZE > nobj * obj_size)
38862306a36Sopenharmony_ci			chunk_size = nobj * obj_size - i * MTHCA_TABLE_CHUNK_SIZE;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
39162306a36Sopenharmony_ci						(use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
39262306a36Sopenharmony_ci						__GFP_NOWARN, use_coherent);
39362306a36Sopenharmony_ci		if (!table->icm[i])
39462306a36Sopenharmony_ci			goto err;
39562306a36Sopenharmony_ci		if (mthca_MAP_ICM(dev, table->icm[i],
39662306a36Sopenharmony_ci				  virt + i * MTHCA_TABLE_CHUNK_SIZE)) {
39762306a36Sopenharmony_ci			mthca_free_icm(dev, table->icm[i], table->coherent);
39862306a36Sopenharmony_ci			table->icm[i] = NULL;
39962306a36Sopenharmony_ci			goto err;
40062306a36Sopenharmony_ci		}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		/*
40362306a36Sopenharmony_ci		 * Add a reference to this ICM chunk so that it never
40462306a36Sopenharmony_ci		 * gets freed (since it contains reserved firmware objects).
40562306a36Sopenharmony_ci		 */
40662306a36Sopenharmony_ci		++table->icm[i]->refcount;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return table;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cierr:
41262306a36Sopenharmony_ci	for (i = 0; i < num_icm; ++i)
41362306a36Sopenharmony_ci		if (table->icm[i]) {
41462306a36Sopenharmony_ci			mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE,
41562306a36Sopenharmony_ci					MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE);
41662306a36Sopenharmony_ci			mthca_free_icm(dev, table->icm[i], table->coherent);
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	kfree(table);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	return NULL;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_civoid mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	int i;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	for (i = 0; i < table->num_icm; ++i)
42962306a36Sopenharmony_ci		if (table->icm[i]) {
43062306a36Sopenharmony_ci			mthca_UNMAP_ICM(dev,
43162306a36Sopenharmony_ci					table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
43262306a36Sopenharmony_ci					MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE);
43362306a36Sopenharmony_ci			mthca_free_icm(dev, table->icm[i], table->coherent);
43462306a36Sopenharmony_ci		}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	kfree(table);
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	return dev->uar_table.uarc_base +
44262306a36Sopenharmony_ci		uar->index * dev->uar_table.uarc_size +
44362306a36Sopenharmony_ci		page * MTHCA_ICM_PAGE_SIZE;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ciint mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
44762306a36Sopenharmony_ci		      struct mthca_user_db_table *db_tab, int index, u64 uaddr)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct page *pages[1];
45062306a36Sopenharmony_ci	int ret = 0;
45162306a36Sopenharmony_ci	int i;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
45462306a36Sopenharmony_ci		return 0;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (index < 0 || index > dev->uar_table.uarc_size / 8)
45762306a36Sopenharmony_ci		return -EINVAL;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	mutex_lock(&db_tab->mutex);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	i = index / MTHCA_DB_REC_PER_PAGE;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE)       ||
46462306a36Sopenharmony_ci	    (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) ||
46562306a36Sopenharmony_ci	    (uaddr & 4095)) {
46662306a36Sopenharmony_ci		ret = -EINVAL;
46762306a36Sopenharmony_ci		goto out;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (db_tab->page[i].refcount) {
47162306a36Sopenharmony_ci		++db_tab->page[i].refcount;
47262306a36Sopenharmony_ci		goto out;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	ret = pin_user_pages_fast(uaddr & PAGE_MASK, 1,
47662306a36Sopenharmony_ci				  FOLL_WRITE | FOLL_LONGTERM, pages);
47762306a36Sopenharmony_ci	if (ret < 0)
47862306a36Sopenharmony_ci		goto out;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	sg_set_page(&db_tab->page[i].mem, pages[0], MTHCA_ICM_PAGE_SIZE,
48162306a36Sopenharmony_ci			uaddr & ~PAGE_MASK);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	ret = dma_map_sg(&dev->pdev->dev, &db_tab->page[i].mem, 1,
48462306a36Sopenharmony_ci			 DMA_TO_DEVICE);
48562306a36Sopenharmony_ci	if (ret < 0) {
48662306a36Sopenharmony_ci		unpin_user_page(pages[0]);
48762306a36Sopenharmony_ci		goto out;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem),
49162306a36Sopenharmony_ci				 mthca_uarc_virt(dev, uar, i));
49262306a36Sopenharmony_ci	if (ret) {
49362306a36Sopenharmony_ci		dma_unmap_sg(&dev->pdev->dev, &db_tab->page[i].mem, 1,
49462306a36Sopenharmony_ci			     DMA_TO_DEVICE);
49562306a36Sopenharmony_ci		unpin_user_page(sg_page(&db_tab->page[i].mem));
49662306a36Sopenharmony_ci		goto out;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	db_tab->page[i].uvirt    = uaddr;
50062306a36Sopenharmony_ci	db_tab->page[i].refcount = 1;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciout:
50362306a36Sopenharmony_ci	mutex_unlock(&db_tab->mutex);
50462306a36Sopenharmony_ci	return ret;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_civoid mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
50862306a36Sopenharmony_ci			 struct mthca_user_db_table *db_tab, int index)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
51162306a36Sopenharmony_ci		return;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/*
51462306a36Sopenharmony_ci	 * To make our bookkeeping simpler, we don't unmap DB
51562306a36Sopenharmony_ci	 * pages until we clean up the whole db table.
51662306a36Sopenharmony_ci	 */
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	mutex_lock(&db_tab->mutex);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	--db_tab->page[index / MTHCA_DB_REC_PER_PAGE].refcount;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	mutex_unlock(&db_tab->mutex);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistruct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct mthca_user_db_table *db_tab;
52862306a36Sopenharmony_ci	int npages;
52962306a36Sopenharmony_ci	int i;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
53262306a36Sopenharmony_ci		return NULL;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
53562306a36Sopenharmony_ci	db_tab = kmalloc(struct_size(db_tab, page, npages), GFP_KERNEL);
53662306a36Sopenharmony_ci	if (!db_tab)
53762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	mutex_init(&db_tab->mutex);
54062306a36Sopenharmony_ci	for (i = 0; i < npages; ++i) {
54162306a36Sopenharmony_ci		db_tab->page[i].refcount = 0;
54262306a36Sopenharmony_ci		db_tab->page[i].uvirt    = 0;
54362306a36Sopenharmony_ci		sg_init_table(&db_tab->page[i].mem, 1);
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return db_tab;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_civoid mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
55062306a36Sopenharmony_ci			       struct mthca_user_db_table *db_tab)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	int i;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
55562306a36Sopenharmony_ci		return;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	for (i = 0; i < dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; ++i) {
55862306a36Sopenharmony_ci		if (db_tab->page[i].uvirt) {
55962306a36Sopenharmony_ci			mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1);
56062306a36Sopenharmony_ci			dma_unmap_sg(&dev->pdev->dev, &db_tab->page[i].mem, 1,
56162306a36Sopenharmony_ci				     DMA_TO_DEVICE);
56262306a36Sopenharmony_ci			unpin_user_page(sg_page(&db_tab->page[i].mem));
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	kfree(db_tab);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ciint mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type,
57062306a36Sopenharmony_ci		   u32 qn, __be32 **db)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	int group;
57362306a36Sopenharmony_ci	int start, end, dir;
57462306a36Sopenharmony_ci	int i, j;
57562306a36Sopenharmony_ci	struct mthca_db_page *page;
57662306a36Sopenharmony_ci	int ret = 0;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	mutex_lock(&dev->db_tab->mutex);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	switch (type) {
58162306a36Sopenharmony_ci	case MTHCA_DB_TYPE_CQ_ARM:
58262306a36Sopenharmony_ci	case MTHCA_DB_TYPE_SQ:
58362306a36Sopenharmony_ci		group = 0;
58462306a36Sopenharmony_ci		start = 0;
58562306a36Sopenharmony_ci		end   = dev->db_tab->max_group1;
58662306a36Sopenharmony_ci		dir   = 1;
58762306a36Sopenharmony_ci		break;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	case MTHCA_DB_TYPE_CQ_SET_CI:
59062306a36Sopenharmony_ci	case MTHCA_DB_TYPE_RQ:
59162306a36Sopenharmony_ci	case MTHCA_DB_TYPE_SRQ:
59262306a36Sopenharmony_ci		group = 1;
59362306a36Sopenharmony_ci		start = dev->db_tab->npages - 1;
59462306a36Sopenharmony_ci		end   = dev->db_tab->min_group2;
59562306a36Sopenharmony_ci		dir   = -1;
59662306a36Sopenharmony_ci		break;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	default:
59962306a36Sopenharmony_ci		ret = -EINVAL;
60062306a36Sopenharmony_ci		goto out;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	for (i = start; i != end; i += dir)
60462306a36Sopenharmony_ci		if (dev->db_tab->page[i].db_rec &&
60562306a36Sopenharmony_ci		    !bitmap_full(dev->db_tab->page[i].used,
60662306a36Sopenharmony_ci				 MTHCA_DB_REC_PER_PAGE)) {
60762306a36Sopenharmony_ci			page = dev->db_tab->page + i;
60862306a36Sopenharmony_ci			goto found;
60962306a36Sopenharmony_ci		}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	for (i = start; i != end; i += dir)
61262306a36Sopenharmony_ci		if (!dev->db_tab->page[i].db_rec) {
61362306a36Sopenharmony_ci			page = dev->db_tab->page + i;
61462306a36Sopenharmony_ci			goto alloc;
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (dev->db_tab->max_group1 >= dev->db_tab->min_group2 - 1) {
61862306a36Sopenharmony_ci		ret = -ENOMEM;
61962306a36Sopenharmony_ci		goto out;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (group == 0)
62362306a36Sopenharmony_ci		++dev->db_tab->max_group1;
62462306a36Sopenharmony_ci	else
62562306a36Sopenharmony_ci		--dev->db_tab->min_group2;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	page = dev->db_tab->page + end;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cialloc:
63062306a36Sopenharmony_ci	page->db_rec = dma_alloc_coherent(&dev->pdev->dev,
63162306a36Sopenharmony_ci					  MTHCA_ICM_PAGE_SIZE, &page->mapping,
63262306a36Sopenharmony_ci					  GFP_KERNEL);
63362306a36Sopenharmony_ci	if (!page->db_rec) {
63462306a36Sopenharmony_ci		ret = -ENOMEM;
63562306a36Sopenharmony_ci		goto out;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	ret = mthca_MAP_ICM_page(dev, page->mapping,
63962306a36Sopenharmony_ci				 mthca_uarc_virt(dev, &dev->driver_uar, i));
64062306a36Sopenharmony_ci	if (ret) {
64162306a36Sopenharmony_ci		dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
64262306a36Sopenharmony_ci				  page->db_rec, page->mapping);
64362306a36Sopenharmony_ci		goto out;
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	bitmap_zero(page->used, MTHCA_DB_REC_PER_PAGE);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cifound:
64962306a36Sopenharmony_ci	j = find_first_zero_bit(page->used, MTHCA_DB_REC_PER_PAGE);
65062306a36Sopenharmony_ci	set_bit(j, page->used);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (group == 1)
65362306a36Sopenharmony_ci		j = MTHCA_DB_REC_PER_PAGE - 1 - j;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	ret = i * MTHCA_DB_REC_PER_PAGE + j;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	page->db_rec[j] = cpu_to_be64((qn << 8) | (type << 5));
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	*db = (__be32 *) &page->db_rec[j];
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ciout:
66262306a36Sopenharmony_ci	mutex_unlock(&dev->db_tab->mutex);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return ret;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_civoid mthca_free_db(struct mthca_dev *dev, int type, int db_index)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	int i, j;
67062306a36Sopenharmony_ci	struct mthca_db_page *page;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	i = db_index / MTHCA_DB_REC_PER_PAGE;
67362306a36Sopenharmony_ci	j = db_index % MTHCA_DB_REC_PER_PAGE;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	page = dev->db_tab->page + i;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	mutex_lock(&dev->db_tab->mutex);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	page->db_rec[j] = 0;
68062306a36Sopenharmony_ci	if (i >= dev->db_tab->min_group2)
68162306a36Sopenharmony_ci		j = MTHCA_DB_REC_PER_PAGE - 1 - j;
68262306a36Sopenharmony_ci	clear_bit(j, page->used);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) &&
68562306a36Sopenharmony_ci	    i >= dev->db_tab->max_group1 - 1) {
68662306a36Sopenharmony_ci		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
68962306a36Sopenharmony_ci				  page->db_rec, page->mapping);
69062306a36Sopenharmony_ci		page->db_rec = NULL;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		if (i == dev->db_tab->max_group1) {
69362306a36Sopenharmony_ci			--dev->db_tab->max_group1;
69462306a36Sopenharmony_ci			/* XXX may be able to unmap more pages now */
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci		if (i == dev->db_tab->min_group2)
69762306a36Sopenharmony_ci			++dev->db_tab->min_group2;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	mutex_unlock(&dev->db_tab->mutex);
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ciint mthca_init_db_tab(struct mthca_dev *dev)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	int i;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
70862306a36Sopenharmony_ci		return 0;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	dev->db_tab = kmalloc(sizeof *dev->db_tab, GFP_KERNEL);
71162306a36Sopenharmony_ci	if (!dev->db_tab)
71262306a36Sopenharmony_ci		return -ENOMEM;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	mutex_init(&dev->db_tab->mutex);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	dev->db_tab->npages     = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
71762306a36Sopenharmony_ci	dev->db_tab->max_group1 = 0;
71862306a36Sopenharmony_ci	dev->db_tab->min_group2 = dev->db_tab->npages - 1;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	dev->db_tab->page = kmalloc_array(dev->db_tab->npages,
72162306a36Sopenharmony_ci					  sizeof(*dev->db_tab->page),
72262306a36Sopenharmony_ci					  GFP_KERNEL);
72362306a36Sopenharmony_ci	if (!dev->db_tab->page) {
72462306a36Sopenharmony_ci		kfree(dev->db_tab);
72562306a36Sopenharmony_ci		return -ENOMEM;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	for (i = 0; i < dev->db_tab->npages; ++i)
72962306a36Sopenharmony_ci		dev->db_tab->page[i].db_rec = NULL;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return 0;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_civoid mthca_cleanup_db_tab(struct mthca_dev *dev)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	int i;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (!mthca_is_memfree(dev))
73962306a36Sopenharmony_ci		return;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/*
74262306a36Sopenharmony_ci	 * Because we don't always free our UARC pages when they
74362306a36Sopenharmony_ci	 * become empty to make mthca_free_db() simpler we need to
74462306a36Sopenharmony_ci	 * make a sweep through the doorbell pages and free any
74562306a36Sopenharmony_ci	 * leftover pages now.
74662306a36Sopenharmony_ci	 */
74762306a36Sopenharmony_ci	for (i = 0; i < dev->db_tab->npages; ++i) {
74862306a36Sopenharmony_ci		if (!dev->db_tab->page[i].db_rec)
74962306a36Sopenharmony_ci			continue;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE))
75262306a36Sopenharmony_ci			mthca_warn(dev, "Kernel UARC page %d not empty\n", i);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci		dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
75762306a36Sopenharmony_ci				  dev->db_tab->page[i].db_rec,
75862306a36Sopenharmony_ci				  dev->db_tab->page[i].mapping);
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	kfree(dev->db_tab->page);
76262306a36Sopenharmony_ci	kfree(dev->db_tab);
76362306a36Sopenharmony_ci}
764