112515907SHans Petter Selasky /*-
212515907SHans Petter Selasky  * Copyright (c) 2013-2015, Mellanox Technologies, Ltd.  All rights reserved.
312515907SHans Petter Selasky  *
412515907SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
512515907SHans Petter Selasky  * modification, are permitted provided that the following conditions
612515907SHans Petter Selasky  * are met:
712515907SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
812515907SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
912515907SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
1012515907SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
1112515907SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
1212515907SHans Petter Selasky  *
1312515907SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
1412515907SHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1512515907SHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1612515907SHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1712515907SHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1812515907SHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1912515907SHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2012515907SHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2112515907SHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2212515907SHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2312515907SHans Petter Selasky  * SUCH DAMAGE.
2412515907SHans Petter Selasky  */
2512515907SHans Petter Selasky 
2670600979SKonstantin Belousov #include "opt_rss.h"
2770600979SKonstantin Belousov #include "opt_ratelimit.h"
2870600979SKonstantin Belousov 
2912515907SHans Petter Selasky #include <linux/kref.h>
3012515907SHans Petter Selasky #include <linux/slab.h>
3112515907SHans Petter Selasky #include <rdma/ib_umem.h>
3212515907SHans Petter Selasky 
33028130b8SKonstantin Belousov #include <dev/mlx5/mlx5_ib/mlx5_ib.h>
3412515907SHans Petter Selasky 
3512515907SHans Petter Selasky struct mlx5_ib_user_db_page {
3612515907SHans Petter Selasky 	struct list_head	list;
3712515907SHans Petter Selasky 	struct ib_umem	       *umem;
388e6e287fSHans Petter Selasky 	unsigned long		user_virt;
3912515907SHans Petter Selasky 	int			refcnt;
4012515907SHans Petter Selasky };
4112515907SHans Petter Selasky 
mlx5_ib_db_map_user(struct mlx5_ib_ucontext * context,unsigned long virt,struct mlx5_db * db)428e6e287fSHans Petter Selasky int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
4312515907SHans Petter Selasky 			struct mlx5_db *db)
4412515907SHans Petter Selasky {
4512515907SHans Petter Selasky 	struct mlx5_ib_user_db_page *page;
4612515907SHans Petter Selasky 	int err = 0;
4712515907SHans Petter Selasky 
4812515907SHans Petter Selasky 	mutex_lock(&context->db_page_mutex);
4912515907SHans Petter Selasky 
5012515907SHans Petter Selasky 	list_for_each_entry(page, &context->db_page_list, list)
5112515907SHans Petter Selasky 		if (page->user_virt == (virt & PAGE_MASK))
5212515907SHans Petter Selasky 			goto found;
5312515907SHans Petter Selasky 
5412515907SHans Petter Selasky 	page = kmalloc(sizeof(*page), GFP_KERNEL);
5512515907SHans Petter Selasky 	if (!page) {
5612515907SHans Petter Selasky 		err = -ENOMEM;
5712515907SHans Petter Selasky 		goto out;
5812515907SHans Petter Selasky 	}
5912515907SHans Petter Selasky 
6012515907SHans Petter Selasky 	page->user_virt = (virt & PAGE_MASK);
6112515907SHans Petter Selasky 	page->refcnt    = 0;
6212515907SHans Petter Selasky 	page->umem      = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
6312515907SHans Petter Selasky 				      PAGE_SIZE, 0, 0);
6412515907SHans Petter Selasky 	if (IS_ERR(page->umem)) {
6512515907SHans Petter Selasky 		err = PTR_ERR(page->umem);
6612515907SHans Petter Selasky 		kfree(page);
6712515907SHans Petter Selasky 		goto out;
6812515907SHans Petter Selasky 	}
6912515907SHans Petter Selasky 
7012515907SHans Petter Selasky 	list_add(&page->list, &context->db_page_list);
7112515907SHans Petter Selasky 
7212515907SHans Petter Selasky found:
7312515907SHans Petter Selasky 	db->dma = sg_dma_address(page->umem->sg_head.sgl) + (virt & ~PAGE_MASK);
7412515907SHans Petter Selasky 	db->u.user_page = page;
7512515907SHans Petter Selasky 	++page->refcnt;
7612515907SHans Petter Selasky 
7712515907SHans Petter Selasky out:
7812515907SHans Petter Selasky 	mutex_unlock(&context->db_page_mutex);
7912515907SHans Petter Selasky 
8012515907SHans Petter Selasky 	return err;
8112515907SHans Petter Selasky }
8212515907SHans Petter Selasky 
mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext * context,struct mlx5_db * db)8312515907SHans Petter Selasky void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db)
8412515907SHans Petter Selasky {
8512515907SHans Petter Selasky 	mutex_lock(&context->db_page_mutex);
8612515907SHans Petter Selasky 
8712515907SHans Petter Selasky 	if (!--db->u.user_page->refcnt) {
8812515907SHans Petter Selasky 		list_del(&db->u.user_page->list);
8912515907SHans Petter Selasky 		ib_umem_release(db->u.user_page->umem);
9012515907SHans Petter Selasky 		kfree(db->u.user_page);
9112515907SHans Petter Selasky 	}
9212515907SHans Petter Selasky 
9312515907SHans Petter Selasky 	mutex_unlock(&context->db_page_mutex);
9412515907SHans Petter Selasky }
95