xref: /OK3568_Linux_fs/kernel/drivers/infiniband/hw/hns/hns_roce_alloc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2016 Hisilicon Limited.
3*4882a593Smuzhiyun  * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This software is available to you under a choice of one of two
6*4882a593Smuzhiyun  * licenses.  You may choose to be licensed under the terms of the GNU
7*4882a593Smuzhiyun  * General Public License (GPL) Version 2, available from the file
8*4882a593Smuzhiyun  * COPYING in the main directory of this source tree, or the
9*4882a593Smuzhiyun  * OpenIB.org BSD license below:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *     Redistribution and use in source and binary forms, with or
12*4882a593Smuzhiyun  *     without modification, are permitted provided that the following
13*4882a593Smuzhiyun  *     conditions are met:
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *      - Redistributions of source code must retain the above
16*4882a593Smuzhiyun  *        copyright notice, this list of conditions and the following
17*4882a593Smuzhiyun  *        disclaimer.
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  *      - Redistributions in binary form must reproduce the above
20*4882a593Smuzhiyun  *        copyright notice, this list of conditions and the following
21*4882a593Smuzhiyun  *        disclaimer in the documentation and/or other materials
22*4882a593Smuzhiyun  *        provided with the distribution.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25*4882a593Smuzhiyun  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26*4882a593Smuzhiyun  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27*4882a593Smuzhiyun  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28*4882a593Smuzhiyun  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29*4882a593Smuzhiyun  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30*4882a593Smuzhiyun  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31*4882a593Smuzhiyun  * SOFTWARE.
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include <linux/platform_device.h>
35*4882a593Smuzhiyun #include <linux/vmalloc.h>
36*4882a593Smuzhiyun #include "hns_roce_device.h"
37*4882a593Smuzhiyun #include <rdma/ib_umem.h>
38*4882a593Smuzhiyun 
hns_roce_bitmap_alloc(struct hns_roce_bitmap * bitmap,unsigned long * obj)39*4882a593Smuzhiyun int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	int ret = 0;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	spin_lock(&bitmap->lock);
44*4882a593Smuzhiyun 	*obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
45*4882a593Smuzhiyun 	if (*obj >= bitmap->max) {
46*4882a593Smuzhiyun 		bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
47*4882a593Smuzhiyun 			       & bitmap->mask;
48*4882a593Smuzhiyun 		*obj = find_first_zero_bit(bitmap->table, bitmap->max);
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (*obj < bitmap->max) {
52*4882a593Smuzhiyun 		set_bit(*obj, bitmap->table);
53*4882a593Smuzhiyun 		bitmap->last = (*obj + 1);
54*4882a593Smuzhiyun 		if (bitmap->last == bitmap->max)
55*4882a593Smuzhiyun 			bitmap->last = 0;
56*4882a593Smuzhiyun 		*obj |= bitmap->top;
57*4882a593Smuzhiyun 	} else {
58*4882a593Smuzhiyun 		ret = -EINVAL;
59*4882a593Smuzhiyun 	}
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	spin_unlock(&bitmap->lock);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	return ret;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
hns_roce_bitmap_free(struct hns_roce_bitmap * bitmap,unsigned long obj,int rr)66*4882a593Smuzhiyun void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj,
67*4882a593Smuzhiyun 			  int rr)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	hns_roce_bitmap_free_range(bitmap, obj, 1, rr);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
hns_roce_bitmap_alloc_range(struct hns_roce_bitmap * bitmap,int cnt,int align,unsigned long * obj)72*4882a593Smuzhiyun int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt,
73*4882a593Smuzhiyun 				int align, unsigned long *obj)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	int ret = 0;
76*4882a593Smuzhiyun 	int i;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (likely(cnt == 1 && align == 1))
79*4882a593Smuzhiyun 		return hns_roce_bitmap_alloc(bitmap, obj);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	spin_lock(&bitmap->lock);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	*obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
84*4882a593Smuzhiyun 					  bitmap->last, cnt, align - 1);
85*4882a593Smuzhiyun 	if (*obj >= bitmap->max) {
86*4882a593Smuzhiyun 		bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
87*4882a593Smuzhiyun 			       & bitmap->mask;
88*4882a593Smuzhiyun 		*obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, 0,
89*4882a593Smuzhiyun 						  cnt, align - 1);
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (*obj < bitmap->max) {
93*4882a593Smuzhiyun 		for (i = 0; i < cnt; i++)
94*4882a593Smuzhiyun 			set_bit(*obj + i, bitmap->table);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		if (*obj == bitmap->last) {
97*4882a593Smuzhiyun 			bitmap->last = (*obj + cnt);
98*4882a593Smuzhiyun 			if (bitmap->last >= bitmap->max)
99*4882a593Smuzhiyun 				bitmap->last = 0;
100*4882a593Smuzhiyun 		}
101*4882a593Smuzhiyun 		*obj |= bitmap->top;
102*4882a593Smuzhiyun 	} else {
103*4882a593Smuzhiyun 		ret = -EINVAL;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	spin_unlock(&bitmap->lock);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return ret;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
hns_roce_bitmap_free_range(struct hns_roce_bitmap * bitmap,unsigned long obj,int cnt,int rr)111*4882a593Smuzhiyun void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap,
112*4882a593Smuzhiyun 				unsigned long obj, int cnt,
113*4882a593Smuzhiyun 				int rr)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	int i;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	obj &= bitmap->max + bitmap->reserved_top - 1;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	spin_lock(&bitmap->lock);
120*4882a593Smuzhiyun 	for (i = 0; i < cnt; i++)
121*4882a593Smuzhiyun 		clear_bit(obj + i, bitmap->table);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if (!rr)
124*4882a593Smuzhiyun 		bitmap->last = min(bitmap->last, obj);
125*4882a593Smuzhiyun 	bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
126*4882a593Smuzhiyun 		       & bitmap->mask;
127*4882a593Smuzhiyun 	spin_unlock(&bitmap->lock);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
hns_roce_bitmap_init(struct hns_roce_bitmap * bitmap,u32 num,u32 mask,u32 reserved_bot,u32 reserved_top)130*4882a593Smuzhiyun int hns_roce_bitmap_init(struct hns_roce_bitmap *bitmap, u32 num, u32 mask,
131*4882a593Smuzhiyun 			 u32 reserved_bot, u32 reserved_top)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	u32 i;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (num != roundup_pow_of_two(num))
136*4882a593Smuzhiyun 		return -EINVAL;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	bitmap->last = 0;
139*4882a593Smuzhiyun 	bitmap->top = 0;
140*4882a593Smuzhiyun 	bitmap->max = num - reserved_top;
141*4882a593Smuzhiyun 	bitmap->mask = mask;
142*4882a593Smuzhiyun 	bitmap->reserved_top = reserved_top;
143*4882a593Smuzhiyun 	spin_lock_init(&bitmap->lock);
144*4882a593Smuzhiyun 	bitmap->table = kcalloc(BITS_TO_LONGS(bitmap->max), sizeof(long),
145*4882a593Smuzhiyun 				GFP_KERNEL);
146*4882a593Smuzhiyun 	if (!bitmap->table)
147*4882a593Smuzhiyun 		return -ENOMEM;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	for (i = 0; i < reserved_bot; ++i)
150*4882a593Smuzhiyun 		set_bit(i, bitmap->table);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
hns_roce_bitmap_cleanup(struct hns_roce_bitmap * bitmap)155*4882a593Smuzhiyun void hns_roce_bitmap_cleanup(struct hns_roce_bitmap *bitmap)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	kfree(bitmap->table);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
hns_roce_buf_free(struct hns_roce_dev * hr_dev,struct hns_roce_buf * buf)160*4882a593Smuzhiyun void hns_roce_buf_free(struct hns_roce_dev *hr_dev, struct hns_roce_buf *buf)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	struct device *dev = hr_dev->dev;
163*4882a593Smuzhiyun 	u32 size = buf->size;
164*4882a593Smuzhiyun 	int i;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (size == 0)
167*4882a593Smuzhiyun 		return;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	buf->size = 0;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	if (hns_roce_buf_is_direct(buf)) {
172*4882a593Smuzhiyun 		dma_free_coherent(dev, size, buf->direct.buf, buf->direct.map);
173*4882a593Smuzhiyun 	} else {
174*4882a593Smuzhiyun 		for (i = 0; i < buf->npages; ++i)
175*4882a593Smuzhiyun 			if (buf->page_list[i].buf)
176*4882a593Smuzhiyun 				dma_free_coherent(dev, 1 << buf->page_shift,
177*4882a593Smuzhiyun 						  buf->page_list[i].buf,
178*4882a593Smuzhiyun 						  buf->page_list[i].map);
179*4882a593Smuzhiyun 		kfree(buf->page_list);
180*4882a593Smuzhiyun 		buf->page_list = NULL;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
hns_roce_buf_alloc(struct hns_roce_dev * hr_dev,u32 size,u32 max_direct,struct hns_roce_buf * buf,u32 page_shift)184*4882a593Smuzhiyun int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
185*4882a593Smuzhiyun 		       struct hns_roce_buf *buf, u32 page_shift)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun 	struct hns_roce_buf_list *buf_list;
188*4882a593Smuzhiyun 	struct device *dev = hr_dev->dev;
189*4882a593Smuzhiyun 	u32 page_size;
190*4882a593Smuzhiyun 	int i;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	/* The minimum shift of the page accessed by hw is HNS_HW_PAGE_SHIFT */
193*4882a593Smuzhiyun 	buf->page_shift = max_t(int, HNS_HW_PAGE_SHIFT, page_shift);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	page_size = 1 << buf->page_shift;
196*4882a593Smuzhiyun 	buf->npages = DIV_ROUND_UP(size, page_size);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	/* required size is not bigger than one trunk size */
199*4882a593Smuzhiyun 	if (size <= max_direct) {
200*4882a593Smuzhiyun 		buf->page_list = NULL;
201*4882a593Smuzhiyun 		buf->direct.buf = dma_alloc_coherent(dev, size,
202*4882a593Smuzhiyun 						     &buf->direct.map,
203*4882a593Smuzhiyun 						     GFP_KERNEL);
204*4882a593Smuzhiyun 		if (!buf->direct.buf)
205*4882a593Smuzhiyun 			return -ENOMEM;
206*4882a593Smuzhiyun 	} else {
207*4882a593Smuzhiyun 		buf_list = kcalloc(buf->npages, sizeof(*buf_list), GFP_KERNEL);
208*4882a593Smuzhiyun 		if (!buf_list)
209*4882a593Smuzhiyun 			return -ENOMEM;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		for (i = 0; i < buf->npages; i++) {
212*4882a593Smuzhiyun 			buf_list[i].buf = dma_alloc_coherent(dev, page_size,
213*4882a593Smuzhiyun 							     &buf_list[i].map,
214*4882a593Smuzhiyun 							     GFP_KERNEL);
215*4882a593Smuzhiyun 			if (!buf_list[i].buf)
216*4882a593Smuzhiyun 				break;
217*4882a593Smuzhiyun 		}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 		if (i != buf->npages && i > 0) {
220*4882a593Smuzhiyun 			while (i-- > 0)
221*4882a593Smuzhiyun 				dma_free_coherent(dev, page_size,
222*4882a593Smuzhiyun 						  buf_list[i].buf,
223*4882a593Smuzhiyun 						  buf_list[i].map);
224*4882a593Smuzhiyun 			kfree(buf_list);
225*4882a593Smuzhiyun 			return -ENOMEM;
226*4882a593Smuzhiyun 		}
227*4882a593Smuzhiyun 		buf->page_list = buf_list;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 	buf->size = size;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
hns_roce_get_kmem_bufs(struct hns_roce_dev * hr_dev,dma_addr_t * bufs,int buf_cnt,int start,struct hns_roce_buf * buf)234*4882a593Smuzhiyun int hns_roce_get_kmem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
235*4882a593Smuzhiyun 			   int buf_cnt, int start, struct hns_roce_buf *buf)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	int i, end;
238*4882a593Smuzhiyun 	int total;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	end = start + buf_cnt;
241*4882a593Smuzhiyun 	if (end > buf->npages) {
242*4882a593Smuzhiyun 		dev_err(hr_dev->dev,
243*4882a593Smuzhiyun 			"failed to check kmem bufs, end %d + %d total %u!\n",
244*4882a593Smuzhiyun 			start, buf_cnt, buf->npages);
245*4882a593Smuzhiyun 		return -EINVAL;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	total = 0;
249*4882a593Smuzhiyun 	for (i = start; i < end; i++)
250*4882a593Smuzhiyun 		bufs[total++] = hns_roce_buf_page(buf, i);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	return total;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
hns_roce_get_umem_bufs(struct hns_roce_dev * hr_dev,dma_addr_t * bufs,int buf_cnt,int start,struct ib_umem * umem,unsigned int page_shift)255*4882a593Smuzhiyun int hns_roce_get_umem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
256*4882a593Smuzhiyun 			   int buf_cnt, int start, struct ib_umem *umem,
257*4882a593Smuzhiyun 			   unsigned int page_shift)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct ib_block_iter biter;
260*4882a593Smuzhiyun 	int total = 0;
261*4882a593Smuzhiyun 	int idx = 0;
262*4882a593Smuzhiyun 	u64 addr;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (page_shift < HNS_HW_PAGE_SHIFT) {
265*4882a593Smuzhiyun 		dev_err(hr_dev->dev, "failed to check umem page shift %u!\n",
266*4882a593Smuzhiyun 			page_shift);
267*4882a593Smuzhiyun 		return -EINVAL;
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	/* convert system page cnt to hw page cnt */
271*4882a593Smuzhiyun 	rdma_umem_for_each_dma_block(umem, &biter, 1 << page_shift) {
272*4882a593Smuzhiyun 		addr = rdma_block_iter_dma_address(&biter);
273*4882a593Smuzhiyun 		if (idx >= start) {
274*4882a593Smuzhiyun 			bufs[total++] = addr;
275*4882a593Smuzhiyun 			if (total >= buf_cnt)
276*4882a593Smuzhiyun 				goto done;
277*4882a593Smuzhiyun 		}
278*4882a593Smuzhiyun 		idx++;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun done:
282*4882a593Smuzhiyun 	return total;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
hns_roce_cleanup_bitmap(struct hns_roce_dev * hr_dev)285*4882a593Smuzhiyun void hns_roce_cleanup_bitmap(struct hns_roce_dev *hr_dev)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ)
288*4882a593Smuzhiyun 		hns_roce_cleanup_srq_table(hr_dev);
289*4882a593Smuzhiyun 	hns_roce_cleanup_qp_table(hr_dev);
290*4882a593Smuzhiyun 	hns_roce_cleanup_cq_table(hr_dev);
291*4882a593Smuzhiyun 	hns_roce_cleanup_mr_table(hr_dev);
292*4882a593Smuzhiyun 	hns_roce_cleanup_pd_table(hr_dev);
293*4882a593Smuzhiyun 	hns_roce_cleanup_uar_table(hr_dev);
294*4882a593Smuzhiyun }
295