2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <linux/kernel.h>
34 #include <linux/module.h>
35 #include <linux/io-mapping.h>
36 #include <linux/mlx5/driver.h>
37 #include <linux/mlx5/cmd.h>
38 #include "mlx5_core.h"
40 int mlx5_cmd_alloc_uar(struct mlx5_core_dev
*dev
, u32
*uarn
)
42 u32 out
[MLX5_ST_SZ_DW(alloc_uar_out
)] = {0};
43 u32 in
[MLX5_ST_SZ_DW(alloc_uar_in
)] = {0};
46 MLX5_SET(alloc_uar_in
, in
, opcode
, MLX5_CMD_OP_ALLOC_UAR
);
47 err
= mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
49 *uarn
= MLX5_GET(alloc_uar_out
, out
, uar
);
52 EXPORT_SYMBOL(mlx5_cmd_alloc_uar
);
54 int mlx5_cmd_free_uar(struct mlx5_core_dev
*dev
, u32 uarn
)
56 u32 out
[MLX5_ST_SZ_DW(dealloc_uar_out
)] = {0};
57 u32 in
[MLX5_ST_SZ_DW(dealloc_uar_in
)] = {0};
59 MLX5_SET(dealloc_uar_in
, in
, opcode
, MLX5_CMD_OP_DEALLOC_UAR
);
60 MLX5_SET(dealloc_uar_in
, in
, uar
, uarn
);
61 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
63 EXPORT_SYMBOL(mlx5_cmd_free_uar
);
65 static int uars_per_sys_page(struct mlx5_core_dev
*mdev
)
67 if (MLX5_CAP_GEN(mdev
, uar_4k
))
68 return MLX5_CAP_GEN(mdev
, num_of_uars_per_page
);
73 static u64
uar2pfn(struct mlx5_core_dev
*mdev
, u32 index
)
75 u32 system_page_index
;
77 if (MLX5_CAP_GEN(mdev
, uar_4k
))
78 system_page_index
= index
>> (PAGE_SHIFT
- MLX5_ADAPTER_PAGE_SHIFT
);
80 system_page_index
= index
;
82 return (pci_resource_start(mdev
->pdev
, 0) >> PAGE_SHIFT
) + system_page_index
;
85 static void up_rel_func(struct kref
*kref
)
87 struct mlx5_uars_page
*up
= container_of(kref
, struct mlx5_uars_page
, ref_count
);
91 if (mlx5_cmd_free_uar(up
->mdev
, up
->index
))
92 mlx5_core_warn(up
->mdev
, "failed to free uar index %d\n", up
->index
);
93 kfree(up
->reg_bitmap
);
98 static struct mlx5_uars_page
*alloc_uars_page(struct mlx5_core_dev
*mdev
,
101 struct mlx5_uars_page
*up
;
107 bfregs
= uars_per_sys_page(mdev
) * MLX5_BFREGS_PER_UAR
;
108 up
= kzalloc(sizeof(*up
), GFP_KERNEL
);
113 up
->reg_bitmap
= kcalloc(BITS_TO_LONGS(bfregs
), sizeof(unsigned long), GFP_KERNEL
);
117 up
->fp_bitmap
= kcalloc(BITS_TO_LONGS(bfregs
), sizeof(unsigned long), GFP_KERNEL
);
121 for (i
= 0; i
< bfregs
; i
++)
122 if ((i
% MLX5_BFREGS_PER_UAR
) < MLX5_NON_FP_BFREGS_PER_UAR
)
123 set_bit(i
, up
->reg_bitmap
);
125 set_bit(i
, up
->fp_bitmap
);
128 up
->fp_avail
= bfregs
* MLX5_FP_BFREGS_PER_UAR
/ MLX5_BFREGS_PER_UAR
;
129 up
->reg_avail
= bfregs
* MLX5_NON_FP_BFREGS_PER_UAR
/ MLX5_BFREGS_PER_UAR
;
131 err
= mlx5_cmd_alloc_uar(mdev
, &up
->index
);
133 mlx5_core_warn(mdev
, "mlx5_cmd_alloc_uar() failed, %d\n", err
);
137 pfn
= uar2pfn(mdev
, up
->index
);
139 up
->map
= ioremap_wc(pfn
<< PAGE_SHIFT
, PAGE_SIZE
);
145 up
->map
= ioremap(pfn
<< PAGE_SHIFT
, PAGE_SIZE
);
151 kref_init(&up
->ref_count
);
152 mlx5_core_dbg(mdev
, "allocated UAR page: index %d, total bfregs %d\n",
153 up
->index
, up
->bfregs
);
157 if (mlx5_cmd_free_uar(mdev
, up
->index
))
158 mlx5_core_warn(mdev
, "failed to free uar index %d\n", up
->index
);
160 kfree(up
->fp_bitmap
);
161 kfree(up
->reg_bitmap
);
166 struct mlx5_uars_page
*mlx5_get_uars_page(struct mlx5_core_dev
*mdev
)
168 struct mlx5_uars_page
*ret
;
170 mutex_lock(&mdev
->priv
.bfregs
.reg_head
.lock
);
171 if (!list_empty(&mdev
->priv
.bfregs
.reg_head
.list
)) {
172 ret
= list_first_entry(&mdev
->priv
.bfregs
.reg_head
.list
,
173 struct mlx5_uars_page
, list
);
174 kref_get(&ret
->ref_count
);
177 ret
= alloc_uars_page(mdev
, false);
180 list_add(&ret
->list
, &mdev
->priv
.bfregs
.reg_head
.list
);
182 mutex_unlock(&mdev
->priv
.bfregs
.reg_head
.lock
);
186 EXPORT_SYMBOL(mlx5_get_uars_page
);
188 void mlx5_put_uars_page(struct mlx5_core_dev
*mdev
, struct mlx5_uars_page
*up
)
190 mutex_lock(&mdev
->priv
.bfregs
.reg_head
.lock
);
191 kref_put(&up
->ref_count
, up_rel_func
);
192 mutex_unlock(&mdev
->priv
.bfregs
.reg_head
.lock
);
194 EXPORT_SYMBOL(mlx5_put_uars_page
);
196 static unsigned long map_offset(struct mlx5_core_dev
*mdev
, int dbi
)
198 /* return the offset in bytes from the start of the page to the
199 * blue flame area of the UAR
201 return dbi
/ MLX5_BFREGS_PER_UAR
* MLX5_ADAPTER_PAGE_SIZE
+
202 (dbi
% MLX5_BFREGS_PER_UAR
) *
203 (1 << MLX5_CAP_GEN(mdev
, log_bf_reg_size
)) + MLX5_BF_OFFSET
;
206 static int alloc_bfreg(struct mlx5_core_dev
*mdev
, struct mlx5_sq_bfreg
*bfreg
,
207 bool map_wc
, bool fast_path
)
209 struct mlx5_bfreg_data
*bfregs
;
210 struct mlx5_uars_page
*up
;
211 struct list_head
*head
;
212 unsigned long *bitmap
;
214 struct mutex
*lock
; /* pointer to right mutex */
217 bfregs
= &mdev
->priv
.bfregs
;
219 head
= &bfregs
->wc_head
.list
;
220 lock
= &bfregs
->wc_head
.lock
;
222 head
= &bfregs
->reg_head
.list
;
223 lock
= &bfregs
->reg_head
.lock
;
226 if (list_empty(head
)) {
227 up
= alloc_uars_page(mdev
, map_wc
);
232 list_add(&up
->list
, head
);
234 up
= list_entry(head
->next
, struct mlx5_uars_page
, list
);
235 kref_get(&up
->ref_count
);
238 bitmap
= up
->fp_bitmap
;
239 avail
= &up
->fp_avail
;
241 bitmap
= up
->reg_bitmap
;
242 avail
= &up
->reg_avail
;
244 dbi
= find_first_bit(bitmap
, up
->bfregs
);
245 clear_bit(dbi
, bitmap
);
250 bfreg
->map
= up
->map
+ map_offset(mdev
, dbi
);
253 bfreg
->index
= up
->index
+ dbi
/ MLX5_BFREGS_PER_UAR
;
259 int mlx5_alloc_bfreg(struct mlx5_core_dev
*mdev
, struct mlx5_sq_bfreg
*bfreg
,
260 bool map_wc
, bool fast_path
)
264 err
= alloc_bfreg(mdev
, bfreg
, map_wc
, fast_path
);
268 if (err
== -EAGAIN
&& map_wc
)
269 return alloc_bfreg(mdev
, bfreg
, false, fast_path
);
273 EXPORT_SYMBOL(mlx5_alloc_bfreg
);
275 static unsigned int addr_to_dbi_in_syspage(struct mlx5_core_dev
*dev
,
276 struct mlx5_uars_page
*up
,
277 struct mlx5_sq_bfreg
*bfreg
)
279 unsigned int uar_idx
;
280 unsigned int bfreg_idx
;
281 unsigned int bf_reg_size
;
283 bf_reg_size
= 1 << MLX5_CAP_GEN(dev
, log_bf_reg_size
);
285 uar_idx
= (bfreg
->map
- up
->map
) >> MLX5_ADAPTER_PAGE_SHIFT
;
286 bfreg_idx
= (((uintptr_t)bfreg
->map
% MLX5_ADAPTER_PAGE_SIZE
) - MLX5_BF_OFFSET
) / bf_reg_size
;
288 return uar_idx
* MLX5_BFREGS_PER_UAR
+ bfreg_idx
;
291 void mlx5_free_bfreg(struct mlx5_core_dev
*mdev
, struct mlx5_sq_bfreg
*bfreg
)
293 struct mlx5_bfreg_data
*bfregs
;
294 struct mlx5_uars_page
*up
;
295 struct mutex
*lock
; /* pointer to right mutex */
299 unsigned long *bitmap
;
300 struct list_head
*head
;
302 bfregs
= &mdev
->priv
.bfregs
;
304 head
= &bfregs
->wc_head
.list
;
305 lock
= &bfregs
->wc_head
.lock
;
307 head
= &bfregs
->reg_head
.list
;
308 lock
= &bfregs
->reg_head
.lock
;
311 dbi
= addr_to_dbi_in_syspage(mdev
, up
, bfreg
);
312 fp
= (dbi
% MLX5_BFREGS_PER_UAR
) >= MLX5_NON_FP_BFREGS_PER_UAR
;
314 avail
= &up
->fp_avail
;
315 bitmap
= up
->fp_bitmap
;
317 avail
= &up
->reg_avail
;
318 bitmap
= up
->reg_bitmap
;
322 set_bit(dbi
, bitmap
);
324 list_add_tail(&up
->list
, head
);
326 kref_put(&up
->ref_count
, up_rel_func
);
329 EXPORT_SYMBOL(mlx5_free_bfreg
);