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