xref: /openbmc/linux/net/rds/ib_rdma.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
108b48a1eSAndy Grover /*
2b7ff8b10SKa-Cheong Poon  * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
308b48a1eSAndy Grover  *
408b48a1eSAndy Grover  * This software is available to you under a choice of one of two
508b48a1eSAndy Grover  * licenses.  You may choose to be licensed under the terms of the GNU
608b48a1eSAndy Grover  * General Public License (GPL) Version 2, available from the file
708b48a1eSAndy Grover  * COPYING in the main directory of this source tree, or the
808b48a1eSAndy Grover  * OpenIB.org BSD license below:
908b48a1eSAndy Grover  *
1008b48a1eSAndy Grover  *     Redistribution and use in source and binary forms, with or
1108b48a1eSAndy Grover  *     without modification, are permitted provided that the following
1208b48a1eSAndy Grover  *     conditions are met:
1308b48a1eSAndy Grover  *
1408b48a1eSAndy Grover  *      - Redistributions of source code must retain the above
1508b48a1eSAndy Grover  *        copyright notice, this list of conditions and the following
1608b48a1eSAndy Grover  *        disclaimer.
1708b48a1eSAndy Grover  *
1808b48a1eSAndy Grover  *      - Redistributions in binary form must reproduce the above
1908b48a1eSAndy Grover  *        copyright notice, this list of conditions and the following
2008b48a1eSAndy Grover  *        disclaimer in the documentation and/or other materials
2108b48a1eSAndy Grover  *        provided with the distribution.
2208b48a1eSAndy Grover  *
2308b48a1eSAndy Grover  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2408b48a1eSAndy Grover  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2508b48a1eSAndy Grover  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2608b48a1eSAndy Grover  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2708b48a1eSAndy Grover  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2808b48a1eSAndy Grover  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2908b48a1eSAndy Grover  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3008b48a1eSAndy Grover  * SOFTWARE.
3108b48a1eSAndy Grover  *
3208b48a1eSAndy Grover  */
3308b48a1eSAndy Grover #include <linux/kernel.h>
345a0e3ad6STejun Heo #include <linux/slab.h>
35764f2dd9SChris Mason #include <linux/rculist.h>
361bc144b6SHuang Ying #include <linux/llist.h>
3708b48a1eSAndy Grover 
380cb43965SSowmini Varadhan #include "rds_single_path.h"
39f6df683fSsantosh.shilimkar@oracle.com #include "ib_mr.h"
402eafa174SHans Westgaard Ry #include "rds.h"
41f6df683fSsantosh.shilimkar@oracle.com 
42f6df683fSsantosh.shilimkar@oracle.com struct workqueue_struct *rds_ib_mr_wq;
432eafa174SHans Westgaard Ry struct rds_ib_dereg_odp_mr {
442eafa174SHans Westgaard Ry 	struct work_struct work;
452eafa174SHans Westgaard Ry 	struct ib_mr *mr;
462eafa174SHans Westgaard Ry };
472eafa174SHans Westgaard Ry 
482eafa174SHans Westgaard Ry static void rds_ib_odp_mr_worker(struct work_struct *work);
4908b48a1eSAndy Grover 
rds_ib_get_device(__be32 ipaddr)5008b48a1eSAndy Grover static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
5108b48a1eSAndy Grover {
5208b48a1eSAndy Grover 	struct rds_ib_device *rds_ibdev;
5308b48a1eSAndy Grover 	struct rds_ib_ipaddr *i_ipaddr;
5408b48a1eSAndy Grover 
55764f2dd9SChris Mason 	rcu_read_lock();
56ea819867SZach Brown 	list_for_each_entry_rcu(rds_ibdev, &rds_ib_devices, list) {
57764f2dd9SChris Mason 		list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
5808b48a1eSAndy Grover 			if (i_ipaddr->ipaddr == ipaddr) {
5950d61ff7SReshetova, Elena 				refcount_inc(&rds_ibdev->refcount);
60764f2dd9SChris Mason 				rcu_read_unlock();
6108b48a1eSAndy Grover 				return rds_ibdev;
6208b48a1eSAndy Grover 			}
6308b48a1eSAndy Grover 		}
6408b48a1eSAndy Grover 	}
65ea819867SZach Brown 	rcu_read_unlock();
6608b48a1eSAndy Grover 
6708b48a1eSAndy Grover 	return NULL;
6808b48a1eSAndy Grover }
6908b48a1eSAndy Grover 
rds_ib_add_ipaddr(struct rds_ib_device * rds_ibdev,__be32 ipaddr)7008b48a1eSAndy Grover static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
7108b48a1eSAndy Grover {
7208b48a1eSAndy Grover 	struct rds_ib_ipaddr *i_ipaddr;
7308b48a1eSAndy Grover 
7408b48a1eSAndy Grover 	i_ipaddr = kmalloc(sizeof *i_ipaddr, GFP_KERNEL);
7508b48a1eSAndy Grover 	if (!i_ipaddr)
7608b48a1eSAndy Grover 		return -ENOMEM;
7708b48a1eSAndy Grover 
7808b48a1eSAndy Grover 	i_ipaddr->ipaddr = ipaddr;
7908b48a1eSAndy Grover 
8008b48a1eSAndy Grover 	spin_lock_irq(&rds_ibdev->spinlock);
81764f2dd9SChris Mason 	list_add_tail_rcu(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
8208b48a1eSAndy Grover 	spin_unlock_irq(&rds_ibdev->spinlock);
8308b48a1eSAndy Grover 
8408b48a1eSAndy Grover 	return 0;
8508b48a1eSAndy Grover }
8608b48a1eSAndy Grover 
rds_ib_remove_ipaddr(struct rds_ib_device * rds_ibdev,__be32 ipaddr)8708b48a1eSAndy Grover static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
8808b48a1eSAndy Grover {
894a81802bSAndy Grover 	struct rds_ib_ipaddr *i_ipaddr;
90764f2dd9SChris Mason 	struct rds_ib_ipaddr *to_free = NULL;
91764f2dd9SChris Mason 
9208b48a1eSAndy Grover 
9308b48a1eSAndy Grover 	spin_lock_irq(&rds_ibdev->spinlock);
94764f2dd9SChris Mason 	list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
9508b48a1eSAndy Grover 		if (i_ipaddr->ipaddr == ipaddr) {
96764f2dd9SChris Mason 			list_del_rcu(&i_ipaddr->list);
97764f2dd9SChris Mason 			to_free = i_ipaddr;
9808b48a1eSAndy Grover 			break;
9908b48a1eSAndy Grover 		}
10008b48a1eSAndy Grover 	}
10108b48a1eSAndy Grover 	spin_unlock_irq(&rds_ibdev->spinlock);
102764f2dd9SChris Mason 
10359fe4606SSantosh Shilimkar 	if (to_free)
10459fe4606SSantosh Shilimkar 		kfree_rcu(to_free, rcu);
10508b48a1eSAndy Grover }
10608b48a1eSAndy Grover 
rds_ib_update_ipaddr(struct rds_ib_device * rds_ibdev,struct in6_addr * ipaddr)107eee2fa6aSKa-Cheong Poon int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev,
108eee2fa6aSKa-Cheong Poon 			 struct in6_addr *ipaddr)
10908b48a1eSAndy Grover {
11008b48a1eSAndy Grover 	struct rds_ib_device *rds_ibdev_old;
11108b48a1eSAndy Grover 
112eee2fa6aSKa-Cheong Poon 	rds_ibdev_old = rds_ib_get_device(ipaddr->s6_addr32[3]);
113e1f475a7Ssantosh.shilimkar@oracle.com 	if (!rds_ibdev_old)
114eee2fa6aSKa-Cheong Poon 		return rds_ib_add_ipaddr(rds_ibdev, ipaddr->s6_addr32[3]);
115e1f475a7Ssantosh.shilimkar@oracle.com 
116e1f475a7Ssantosh.shilimkar@oracle.com 	if (rds_ibdev_old != rds_ibdev) {
117eee2fa6aSKa-Cheong Poon 		rds_ib_remove_ipaddr(rds_ibdev_old, ipaddr->s6_addr32[3]);
1183e0249f9SZach Brown 		rds_ib_dev_put(rds_ibdev_old);
119eee2fa6aSKa-Cheong Poon 		return rds_ib_add_ipaddr(rds_ibdev, ipaddr->s6_addr32[3]);
12008b48a1eSAndy Grover 	}
121e1f475a7Ssantosh.shilimkar@oracle.com 	rds_ib_dev_put(rds_ibdev_old);
122e1f475a7Ssantosh.shilimkar@oracle.com 
123e1f475a7Ssantosh.shilimkar@oracle.com 	return 0;
124e1f475a7Ssantosh.shilimkar@oracle.com }
12508b48a1eSAndy Grover 
rds_ib_add_conn(struct rds_ib_device * rds_ibdev,struct rds_connection * conn)126745cbccaSAndy Grover void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
12708b48a1eSAndy Grover {
12808b48a1eSAndy Grover 	struct rds_ib_connection *ic = conn->c_transport_data;
12908b48a1eSAndy Grover 
13008b48a1eSAndy Grover 	/* conn was previously on the nodev_conns_list */
13108b48a1eSAndy Grover 	spin_lock_irq(&ib_nodev_conns_lock);
13208b48a1eSAndy Grover 	BUG_ON(list_empty(&ib_nodev_conns));
13308b48a1eSAndy Grover 	BUG_ON(list_empty(&ic->ib_node));
13408b48a1eSAndy Grover 	list_del(&ic->ib_node);
13508b48a1eSAndy Grover 
136aef3ea33SDan Carpenter 	spin_lock(&rds_ibdev->spinlock);
13708b48a1eSAndy Grover 	list_add_tail(&ic->ib_node, &rds_ibdev->conn_list);
138aef3ea33SDan Carpenter 	spin_unlock(&rds_ibdev->spinlock);
13908b48a1eSAndy Grover 	spin_unlock_irq(&ib_nodev_conns_lock);
14008b48a1eSAndy Grover 
141745cbccaSAndy Grover 	ic->rds_ibdev = rds_ibdev;
14250d61ff7SReshetova, Elena 	refcount_inc(&rds_ibdev->refcount);
14308b48a1eSAndy Grover }
14408b48a1eSAndy Grover 
rds_ib_remove_conn(struct rds_ib_device * rds_ibdev,struct rds_connection * conn)145745cbccaSAndy Grover void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
146745cbccaSAndy Grover {
147745cbccaSAndy Grover 	struct rds_ib_connection *ic = conn->c_transport_data;
148745cbccaSAndy Grover 
149745cbccaSAndy Grover 	/* place conn on nodev_conns_list */
150745cbccaSAndy Grover 	spin_lock(&ib_nodev_conns_lock);
151745cbccaSAndy Grover 
152745cbccaSAndy Grover 	spin_lock_irq(&rds_ibdev->spinlock);
153745cbccaSAndy Grover 	BUG_ON(list_empty(&ic->ib_node));
154745cbccaSAndy Grover 	list_del(&ic->ib_node);
155745cbccaSAndy Grover 	spin_unlock_irq(&rds_ibdev->spinlock);
156745cbccaSAndy Grover 
157745cbccaSAndy Grover 	list_add_tail(&ic->ib_node, &ib_nodev_conns);
158745cbccaSAndy Grover 
159745cbccaSAndy Grover 	spin_unlock(&ib_nodev_conns_lock);
160745cbccaSAndy Grover 
161745cbccaSAndy Grover 	ic->rds_ibdev = NULL;
1623e0249f9SZach Brown 	rds_ib_dev_put(rds_ibdev);
163745cbccaSAndy Grover }
164745cbccaSAndy Grover 
rds_ib_destroy_nodev_conns(void)1658aeb1ba6SZach Brown void rds_ib_destroy_nodev_conns(void)
16608b48a1eSAndy Grover {
16708b48a1eSAndy Grover 	struct rds_ib_connection *ic, *_ic;
16808b48a1eSAndy Grover 	LIST_HEAD(tmp_list);
16908b48a1eSAndy Grover 
17008b48a1eSAndy Grover 	/* avoid calling conn_destroy with irqs off */
1718aeb1ba6SZach Brown 	spin_lock_irq(&ib_nodev_conns_lock);
1728aeb1ba6SZach Brown 	list_splice(&ib_nodev_conns, &tmp_list);
1738aeb1ba6SZach Brown 	spin_unlock_irq(&ib_nodev_conns_lock);
17408b48a1eSAndy Grover 
175433d308dSAndy Grover 	list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node)
17608b48a1eSAndy Grover 		rds_conn_destroy(ic->conn);
17708b48a1eSAndy Grover }
17808b48a1eSAndy Grover 
rds_ib_get_mr_info(struct rds_ib_device * rds_ibdev,struct rds_info_rdma_connection * iinfo)17908b48a1eSAndy Grover void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo)
18008b48a1eSAndy Grover {
18106766513SSantosh Shilimkar 	struct rds_ib_mr_pool *pool_1m = rds_ibdev->mr_1m_pool;
18208b48a1eSAndy Grover 
18306766513SSantosh Shilimkar 	iinfo->rdma_mr_max = pool_1m->max_items;
184*07549ee2SMax Gurtovoy 	iinfo->rdma_mr_size = pool_1m->max_pages;
18508b48a1eSAndy Grover }
18608b48a1eSAndy Grover 
187e65d4d96SKa-Cheong Poon #if IS_ENABLED(CONFIG_IPV6)
rds6_ib_get_mr_info(struct rds_ib_device * rds_ibdev,struct rds6_info_rdma_connection * iinfo6)188b7ff8b10SKa-Cheong Poon void rds6_ib_get_mr_info(struct rds_ib_device *rds_ibdev,
189b7ff8b10SKa-Cheong Poon 			 struct rds6_info_rdma_connection *iinfo6)
190b7ff8b10SKa-Cheong Poon {
191b7ff8b10SKa-Cheong Poon 	struct rds_ib_mr_pool *pool_1m = rds_ibdev->mr_1m_pool;
192b7ff8b10SKa-Cheong Poon 
193b7ff8b10SKa-Cheong Poon 	iinfo6->rdma_mr_max = pool_1m->max_items;
194*07549ee2SMax Gurtovoy 	iinfo6->rdma_mr_size = pool_1m->max_pages;
195b7ff8b10SKa-Cheong Poon }
196e65d4d96SKa-Cheong Poon #endif
197b7ff8b10SKa-Cheong Poon 
rds_ib_reuse_mr(struct rds_ib_mr_pool * pool)198f6df683fSsantosh.shilimkar@oracle.com struct rds_ib_mr *rds_ib_reuse_mr(struct rds_ib_mr_pool *pool)
19908b48a1eSAndy Grover {
20008b48a1eSAndy Grover 	struct rds_ib_mr *ibmr = NULL;
2011bc144b6SHuang Ying 	struct llist_node *ret;
202c9467447SGerd Rausch 	unsigned long flags;
20308b48a1eSAndy Grover 
204c9467447SGerd Rausch 	spin_lock_irqsave(&pool->clean_lock, flags);
2051bc144b6SHuang Ying 	ret = llist_del_first(&pool->clean_list);
206c9467447SGerd Rausch 	spin_unlock_irqrestore(&pool->clean_lock, flags);
207db42753aSsantosh.shilimkar@oracle.com 	if (ret) {
2081bc144b6SHuang Ying 		ibmr = llist_entry(ret, struct rds_ib_mr, llnode);
209db42753aSsantosh.shilimkar@oracle.com 		if (pool->pool_type == RDS_IB_MR_8K_POOL)
210db42753aSsantosh.shilimkar@oracle.com 			rds_ib_stats_inc(s_ib_rdma_mr_8k_reused);
211db42753aSsantosh.shilimkar@oracle.com 		else
212db42753aSsantosh.shilimkar@oracle.com 			rds_ib_stats_inc(s_ib_rdma_mr_1m_reused);
213db42753aSsantosh.shilimkar@oracle.com 	}
21408b48a1eSAndy Grover 
21508b48a1eSAndy Grover 	return ibmr;
21608b48a1eSAndy Grover }
21708b48a1eSAndy Grover 
rds_ib_sync_mr(void * trans_private,int direction)21808b48a1eSAndy Grover void rds_ib_sync_mr(void *trans_private, int direction)
21908b48a1eSAndy Grover {
22008b48a1eSAndy Grover 	struct rds_ib_mr *ibmr = trans_private;
22108b48a1eSAndy Grover 	struct rds_ib_device *rds_ibdev = ibmr->device;
22208b48a1eSAndy Grover 
2232eafa174SHans Westgaard Ry 	if (ibmr->odp)
2242eafa174SHans Westgaard Ry 		return;
2252eafa174SHans Westgaard Ry 
22608b48a1eSAndy Grover 	switch (direction) {
22708b48a1eSAndy Grover 	case DMA_FROM_DEVICE:
22808b48a1eSAndy Grover 		ib_dma_sync_sg_for_cpu(rds_ibdev->dev, ibmr->sg,
22908b48a1eSAndy Grover 			ibmr->sg_dma_len, DMA_BIDIRECTIONAL);
23008b48a1eSAndy Grover 		break;
23108b48a1eSAndy Grover 	case DMA_TO_DEVICE:
23208b48a1eSAndy Grover 		ib_dma_sync_sg_for_device(rds_ibdev->dev, ibmr->sg,
23308b48a1eSAndy Grover 			ibmr->sg_dma_len, DMA_BIDIRECTIONAL);
23408b48a1eSAndy Grover 		break;
23508b48a1eSAndy Grover 	}
23608b48a1eSAndy Grover }
23708b48a1eSAndy Grover 
__rds_ib_teardown_mr(struct rds_ib_mr * ibmr)238f6df683fSsantosh.shilimkar@oracle.com void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
23908b48a1eSAndy Grover {
24008b48a1eSAndy Grover 	struct rds_ib_device *rds_ibdev = ibmr->device;
24108b48a1eSAndy Grover 
24208b48a1eSAndy Grover 	if (ibmr->sg_dma_len) {
24308b48a1eSAndy Grover 		ib_dma_unmap_sg(rds_ibdev->dev,
24408b48a1eSAndy Grover 				ibmr->sg, ibmr->sg_len,
24508b48a1eSAndy Grover 				DMA_BIDIRECTIONAL);
24608b48a1eSAndy Grover 		ibmr->sg_dma_len = 0;
24708b48a1eSAndy Grover 	}
24808b48a1eSAndy Grover 
24908b48a1eSAndy Grover 	/* Release the s/g list */
25008b48a1eSAndy Grover 	if (ibmr->sg_len) {
25108b48a1eSAndy Grover 		unsigned int i;
25208b48a1eSAndy Grover 
25308b48a1eSAndy Grover 		for (i = 0; i < ibmr->sg_len; ++i) {
25408b48a1eSAndy Grover 			struct page *page = sg_page(&ibmr->sg[i]);
25508b48a1eSAndy Grover 
25608b48a1eSAndy Grover 			/* FIXME we need a way to tell a r/w MR
25708b48a1eSAndy Grover 			 * from a r/o MR */
2585c240fa2Ssantosh.shilimkar@oracle.com 			WARN_ON(!page->mapping && irqs_disabled());
25908b48a1eSAndy Grover 			set_page_dirty(page);
26008b48a1eSAndy Grover 			put_page(page);
26108b48a1eSAndy Grover 		}
26208b48a1eSAndy Grover 		kfree(ibmr->sg);
26308b48a1eSAndy Grover 
26408b48a1eSAndy Grover 		ibmr->sg = NULL;
26508b48a1eSAndy Grover 		ibmr->sg_len = 0;
26608b48a1eSAndy Grover 	}
26708b48a1eSAndy Grover }
26808b48a1eSAndy Grover 
rds_ib_teardown_mr(struct rds_ib_mr * ibmr)269f6df683fSsantosh.shilimkar@oracle.com void rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
27008b48a1eSAndy Grover {
27108b48a1eSAndy Grover 	unsigned int pinned = ibmr->sg_len;
27208b48a1eSAndy Grover 
27308b48a1eSAndy Grover 	__rds_ib_teardown_mr(ibmr);
27408b48a1eSAndy Grover 	if (pinned) {
27526139dc1SSantosh Shilimkar 		struct rds_ib_mr_pool *pool = ibmr->pool;
27608b48a1eSAndy Grover 
27708b48a1eSAndy Grover 		atomic_sub(pinned, &pool->free_pinned);
27808b48a1eSAndy Grover 	}
27908b48a1eSAndy Grover }
28008b48a1eSAndy Grover 
rds_ib_flush_goal(struct rds_ib_mr_pool * pool,int free_all)28108b48a1eSAndy Grover static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int free_all)
28208b48a1eSAndy Grover {
28308b48a1eSAndy Grover 	unsigned int item_count;
28408b48a1eSAndy Grover 
28508b48a1eSAndy Grover 	item_count = atomic_read(&pool->item_count);
28608b48a1eSAndy Grover 	if (free_all)
28708b48a1eSAndy Grover 		return item_count;
28808b48a1eSAndy Grover 
28908b48a1eSAndy Grover 	return 0;
29008b48a1eSAndy Grover }
29108b48a1eSAndy Grover 
29208b48a1eSAndy Grover /*
2931bc144b6SHuang Ying  * given an llist of mrs, put them all into the list_head for more processing
2946fa70da6SChris Mason  */
llist_append_to_list(struct llist_head * llist,struct list_head * list)2956116c203SWengang Wang static unsigned int llist_append_to_list(struct llist_head *llist,
2966116c203SWengang Wang 					 struct list_head *list)
2976fa70da6SChris Mason {
2986fa70da6SChris Mason 	struct rds_ib_mr *ibmr;
2991bc144b6SHuang Ying 	struct llist_node *node;
3001bc144b6SHuang Ying 	struct llist_node *next;
3016116c203SWengang Wang 	unsigned int count = 0;
3026fa70da6SChris Mason 
3031bc144b6SHuang Ying 	node = llist_del_all(llist);
3041bc144b6SHuang Ying 	while (node) {
3051bc144b6SHuang Ying 		next = node->next;
3061bc144b6SHuang Ying 		ibmr = llist_entry(node, struct rds_ib_mr, llnode);
3076fa70da6SChris Mason 		list_add_tail(&ibmr->unmap_list, list);
3081bc144b6SHuang Ying 		node = next;
3096116c203SWengang Wang 		count++;
3106fa70da6SChris Mason 	}
3116116c203SWengang Wang 	return count;
3126fa70da6SChris Mason }
3136fa70da6SChris Mason 
3146fa70da6SChris Mason /*
3151bc144b6SHuang Ying  * this takes a list head of mrs and turns it into linked llist nodes
3161bc144b6SHuang Ying  * of clusters.  Each cluster has linked llist nodes of
3171bc144b6SHuang Ying  * MR_CLUSTER_SIZE mrs that are ready for reuse.
3186fa70da6SChris Mason  */
list_to_llist_nodes(struct list_head * list,struct llist_node ** nodes_head,struct llist_node ** nodes_tail)319c9467447SGerd Rausch static void list_to_llist_nodes(struct list_head *list,
3201bc144b6SHuang Ying 				struct llist_node **nodes_head,
3211bc144b6SHuang Ying 				struct llist_node **nodes_tail)
3226fa70da6SChris Mason {
3236fa70da6SChris Mason 	struct rds_ib_mr *ibmr;
3241bc144b6SHuang Ying 	struct llist_node *cur = NULL;
3251bc144b6SHuang Ying 	struct llist_node **next = nodes_head;
3266fa70da6SChris Mason 
3276fa70da6SChris Mason 	list_for_each_entry(ibmr, list, unmap_list) {
3281bc144b6SHuang Ying 		cur = &ibmr->llnode;
3291bc144b6SHuang Ying 		*next = cur;
3301bc144b6SHuang Ying 		next = &cur->next;
3316fa70da6SChris Mason 	}
3321bc144b6SHuang Ying 	*next = NULL;
3331bc144b6SHuang Ying 	*nodes_tail = cur;
3346fa70da6SChris Mason }
3356fa70da6SChris Mason 
3366fa70da6SChris Mason /*
33708b48a1eSAndy Grover  * Flush our pool of MRs.
33808b48a1eSAndy Grover  * At a minimum, all currently unused MRs are unmapped.
33908b48a1eSAndy Grover  * If the number of MRs allocated exceeds the limit, we also try
34008b48a1eSAndy Grover  * to free as many MRs as needed to get back to this limit.
34108b48a1eSAndy Grover  */
rds_ib_flush_mr_pool(struct rds_ib_mr_pool * pool,int free_all,struct rds_ib_mr ** ibmr_ret)342f6df683fSsantosh.shilimkar@oracle.com int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
3436fa70da6SChris Mason 			 int free_all, struct rds_ib_mr **ibmr_ret)
34408b48a1eSAndy Grover {
345490ea596Ssantosh.shilimkar@oracle.com 	struct rds_ib_mr *ibmr;
3461bc144b6SHuang Ying 	struct llist_node *clean_nodes;
3471bc144b6SHuang Ying 	struct llist_node *clean_tail;
34808b48a1eSAndy Grover 	LIST_HEAD(unmap_list);
34908b48a1eSAndy Grover 	unsigned long unpinned = 0;
3506116c203SWengang Wang 	unsigned int nfreed = 0, dirty_to_clean = 0, free_goal;
35108b48a1eSAndy Grover 
35206766513SSantosh Shilimkar 	if (pool->pool_type == RDS_IB_MR_8K_POOL)
35306766513SSantosh Shilimkar 		rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_flush);
35406766513SSantosh Shilimkar 	else
35506766513SSantosh Shilimkar 		rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_flush);
35608b48a1eSAndy Grover 
3576fa70da6SChris Mason 	if (ibmr_ret) {
3586fa70da6SChris Mason 		DEFINE_WAIT(wait);
3596fa70da6SChris Mason 		while (!mutex_trylock(&pool->flush_lock)) {
360f6df683fSsantosh.shilimkar@oracle.com 			ibmr = rds_ib_reuse_mr(pool);
3616fa70da6SChris Mason 			if (ibmr) {
3626fa70da6SChris Mason 				*ibmr_ret = ibmr;
3636fa70da6SChris Mason 				finish_wait(&pool->flush_wait, &wait);
3646fa70da6SChris Mason 				goto out_nolock;
3656fa70da6SChris Mason 			}
3666fa70da6SChris Mason 
3676fa70da6SChris Mason 			prepare_to_wait(&pool->flush_wait, &wait,
3686fa70da6SChris Mason 					TASK_UNINTERRUPTIBLE);
3691bc144b6SHuang Ying 			if (llist_empty(&pool->clean_list))
3706fa70da6SChris Mason 				schedule();
3716fa70da6SChris Mason 
372f6df683fSsantosh.shilimkar@oracle.com 			ibmr = rds_ib_reuse_mr(pool);
3736fa70da6SChris Mason 			if (ibmr) {
3746fa70da6SChris Mason 				*ibmr_ret = ibmr;
3756fa70da6SChris Mason 				finish_wait(&pool->flush_wait, &wait);
3766fa70da6SChris Mason 				goto out_nolock;
3776fa70da6SChris Mason 			}
3786fa70da6SChris Mason 		}
3796fa70da6SChris Mason 		finish_wait(&pool->flush_wait, &wait);
3806fa70da6SChris Mason 	} else
38108b48a1eSAndy Grover 		mutex_lock(&pool->flush_lock);
38208b48a1eSAndy Grover 
3836fa70da6SChris Mason 	if (ibmr_ret) {
384f6df683fSsantosh.shilimkar@oracle.com 		ibmr = rds_ib_reuse_mr(pool);
3856fa70da6SChris Mason 		if (ibmr) {
3866fa70da6SChris Mason 			*ibmr_ret = ibmr;
3876fa70da6SChris Mason 			goto out;
3886fa70da6SChris Mason 		}
3896fa70da6SChris Mason 	}
3906fa70da6SChris Mason 
39108b48a1eSAndy Grover 	/* Get the list of all MRs to be dropped. Ordering matters -
3926fa70da6SChris Mason 	 * we want to put drop_list ahead of free_list.
3936fa70da6SChris Mason 	 */
3946116c203SWengang Wang 	dirty_to_clean = llist_append_to_list(&pool->drop_list, &unmap_list);
3956116c203SWengang Wang 	dirty_to_clean += llist_append_to_list(&pool->free_list, &unmap_list);
396c9467447SGerd Rausch 	if (free_all) {
397c9467447SGerd Rausch 		unsigned long flags;
398c9467447SGerd Rausch 
399c9467447SGerd Rausch 		spin_lock_irqsave(&pool->clean_lock, flags);
4001bc144b6SHuang Ying 		llist_append_to_list(&pool->clean_list, &unmap_list);
401c9467447SGerd Rausch 		spin_unlock_irqrestore(&pool->clean_lock, flags);
402c9467447SGerd Rausch 	}
40308b48a1eSAndy Grover 
40408b48a1eSAndy Grover 	free_goal = rds_ib_flush_goal(pool, free_all);
40508b48a1eSAndy Grover 
40608b48a1eSAndy Grover 	if (list_empty(&unmap_list))
40708b48a1eSAndy Grover 		goto out;
40808b48a1eSAndy Grover 
4091659185fSAvinash Repaka 	rds_ib_unreg_frmr(&unmap_list, &nfreed, &unpinned, free_goal);
41008b48a1eSAndy Grover 
4116fa70da6SChris Mason 	if (!list_empty(&unmap_list)) {
412c9467447SGerd Rausch 		unsigned long flags;
4136fa70da6SChris Mason 
414c9467447SGerd Rausch 		list_to_llist_nodes(&unmap_list, &clean_nodes, &clean_tail);
41585cb9287SZhu Yanjun 		if (ibmr_ret) {
4161bc144b6SHuang Ying 			*ibmr_ret = llist_entry(clean_nodes, struct rds_ib_mr, llnode);
41785cb9287SZhu Yanjun 			clean_nodes = clean_nodes->next;
41885cb9287SZhu Yanjun 		}
4191bc144b6SHuang Ying 		/* more than one entry in llist nodes */
420c9467447SGerd Rausch 		if (clean_nodes) {
421c9467447SGerd Rausch 			spin_lock_irqsave(&pool->clean_lock, flags);
42285cb9287SZhu Yanjun 			llist_add_batch(clean_nodes, clean_tail,
42385cb9287SZhu Yanjun 					&pool->clean_list);
424c9467447SGerd Rausch 			spin_unlock_irqrestore(&pool->clean_lock, flags);
425c9467447SGerd Rausch 		}
4266fa70da6SChris Mason 	}
42708b48a1eSAndy Grover 
42808b48a1eSAndy Grover 	atomic_sub(unpinned, &pool->free_pinned);
4296116c203SWengang Wang 	atomic_sub(dirty_to_clean, &pool->dirty_count);
43008b48a1eSAndy Grover 	atomic_sub(nfreed, &pool->item_count);
43108b48a1eSAndy Grover 
43208b48a1eSAndy Grover out:
43308b48a1eSAndy Grover 	mutex_unlock(&pool->flush_lock);
4346fa70da6SChris Mason 	if (waitqueue_active(&pool->flush_wait))
4356fa70da6SChris Mason 		wake_up(&pool->flush_wait);
4366fa70da6SChris Mason out_nolock:
437490ea596Ssantosh.shilimkar@oracle.com 	return 0;
438490ea596Ssantosh.shilimkar@oracle.com }
439490ea596Ssantosh.shilimkar@oracle.com 
rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool * pool)440490ea596Ssantosh.shilimkar@oracle.com struct rds_ib_mr *rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool *pool)
441490ea596Ssantosh.shilimkar@oracle.com {
442490ea596Ssantosh.shilimkar@oracle.com 	struct rds_ib_mr *ibmr = NULL;
443490ea596Ssantosh.shilimkar@oracle.com 	int iter = 0;
444490ea596Ssantosh.shilimkar@oracle.com 
445490ea596Ssantosh.shilimkar@oracle.com 	while (1) {
446490ea596Ssantosh.shilimkar@oracle.com 		ibmr = rds_ib_reuse_mr(pool);
447490ea596Ssantosh.shilimkar@oracle.com 		if (ibmr)
448490ea596Ssantosh.shilimkar@oracle.com 			return ibmr;
449490ea596Ssantosh.shilimkar@oracle.com 
450490ea596Ssantosh.shilimkar@oracle.com 		if (atomic_inc_return(&pool->item_count) <= pool->max_items)
451490ea596Ssantosh.shilimkar@oracle.com 			break;
452490ea596Ssantosh.shilimkar@oracle.com 
453490ea596Ssantosh.shilimkar@oracle.com 		atomic_dec(&pool->item_count);
454490ea596Ssantosh.shilimkar@oracle.com 
455490ea596Ssantosh.shilimkar@oracle.com 		if (++iter > 2) {
456490ea596Ssantosh.shilimkar@oracle.com 			if (pool->pool_type == RDS_IB_MR_8K_POOL)
457490ea596Ssantosh.shilimkar@oracle.com 				rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_depleted);
458490ea596Ssantosh.shilimkar@oracle.com 			else
459490ea596Ssantosh.shilimkar@oracle.com 				rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_depleted);
460aea01a22SGerd Rausch 			break;
461490ea596Ssantosh.shilimkar@oracle.com 		}
462490ea596Ssantosh.shilimkar@oracle.com 
463490ea596Ssantosh.shilimkar@oracle.com 		/* We do have some empty MRs. Flush them out. */
464490ea596Ssantosh.shilimkar@oracle.com 		if (pool->pool_type == RDS_IB_MR_8K_POOL)
465490ea596Ssantosh.shilimkar@oracle.com 			rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_wait);
466490ea596Ssantosh.shilimkar@oracle.com 		else
467490ea596Ssantosh.shilimkar@oracle.com 			rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_wait);
468490ea596Ssantosh.shilimkar@oracle.com 
469490ea596Ssantosh.shilimkar@oracle.com 		rds_ib_flush_mr_pool(pool, 0, &ibmr);
470490ea596Ssantosh.shilimkar@oracle.com 		if (ibmr)
471490ea596Ssantosh.shilimkar@oracle.com 			return ibmr;
472490ea596Ssantosh.shilimkar@oracle.com 	}
473490ea596Ssantosh.shilimkar@oracle.com 
474aea01a22SGerd Rausch 	return NULL;
47508b48a1eSAndy Grover }
47608b48a1eSAndy Grover 
rds_ib_mr_pool_flush_worker(struct work_struct * work)47708b48a1eSAndy Grover static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
47808b48a1eSAndy Grover {
4797a0ff5dbSChris Mason 	struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker.work);
48008b48a1eSAndy Grover 
4816fa70da6SChris Mason 	rds_ib_flush_mr_pool(pool, 0, NULL);
48208b48a1eSAndy Grover }
48308b48a1eSAndy Grover 
rds_ib_free_mr(void * trans_private,int invalidate)48408b48a1eSAndy Grover void rds_ib_free_mr(void *trans_private, int invalidate)
48508b48a1eSAndy Grover {
48608b48a1eSAndy Grover 	struct rds_ib_mr *ibmr = trans_private;
48726139dc1SSantosh Shilimkar 	struct rds_ib_mr_pool *pool = ibmr->pool;
48808b48a1eSAndy Grover 	struct rds_ib_device *rds_ibdev = ibmr->device;
48908b48a1eSAndy Grover 
49008b48a1eSAndy Grover 	rdsdebug("RDS/IB: free_mr nents %u\n", ibmr->sg_len);
49108b48a1eSAndy Grover 
4922eafa174SHans Westgaard Ry 	if (ibmr->odp) {
4932eafa174SHans Westgaard Ry 		/* A MR created and marked as use_once. We use delayed work,
4942eafa174SHans Westgaard Ry 		 * because there is a change that we are in interrupt and can't
4952eafa174SHans Westgaard Ry 		 * call to ib_dereg_mr() directly.
4962eafa174SHans Westgaard Ry 		 */
4972eafa174SHans Westgaard Ry 		INIT_DELAYED_WORK(&ibmr->work, rds_ib_odp_mr_worker);
4982eafa174SHans Westgaard Ry 		queue_delayed_work(rds_ib_mr_wq, &ibmr->work, 0);
4992eafa174SHans Westgaard Ry 		return;
5002eafa174SHans Westgaard Ry 	}
5012eafa174SHans Westgaard Ry 
50208b48a1eSAndy Grover 	/* Return it to the pool's free list */
5031659185fSAvinash Repaka 	rds_ib_free_frmr_list(ibmr);
50408b48a1eSAndy Grover 
50508b48a1eSAndy Grover 	atomic_add(ibmr->sg_len, &pool->free_pinned);
50608b48a1eSAndy Grover 	atomic_inc(&pool->dirty_count);
50708b48a1eSAndy Grover 
50808b48a1eSAndy Grover 	/* If we've pinned too many pages, request a flush */
509f64f9e71SJoe Perches 	if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
510ef5217a6Ssantosh.shilimkar@oracle.com 	    atomic_read(&pool->dirty_count) >= pool->max_items / 5)
511f6df683fSsantosh.shilimkar@oracle.com 		queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10);
51208b48a1eSAndy Grover 
51308b48a1eSAndy Grover 	if (invalidate) {
51408b48a1eSAndy Grover 		if (likely(!in_interrupt())) {
5156fa70da6SChris Mason 			rds_ib_flush_mr_pool(pool, 0, NULL);
51608b48a1eSAndy Grover 		} else {
51708b48a1eSAndy Grover 			/* We get here if the user created a MR marked
518ad1d7dc0Ssantosh.shilimkar@oracle.com 			 * as use_once and invalidate at the same time.
519ad1d7dc0Ssantosh.shilimkar@oracle.com 			 */
520f6df683fSsantosh.shilimkar@oracle.com 			queue_delayed_work(rds_ib_mr_wq,
521ad1d7dc0Ssantosh.shilimkar@oracle.com 					   &pool->flush_worker, 10);
52208b48a1eSAndy Grover 		}
52308b48a1eSAndy Grover 	}
5243e0249f9SZach Brown 
5253e0249f9SZach Brown 	rds_ib_dev_put(rds_ibdev);
52608b48a1eSAndy Grover }
52708b48a1eSAndy Grover 
rds_ib_flush_mrs(void)52808b48a1eSAndy Grover void rds_ib_flush_mrs(void)
52908b48a1eSAndy Grover {
53008b48a1eSAndy Grover 	struct rds_ib_device *rds_ibdev;
53108b48a1eSAndy Grover 
532ea819867SZach Brown 	down_read(&rds_ib_devices_lock);
53308b48a1eSAndy Grover 	list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
53406766513SSantosh Shilimkar 		if (rds_ibdev->mr_8k_pool)
53506766513SSantosh Shilimkar 			rds_ib_flush_mr_pool(rds_ibdev->mr_8k_pool, 0, NULL);
53608b48a1eSAndy Grover 
53706766513SSantosh Shilimkar 		if (rds_ibdev->mr_1m_pool)
53806766513SSantosh Shilimkar 			rds_ib_flush_mr_pool(rds_ibdev->mr_1m_pool, 0, NULL);
53908b48a1eSAndy Grover 	}
540ea819867SZach Brown 	up_read(&rds_ib_devices_lock);
54108b48a1eSAndy Grover }
54208b48a1eSAndy Grover 
rds_ib_get_lkey(void * trans_private)5432eafa174SHans Westgaard Ry u32 rds_ib_get_lkey(void *trans_private)
5442eafa174SHans Westgaard Ry {
5452eafa174SHans Westgaard Ry 	struct rds_ib_mr *ibmr = trans_private;
5462eafa174SHans Westgaard Ry 
5472eafa174SHans Westgaard Ry 	return ibmr->u.mr->lkey;
5482eafa174SHans Westgaard Ry }
5492eafa174SHans Westgaard Ry 
rds_ib_get_mr(struct scatterlist * sg,unsigned long nents,struct rds_sock * rs,u32 * key_ret,struct rds_connection * conn,u64 start,u64 length,int need_odp)55008b48a1eSAndy Grover void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
5519e630bcbSAvinash Repaka 		    struct rds_sock *rs, u32 *key_ret,
5522eafa174SHans Westgaard Ry 		    struct rds_connection *conn,
5532eafa174SHans Westgaard Ry 		    u64 start, u64 length, int need_odp)
55408b48a1eSAndy Grover {
55508b48a1eSAndy Grover 	struct rds_ib_device *rds_ibdev;
55608b48a1eSAndy Grover 	struct rds_ib_mr *ibmr = NULL;
5579e630bcbSAvinash Repaka 	struct rds_ib_connection *ic = NULL;
55808b48a1eSAndy Grover 	int ret;
55908b48a1eSAndy Grover 
560eee2fa6aSKa-Cheong Poon 	rds_ibdev = rds_ib_get_device(rs->rs_bound_addr.s6_addr32[3]);
56108b48a1eSAndy Grover 	if (!rds_ibdev) {
56208b48a1eSAndy Grover 		ret = -ENODEV;
56308b48a1eSAndy Grover 		goto out;
56408b48a1eSAndy Grover 	}
56508b48a1eSAndy Grover 
5662eafa174SHans Westgaard Ry 	if (need_odp == ODP_ZEROBASED || need_odp == ODP_VIRTUAL) {
5672eafa174SHans Westgaard Ry 		u64 virt_addr = need_odp == ODP_ZEROBASED ? 0 : start;
5682eafa174SHans Westgaard Ry 		int access_flags =
5692eafa174SHans Westgaard Ry 			(IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ |
5702eafa174SHans Westgaard Ry 			 IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_ATOMIC |
5712eafa174SHans Westgaard Ry 			 IB_ACCESS_ON_DEMAND);
572b2dfc676SHans Westgaard Ry 		struct ib_sge sge = {};
5732eafa174SHans Westgaard Ry 		struct ib_mr *ib_mr;
5742eafa174SHans Westgaard Ry 
5752eafa174SHans Westgaard Ry 		if (!rds_ibdev->odp_capable) {
5762eafa174SHans Westgaard Ry 			ret = -EOPNOTSUPP;
5772eafa174SHans Westgaard Ry 			goto out;
5782eafa174SHans Westgaard Ry 		}
5792eafa174SHans Westgaard Ry 
5802eafa174SHans Westgaard Ry 		ib_mr = ib_reg_user_mr(rds_ibdev->pd, start, length, virt_addr,
5812eafa174SHans Westgaard Ry 				       access_flags);
5822eafa174SHans Westgaard Ry 
5832eafa174SHans Westgaard Ry 		if (IS_ERR(ib_mr)) {
5842eafa174SHans Westgaard Ry 			rdsdebug("rds_ib_get_user_mr returned %d\n",
5852eafa174SHans Westgaard Ry 				 IS_ERR(ib_mr));
5862eafa174SHans Westgaard Ry 			ret = PTR_ERR(ib_mr);
5872eafa174SHans Westgaard Ry 			goto out;
5882eafa174SHans Westgaard Ry 		}
5892eafa174SHans Westgaard Ry 		if (key_ret)
5902eafa174SHans Westgaard Ry 			*key_ret = ib_mr->rkey;
5912eafa174SHans Westgaard Ry 
5922eafa174SHans Westgaard Ry 		ibmr = kzalloc(sizeof(*ibmr), GFP_KERNEL);
5932eafa174SHans Westgaard Ry 		if (!ibmr) {
5942eafa174SHans Westgaard Ry 			ib_dereg_mr(ib_mr);
5952eafa174SHans Westgaard Ry 			ret = -ENOMEM;
5962eafa174SHans Westgaard Ry 			goto out;
5972eafa174SHans Westgaard Ry 		}
5982eafa174SHans Westgaard Ry 		ibmr->u.mr = ib_mr;
5992eafa174SHans Westgaard Ry 		ibmr->odp = 1;
600b2dfc676SHans Westgaard Ry 
601b2dfc676SHans Westgaard Ry 		sge.addr = virt_addr;
602b2dfc676SHans Westgaard Ry 		sge.length = length;
603b2dfc676SHans Westgaard Ry 		sge.lkey = ib_mr->lkey;
604b2dfc676SHans Westgaard Ry 
605b2dfc676SHans Westgaard Ry 		ib_advise_mr(rds_ibdev->pd,
606b2dfc676SHans Westgaard Ry 			     IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_WRITE,
607b2dfc676SHans Westgaard Ry 			     IB_UVERBS_ADVISE_MR_FLAG_FLUSH, &sge, 1);
6082eafa174SHans Westgaard Ry 		return ibmr;
6092eafa174SHans Westgaard Ry 	}
6102eafa174SHans Westgaard Ry 
6119e630bcbSAvinash Repaka 	if (conn)
6129e630bcbSAvinash Repaka 		ic = conn->c_transport_data;
6139e630bcbSAvinash Repaka 
61406766513SSantosh Shilimkar 	if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
61508b48a1eSAndy Grover 		ret = -ENODEV;
61608b48a1eSAndy Grover 		goto out;
61708b48a1eSAndy Grover 	}
61808b48a1eSAndy Grover 
6191659185fSAvinash Repaka 	ibmr = rds_ib_reg_frmr(rds_ibdev, ic, sg, nents, key_ret);
6209e630bcbSAvinash Repaka 	if (IS_ERR(ibmr)) {
6219e630bcbSAvinash Repaka 		ret = PTR_ERR(ibmr);
6229e630bcbSAvinash Repaka 		pr_warn("RDS/IB: rds_ib_get_mr failed (errno=%d)\n", ret);
6239e630bcbSAvinash Repaka 	} else {
6249e630bcbSAvinash Repaka 		return ibmr;
6259e630bcbSAvinash Repaka 	}
62608b48a1eSAndy Grover 
62708b48a1eSAndy Grover  out:
6283e0249f9SZach Brown 	if (rds_ibdev)
6293e0249f9SZach Brown 		rds_ib_dev_put(rds_ibdev);
630490ea596Ssantosh.shilimkar@oracle.com 
6319e630bcbSAvinash Repaka 	return ERR_PTR(ret);
63208b48a1eSAndy Grover }
6336fa70da6SChris Mason 
rds_ib_destroy_mr_pool(struct rds_ib_mr_pool * pool)634f6df683fSsantosh.shilimkar@oracle.com void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
635f6df683fSsantosh.shilimkar@oracle.com {
636f6df683fSsantosh.shilimkar@oracle.com 	cancel_delayed_work_sync(&pool->flush_worker);
637f6df683fSsantosh.shilimkar@oracle.com 	rds_ib_flush_mr_pool(pool, 1, NULL);
638f6df683fSsantosh.shilimkar@oracle.com 	WARN_ON(atomic_read(&pool->item_count));
639f6df683fSsantosh.shilimkar@oracle.com 	WARN_ON(atomic_read(&pool->free_pinned));
640f6df683fSsantosh.shilimkar@oracle.com 	kfree(pool);
641f6df683fSsantosh.shilimkar@oracle.com }
642f6df683fSsantosh.shilimkar@oracle.com 
rds_ib_create_mr_pool(struct rds_ib_device * rds_ibdev,int pool_type)643f6df683fSsantosh.shilimkar@oracle.com struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev,
644f6df683fSsantosh.shilimkar@oracle.com 					     int pool_type)
645f6df683fSsantosh.shilimkar@oracle.com {
646f6df683fSsantosh.shilimkar@oracle.com 	struct rds_ib_mr_pool *pool;
647f6df683fSsantosh.shilimkar@oracle.com 
648f6df683fSsantosh.shilimkar@oracle.com 	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
649f6df683fSsantosh.shilimkar@oracle.com 	if (!pool)
650f6df683fSsantosh.shilimkar@oracle.com 		return ERR_PTR(-ENOMEM);
651f6df683fSsantosh.shilimkar@oracle.com 
652f6df683fSsantosh.shilimkar@oracle.com 	pool->pool_type = pool_type;
653f6df683fSsantosh.shilimkar@oracle.com 	init_llist_head(&pool->free_list);
654f6df683fSsantosh.shilimkar@oracle.com 	init_llist_head(&pool->drop_list);
655f6df683fSsantosh.shilimkar@oracle.com 	init_llist_head(&pool->clean_list);
656c9467447SGerd Rausch 	spin_lock_init(&pool->clean_lock);
657f6df683fSsantosh.shilimkar@oracle.com 	mutex_init(&pool->flush_lock);
658f6df683fSsantosh.shilimkar@oracle.com 	init_waitqueue_head(&pool->flush_wait);
659f6df683fSsantosh.shilimkar@oracle.com 	INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
660f6df683fSsantosh.shilimkar@oracle.com 
661f6df683fSsantosh.shilimkar@oracle.com 	if (pool_type == RDS_IB_MR_1M_POOL) {
662f6df683fSsantosh.shilimkar@oracle.com 		/* +1 allows for unaligned MRs */
663*07549ee2SMax Gurtovoy 		pool->max_pages = RDS_MR_1M_MSG_SIZE + 1;
664b1fb67faSAvinash Repaka 		pool->max_items = rds_ibdev->max_1m_mrs;
665f6df683fSsantosh.shilimkar@oracle.com 	} else {
666f6df683fSsantosh.shilimkar@oracle.com 		/* pool_type == RDS_IB_MR_8K_POOL */
667*07549ee2SMax Gurtovoy 		pool->max_pages = RDS_MR_8K_MSG_SIZE + 1;
668b1fb67faSAvinash Repaka 		pool->max_items = rds_ibdev->max_8k_mrs;
669f6df683fSsantosh.shilimkar@oracle.com 	}
670f6df683fSsantosh.shilimkar@oracle.com 
671*07549ee2SMax Gurtovoy 	pool->max_free_pinned = pool->max_items * pool->max_pages / 4;
672f6df683fSsantosh.shilimkar@oracle.com 	pool->max_items_soft = rds_ibdev->max_mrs * 3 / 4;
673f6df683fSsantosh.shilimkar@oracle.com 
674f6df683fSsantosh.shilimkar@oracle.com 	return pool;
675f6df683fSsantosh.shilimkar@oracle.com }
676f6df683fSsantosh.shilimkar@oracle.com 
rds_ib_mr_init(void)677f6df683fSsantosh.shilimkar@oracle.com int rds_ib_mr_init(void)
678f6df683fSsantosh.shilimkar@oracle.com {
679231edca9SBhaktipriya Shridhar 	rds_ib_mr_wq = alloc_workqueue("rds_mr_flushd", WQ_MEM_RECLAIM, 0);
680f6df683fSsantosh.shilimkar@oracle.com 	if (!rds_ib_mr_wq)
681f6df683fSsantosh.shilimkar@oracle.com 		return -ENOMEM;
682f6df683fSsantosh.shilimkar@oracle.com 	return 0;
683f6df683fSsantosh.shilimkar@oracle.com }
684f6df683fSsantosh.shilimkar@oracle.com 
685f6df683fSsantosh.shilimkar@oracle.com /* By the time this is called all the IB devices should have been torn down and
686f6df683fSsantosh.shilimkar@oracle.com  * had their pools freed.  As each pool is freed its work struct is waited on,
687f6df683fSsantosh.shilimkar@oracle.com  * so the pool flushing work queue should be idle by the time we get here.
688f6df683fSsantosh.shilimkar@oracle.com  */
rds_ib_mr_exit(void)689f6df683fSsantosh.shilimkar@oracle.com void rds_ib_mr_exit(void)
690f6df683fSsantosh.shilimkar@oracle.com {
691f6df683fSsantosh.shilimkar@oracle.com 	destroy_workqueue(rds_ib_mr_wq);
692f6df683fSsantosh.shilimkar@oracle.com }
6932eafa174SHans Westgaard Ry 
rds_ib_odp_mr_worker(struct work_struct * work)6942eafa174SHans Westgaard Ry static void rds_ib_odp_mr_worker(struct work_struct  *work)
6952eafa174SHans Westgaard Ry {
6962eafa174SHans Westgaard Ry 	struct rds_ib_mr *ibmr;
6972eafa174SHans Westgaard Ry 
6982eafa174SHans Westgaard Ry 	ibmr = container_of(work, struct rds_ib_mr, work.work);
6992eafa174SHans Westgaard Ry 	ib_dereg_mr(ibmr->u.mr);
7002eafa174SHans Westgaard Ry 	kfree(ibmr);
7012eafa174SHans Westgaard Ry }
702