1 | /* |
2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
3 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. |
4 | * |
5 | * This software is available to you under a choice of one of two |
6 | * licenses. You may choose to be licensed under the terms of the GNU |
7 | * General Public License (GPL) Version 2, available from the file |
8 | * COPYING in the main directory of this source tree, or the |
9 | * OpenIB.org BSD license below: |
10 | * |
11 | * Redistribution and use in source and binary forms, with or |
12 | * without modification, are permitted provided that the following |
13 | * conditions are met: |
14 | * |
15 | * - Redistributions of source code must retain the above |
16 | * copyright notice, this list of conditions and the following |
17 | * disclaimer. |
18 | * |
19 | * - Redistributions in binary form must reproduce the above |
20 | * copyright notice, this list of conditions and the following |
21 | * disclaimer in the documentation and/or other materials |
22 | * provided with the distribution. |
23 | * |
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
31 | * SOFTWARE. |
32 | */ |
33 | |
34 | #include <linux/errno.h> |
35 | #include <linux/export.h> |
36 | #include <linux/io-mapping.h> |
37 | |
38 | #include <asm/page.h> |
39 | |
40 | #include "mlx4.h" |
41 | #include "icm.h" |
42 | |
43 | enum { |
44 | MLX4_NUM_RESERVED_UARS = 8 |
45 | }; |
46 | |
47 | int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) |
48 | { |
49 | struct mlx4_priv *priv = mlx4_priv(dev); |
50 | |
51 | *pdn = mlx4_bitmap_alloc(bitmap: &priv->pd_bitmap); |
52 | if (*pdn == -1) |
53 | return -ENOMEM; |
54 | |
55 | return 0; |
56 | } |
57 | EXPORT_SYMBOL_GPL(mlx4_pd_alloc); |
58 | |
59 | void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) |
60 | { |
61 | mlx4_bitmap_free(bitmap: &mlx4_priv(dev)->pd_bitmap, obj: pdn, use_rr: MLX4_USE_RR); |
62 | } |
63 | EXPORT_SYMBOL_GPL(mlx4_pd_free); |
64 | |
65 | int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) |
66 | { |
67 | struct mlx4_priv *priv = mlx4_priv(dev); |
68 | |
69 | *xrcdn = mlx4_bitmap_alloc(bitmap: &priv->xrcd_bitmap); |
70 | if (*xrcdn == -1) |
71 | return -ENOMEM; |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) |
77 | { |
78 | u64 out_param; |
79 | int err; |
80 | |
81 | if (mlx4_is_mfunc(dev)) { |
82 | err = mlx4_cmd_imm(dev, in_param: 0, out_param: &out_param, |
83 | in_modifier: RES_XRCD, op_modifier: RES_OP_RESERVE, |
84 | op: MLX4_CMD_ALLOC_RES, |
85 | timeout: MLX4_CMD_TIME_CLASS_A, native: MLX4_CMD_WRAPPED); |
86 | if (err) |
87 | return err; |
88 | |
89 | *xrcdn = get_param_l(arg: &out_param); |
90 | return 0; |
91 | } |
92 | return __mlx4_xrcd_alloc(dev, xrcdn); |
93 | } |
94 | EXPORT_SYMBOL_GPL(mlx4_xrcd_alloc); |
95 | |
96 | void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) |
97 | { |
98 | mlx4_bitmap_free(bitmap: &mlx4_priv(dev)->xrcd_bitmap, obj: xrcdn, use_rr: MLX4_USE_RR); |
99 | } |
100 | |
101 | void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) |
102 | { |
103 | u64 in_param = 0; |
104 | int err; |
105 | |
106 | if (mlx4_is_mfunc(dev)) { |
107 | set_param_l(arg: &in_param, val: xrcdn); |
108 | err = mlx4_cmd(dev, in_param, in_modifier: RES_XRCD, |
109 | op_modifier: RES_OP_RESERVE, op: MLX4_CMD_FREE_RES, |
110 | timeout: MLX4_CMD_TIME_CLASS_A, native: MLX4_CMD_WRAPPED); |
111 | if (err) |
112 | mlx4_warn(dev, "Failed to release xrcdn %d\n" , xrcdn); |
113 | } else |
114 | __mlx4_xrcd_free(dev, xrcdn); |
115 | } |
116 | EXPORT_SYMBOL_GPL(mlx4_xrcd_free); |
117 | |
118 | int mlx4_init_pd_table(struct mlx4_dev *dev) |
119 | { |
120 | struct mlx4_priv *priv = mlx4_priv(dev); |
121 | |
122 | return mlx4_bitmap_init(bitmap: &priv->pd_bitmap, num: dev->caps.num_pds, |
123 | mask: (1 << NOT_MASKED_PD_BITS) - 1, |
124 | reserved_bot: dev->caps.reserved_pds, resetrved_top: 0); |
125 | } |
126 | |
127 | void mlx4_cleanup_pd_table(struct mlx4_dev *dev) |
128 | { |
129 | mlx4_bitmap_cleanup(bitmap: &mlx4_priv(dev)->pd_bitmap); |
130 | } |
131 | |
132 | int mlx4_init_xrcd_table(struct mlx4_dev *dev) |
133 | { |
134 | struct mlx4_priv *priv = mlx4_priv(dev); |
135 | |
136 | return mlx4_bitmap_init(bitmap: &priv->xrcd_bitmap, num: (1 << 16), |
137 | mask: (1 << 16) - 1, reserved_bot: dev->caps.reserved_xrcds + 1, resetrved_top: 0); |
138 | } |
139 | |
140 | void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev) |
141 | { |
142 | mlx4_bitmap_cleanup(bitmap: &mlx4_priv(dev)->xrcd_bitmap); |
143 | } |
144 | |
145 | int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) |
146 | { |
147 | int offset; |
148 | |
149 | uar->index = mlx4_bitmap_alloc(bitmap: &mlx4_priv(dev)->uar_table.bitmap); |
150 | if (uar->index == -1) |
151 | return -ENOMEM; |
152 | |
153 | if (mlx4_is_slave(dev)) |
154 | offset = uar->index % ((int)pci_resource_len(dev->persist->pdev, |
155 | 2) / |
156 | dev->caps.uar_page_size); |
157 | else |
158 | offset = uar->index; |
159 | uar->pfn = (pci_resource_start(dev->persist->pdev, 2) >> PAGE_SHIFT) |
160 | + offset; |
161 | uar->map = NULL; |
162 | return 0; |
163 | } |
164 | EXPORT_SYMBOL_GPL(mlx4_uar_alloc); |
165 | |
166 | void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) |
167 | { |
168 | mlx4_bitmap_free(bitmap: &mlx4_priv(dev)->uar_table.bitmap, obj: uar->index, use_rr: MLX4_USE_RR); |
169 | } |
170 | EXPORT_SYMBOL_GPL(mlx4_uar_free); |
171 | |
172 | int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) |
173 | { |
174 | struct mlx4_priv *priv = mlx4_priv(dev); |
175 | struct mlx4_uar *uar; |
176 | int err = 0; |
177 | int idx; |
178 | |
179 | if (!priv->bf_mapping) |
180 | return -ENOMEM; |
181 | |
182 | mutex_lock(&priv->bf_mutex); |
183 | if (!list_empty(head: &priv->bf_list)) |
184 | uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); |
185 | else { |
186 | if (mlx4_bitmap_avail(bitmap: &priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { |
187 | err = -ENOMEM; |
188 | goto out; |
189 | } |
190 | uar = kmalloc_node(size: sizeof(*uar), GFP_KERNEL, node); |
191 | if (!uar) { |
192 | uar = kmalloc(size: sizeof(*uar), GFP_KERNEL); |
193 | if (!uar) { |
194 | err = -ENOMEM; |
195 | goto out; |
196 | } |
197 | } |
198 | err = mlx4_uar_alloc(dev, uar); |
199 | if (err) |
200 | goto free_kmalloc; |
201 | |
202 | uar->map = ioremap(offset: uar->pfn << PAGE_SHIFT, PAGE_SIZE); |
203 | if (!uar->map) { |
204 | err = -ENOMEM; |
205 | goto free_uar; |
206 | } |
207 | |
208 | uar->bf_map = io_mapping_map_wc(mapping: priv->bf_mapping, |
209 | offset: uar->index << PAGE_SHIFT, |
210 | PAGE_SIZE); |
211 | if (!uar->bf_map) { |
212 | err = -ENOMEM; |
213 | goto unamp_uar; |
214 | } |
215 | uar->free_bf_bmap = 0; |
216 | list_add(new: &uar->bf_list, head: &priv->bf_list); |
217 | } |
218 | |
219 | idx = ffz(uar->free_bf_bmap); |
220 | uar->free_bf_bmap |= 1 << idx; |
221 | bf->uar = uar; |
222 | bf->offset = 0; |
223 | bf->buf_size = dev->caps.bf_reg_size / 2; |
224 | bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; |
225 | if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) |
226 | list_del_init(entry: &uar->bf_list); |
227 | |
228 | goto out; |
229 | |
230 | unamp_uar: |
231 | bf->uar = NULL; |
232 | iounmap(addr: uar->map); |
233 | |
234 | free_uar: |
235 | mlx4_uar_free(dev, uar); |
236 | |
237 | free_kmalloc: |
238 | kfree(objp: uar); |
239 | |
240 | out: |
241 | mutex_unlock(lock: &priv->bf_mutex); |
242 | return err; |
243 | } |
244 | EXPORT_SYMBOL_GPL(mlx4_bf_alloc); |
245 | |
246 | void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) |
247 | { |
248 | struct mlx4_priv *priv = mlx4_priv(dev); |
249 | int idx; |
250 | |
251 | if (!bf->uar || !bf->uar->bf_map) |
252 | return; |
253 | |
254 | mutex_lock(&priv->bf_mutex); |
255 | idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; |
256 | bf->uar->free_bf_bmap &= ~(1 << idx); |
257 | if (!bf->uar->free_bf_bmap) { |
258 | if (!list_empty(head: &bf->uar->bf_list)) |
259 | list_del(entry: &bf->uar->bf_list); |
260 | |
261 | io_mapping_unmap(vaddr: bf->uar->bf_map); |
262 | iounmap(addr: bf->uar->map); |
263 | mlx4_uar_free(dev, bf->uar); |
264 | kfree(objp: bf->uar); |
265 | } else if (list_empty(head: &bf->uar->bf_list)) |
266 | list_add(new: &bf->uar->bf_list, head: &priv->bf_list); |
267 | |
268 | mutex_unlock(lock: &priv->bf_mutex); |
269 | } |
270 | EXPORT_SYMBOL_GPL(mlx4_bf_free); |
271 | |
272 | int mlx4_init_uar_table(struct mlx4_dev *dev) |
273 | { |
274 | int num_reserved_uar = mlx4_get_num_reserved_uar(dev); |
275 | |
276 | mlx4_dbg(dev, "uar_page_shift = %d" , dev->uar_page_shift); |
277 | mlx4_dbg(dev, "Effective reserved_uars=%d" , dev->caps.reserved_uars); |
278 | |
279 | if (dev->caps.num_uars <= num_reserved_uar) { |
280 | mlx4_err( |
281 | dev, "Only %d UAR pages (need more than %d)\n" , |
282 | dev->caps.num_uars, num_reserved_uar); |
283 | mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n" ); |
284 | return -ENODEV; |
285 | } |
286 | |
287 | return mlx4_bitmap_init(bitmap: &mlx4_priv(dev)->uar_table.bitmap, |
288 | num: dev->caps.num_uars, mask: dev->caps.num_uars - 1, |
289 | reserved_bot: dev->caps.reserved_uars, resetrved_top: 0); |
290 | } |
291 | |
292 | void mlx4_cleanup_uar_table(struct mlx4_dev *dev) |
293 | { |
294 | mlx4_bitmap_cleanup(bitmap: &mlx4_priv(dev)->uar_table.bitmap); |
295 | } |
296 | |