1322810Shselasky/*-
2322810Shselasky * Copyright (c) 2013-2015, Mellanox Technologies, Ltd.  All rights reserved.
3322810Shselasky *
4322810Shselasky * Redistribution and use in source and binary forms, with or without
5322810Shselasky * modification, are permitted provided that the following conditions
6322810Shselasky * are met:
7322810Shselasky * 1. Redistributions of source code must retain the above copyright
8322810Shselasky *    notice, this list of conditions and the following disclaimer.
9322810Shselasky * 2. Redistributions in binary form must reproduce the above copyright
10322810Shselasky *    notice, this list of conditions and the following disclaimer in the
11322810Shselasky *    documentation and/or other materials provided with the distribution.
12322810Shselasky *
13322810Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14322810Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15322810Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16322810Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17322810Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18322810Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19322810Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20322810Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21322810Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22322810Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23322810Shselasky * SUCH DAMAGE.
24322810Shselasky *
25322810Shselasky * $FreeBSD: stable/11/sys/dev/mlx5/mlx5_ib/mlx5_ib_doorbell.c 331769 2018-03-30 18:06:29Z hselasky $
26322810Shselasky */
27322810Shselasky
28322810Shselasky#include <linux/kref.h>
29322810Shselasky#include <linux/slab.h>
30322810Shselasky#include <rdma/ib_umem.h>
31322810Shselasky
32322810Shselasky#include "mlx5_ib.h"
33322810Shselasky
34322810Shselaskystruct mlx5_ib_user_db_page {
35322810Shselasky	struct list_head	list;
36322810Shselasky	struct ib_umem	       *umem;
37331769Shselasky	unsigned long		user_virt;
38322810Shselasky	int			refcnt;
39322810Shselasky};
40322810Shselasky
41331769Shselaskyint mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
42322810Shselasky			struct mlx5_db *db)
43322810Shselasky{
44322810Shselasky	struct mlx5_ib_user_db_page *page;
45322810Shselasky	int err = 0;
46322810Shselasky
47322810Shselasky	mutex_lock(&context->db_page_mutex);
48322810Shselasky
49322810Shselasky	list_for_each_entry(page, &context->db_page_list, list)
50322810Shselasky		if (page->user_virt == (virt & PAGE_MASK))
51322810Shselasky			goto found;
52322810Shselasky
53322810Shselasky	page = kmalloc(sizeof(*page), GFP_KERNEL);
54322810Shselasky	if (!page) {
55322810Shselasky		err = -ENOMEM;
56322810Shselasky		goto out;
57322810Shselasky	}
58322810Shselasky
59322810Shselasky	page->user_virt = (virt & PAGE_MASK);
60322810Shselasky	page->refcnt    = 0;
61322810Shselasky	page->umem      = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
62322810Shselasky				      PAGE_SIZE, 0, 0);
63322810Shselasky	if (IS_ERR(page->umem)) {
64322810Shselasky		err = PTR_ERR(page->umem);
65322810Shselasky		kfree(page);
66322810Shselasky		goto out;
67322810Shselasky	}
68322810Shselasky
69322810Shselasky	list_add(&page->list, &context->db_page_list);
70322810Shselasky
71322810Shselaskyfound:
72322810Shselasky	db->dma = sg_dma_address(page->umem->sg_head.sgl) + (virt & ~PAGE_MASK);
73322810Shselasky	db->u.user_page = page;
74322810Shselasky	++page->refcnt;
75322810Shselasky
76322810Shselaskyout:
77322810Shselasky	mutex_unlock(&context->db_page_mutex);
78322810Shselasky
79322810Shselasky	return err;
80322810Shselasky}
81322810Shselasky
82322810Shselaskyvoid mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db)
83322810Shselasky{
84322810Shselasky	mutex_lock(&context->db_page_mutex);
85322810Shselasky
86322810Shselasky	if (!--db->u.user_page->refcnt) {
87322810Shselasky		list_del(&db->u.user_page->list);
88322810Shselasky		ib_umem_release(db->u.user_page->umem);
89322810Shselasky		kfree(db->u.user_page);
90322810Shselasky	}
91322810Shselasky
92322810Shselasky	mutex_unlock(&context->db_page_mutex);
93322810Shselasky}
94