diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4/mr.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mr.c | 401 |
1 files changed, 360 insertions, 41 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 057b22d64a05..916eba4572b7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c | |||
@@ -32,9 +32,11 @@ | |||
32 | * SOFTWARE. | 32 | * SOFTWARE. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/init.h> | ||
35 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
36 | #include <linux/export.h> | 37 | #include <linux/export.h> |
37 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/kernel.h> | ||
38 | 40 | ||
39 | #include <linux/mlx4/cmd.h> | 41 | #include <linux/mlx4/cmd.h> |
40 | 42 | ||
@@ -180,7 +182,7 @@ static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy) | |||
180 | kfree(buddy->num_free); | 182 | kfree(buddy->num_free); |
181 | } | 183 | } |
182 | 184 | ||
183 | static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) | 185 | static u32 __mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) |
184 | { | 186 | { |
185 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; | 187 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; |
186 | u32 seg; | 188 | u32 seg; |
@@ -198,6 +200,26 @@ static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) | |||
198 | return seg; | 200 | return seg; |
199 | } | 201 | } |
200 | 202 | ||
203 | static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) | ||
204 | { | ||
205 | u64 in_param; | ||
206 | u64 out_param; | ||
207 | int err; | ||
208 | |||
209 | if (mlx4_is_mfunc(dev)) { | ||
210 | set_param_l(&in_param, order); | ||
211 | err = mlx4_cmd_imm(dev, in_param, &out_param, RES_MTT, | ||
212 | RES_OP_RESERVE_AND_MAP, | ||
213 | MLX4_CMD_ALLOC_RES, | ||
214 | MLX4_CMD_TIME_CLASS_A, | ||
215 | MLX4_CMD_WRAPPED); | ||
216 | if (err) | ||
217 | return -1; | ||
218 | return get_param_l(&out_param); | ||
219 | } | ||
220 | return __mlx4_alloc_mtt_range(dev, order); | ||
221 | } | ||
222 | |||
201 | int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, | 223 | int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, |
202 | struct mlx4_mtt *mtt) | 224 | struct mlx4_mtt *mtt) |
203 | { | 225 | { |
@@ -221,16 +243,42 @@ int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, | |||
221 | } | 243 | } |
222 | EXPORT_SYMBOL_GPL(mlx4_mtt_init); | 244 | EXPORT_SYMBOL_GPL(mlx4_mtt_init); |
223 | 245 | ||
224 | void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt) | 246 | static void __mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, |
247 | int order) | ||
225 | { | 248 | { |
226 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; | 249 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; |
227 | 250 | ||
251 | mlx4_buddy_free(&mr_table->mtt_buddy, first_seg, order); | ||
252 | mlx4_table_put_range(dev, &mr_table->mtt_table, first_seg, | ||
253 | first_seg + (1 << order) - 1); | ||
254 | } | ||
255 | |||
256 | static void mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order) | ||
257 | { | ||
258 | u64 in_param; | ||
259 | int err; | ||
260 | |||
261 | if (mlx4_is_mfunc(dev)) { | ||
262 | set_param_l(&in_param, first_seg); | ||
263 | set_param_h(&in_param, order); | ||
264 | err = mlx4_cmd(dev, in_param, RES_MTT, RES_OP_RESERVE_AND_MAP, | ||
265 | MLX4_CMD_FREE_RES, | ||
266 | MLX4_CMD_TIME_CLASS_A, | ||
267 | MLX4_CMD_WRAPPED); | ||
268 | if (err) | ||
269 | mlx4_warn(dev, "Failed to free mtt range at:%d" | ||
270 | " order:%d\n", first_seg, order); | ||
271 | return; | ||
272 | } | ||
273 | __mlx4_free_mtt_range(dev, first_seg, order); | ||
274 | } | ||
275 | |||
276 | void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt) | ||
277 | { | ||
228 | if (mtt->order < 0) | 278 | if (mtt->order < 0) |
229 | return; | 279 | return; |
230 | 280 | ||
231 | mlx4_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order); | 281 | mlx4_free_mtt_range(dev, mtt->first_seg, mtt->order); |
232 | mlx4_table_put_range(dev, &mr_table->mtt_table, mtt->first_seg, | ||
233 | mtt->first_seg + (1 << mtt->order) - 1); | ||
234 | } | 282 | } |
235 | EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup); | 283 | EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup); |
236 | 284 | ||
@@ -253,8 +301,9 @@ static u32 key_to_hw_index(u32 key) | |||
253 | static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, | 301 | static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, |
254 | int mpt_index) | 302 | int mpt_index) |
255 | { | 303 | { |
256 | return mlx4_cmd(dev, mailbox->dma, mpt_index, 0, MLX4_CMD_SW2HW_MPT, | 304 | return mlx4_cmd(dev, mailbox->dma | dev->caps.function , mpt_index, |
257 | MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); | 305 | 0, MLX4_CMD_SW2HW_MPT, MLX4_CMD_TIME_CLASS_B, |
306 | MLX4_CMD_WRAPPED); | ||
258 | } | 307 | } |
259 | 308 | ||
260 | static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, | 309 | static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, |
@@ -265,58 +314,192 @@ static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox | |||
265 | MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); | 314 | MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); |
266 | } | 315 | } |
267 | 316 | ||
268 | int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, | 317 | static int mlx4_mr_reserve_range(struct mlx4_dev *dev, int cnt, int align, |
269 | int npages, int page_shift, struct mlx4_mr *mr) | 318 | u32 *base_mridx) |
270 | { | 319 | { |
271 | struct mlx4_priv *priv = mlx4_priv(dev); | 320 | struct mlx4_priv *priv = mlx4_priv(dev); |
272 | u32 index; | 321 | u32 mridx; |
273 | int err; | ||
274 | 322 | ||
275 | index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap); | 323 | mridx = mlx4_bitmap_alloc_range(&priv->mr_table.mpt_bitmap, cnt, align); |
276 | if (index == -1) | 324 | if (mridx == -1) |
277 | return -ENOMEM; | 325 | return -ENOMEM; |
278 | 326 | ||
327 | *base_mridx = mridx; | ||
328 | return 0; | ||
329 | |||
330 | } | ||
331 | EXPORT_SYMBOL_GPL(mlx4_mr_reserve_range); | ||
332 | |||
333 | static void mlx4_mr_release_range(struct mlx4_dev *dev, u32 base_mridx, int cnt) | ||
334 | { | ||
335 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
336 | mlx4_bitmap_free_range(&priv->mr_table.mpt_bitmap, base_mridx, cnt); | ||
337 | } | ||
338 | EXPORT_SYMBOL_GPL(mlx4_mr_release_range); | ||
339 | |||
340 | static int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, | ||
341 | u64 iova, u64 size, u32 access, int npages, | ||
342 | int page_shift, struct mlx4_mr *mr) | ||
343 | { | ||
279 | mr->iova = iova; | 344 | mr->iova = iova; |
280 | mr->size = size; | 345 | mr->size = size; |
281 | mr->pd = pd; | 346 | mr->pd = pd; |
282 | mr->access = access; | 347 | mr->access = access; |
283 | mr->enabled = 0; | 348 | mr->enabled = MLX4_MR_DISABLED; |
284 | mr->key = hw_index_to_key(index); | 349 | mr->key = hw_index_to_key(mridx); |
350 | |||
351 | return mlx4_mtt_init(dev, npages, page_shift, &mr->mtt); | ||
352 | } | ||
353 | EXPORT_SYMBOL_GPL(mlx4_mr_alloc_reserved); | ||
354 | |||
355 | static int mlx4_WRITE_MTT(struct mlx4_dev *dev, | ||
356 | struct mlx4_cmd_mailbox *mailbox, | ||
357 | int num_entries) | ||
358 | { | ||
359 | return mlx4_cmd(dev, mailbox->dma, num_entries, 0, MLX4_CMD_WRITE_MTT, | ||
360 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); | ||
361 | } | ||
362 | |||
363 | static int __mlx4_mr_reserve(struct mlx4_dev *dev) | ||
364 | { | ||
365 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
366 | |||
367 | return mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap); | ||
368 | } | ||
285 | 369 | ||
286 | err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt); | 370 | static int mlx4_mr_reserve(struct mlx4_dev *dev) |
371 | { | ||
372 | u64 out_param; | ||
373 | |||
374 | if (mlx4_is_mfunc(dev)) { | ||
375 | if (mlx4_cmd_imm(dev, 0, &out_param, RES_MPT, RES_OP_RESERVE, | ||
376 | MLX4_CMD_ALLOC_RES, | ||
377 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) | ||
378 | return -1; | ||
379 | return get_param_l(&out_param); | ||
380 | } | ||
381 | return __mlx4_mr_reserve(dev); | ||
382 | } | ||
383 | |||
384 | static void __mlx4_mr_release(struct mlx4_dev *dev, u32 index) | ||
385 | { | ||
386 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
387 | |||
388 | mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index); | ||
389 | } | ||
390 | |||
391 | static void mlx4_mr_release(struct mlx4_dev *dev, u32 index) | ||
392 | { | ||
393 | u64 in_param; | ||
394 | |||
395 | if (mlx4_is_mfunc(dev)) { | ||
396 | set_param_l(&in_param, index); | ||
397 | if (mlx4_cmd(dev, in_param, RES_MPT, RES_OP_RESERVE, | ||
398 | MLX4_CMD_FREE_RES, | ||
399 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED)) | ||
400 | mlx4_warn(dev, "Failed to release mr index:%d\n", | ||
401 | index); | ||
402 | return; | ||
403 | } | ||
404 | __mlx4_mr_release(dev, index); | ||
405 | } | ||
406 | |||
407 | static int __mlx4_mr_alloc_icm(struct mlx4_dev *dev, u32 index) | ||
408 | { | ||
409 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; | ||
410 | |||
411 | return mlx4_table_get(dev, &mr_table->dmpt_table, index); | ||
412 | } | ||
413 | |||
414 | static int mlx4_mr_alloc_icm(struct mlx4_dev *dev, u32 index) | ||
415 | { | ||
416 | u64 param; | ||
417 | |||
418 | if (mlx4_is_mfunc(dev)) { | ||
419 | set_param_l(¶m, index); | ||
420 | return mlx4_cmd_imm(dev, param, ¶m, RES_MPT, RES_OP_MAP_ICM, | ||
421 | MLX4_CMD_ALLOC_RES, | ||
422 | MLX4_CMD_TIME_CLASS_A, | ||
423 | MLX4_CMD_WRAPPED); | ||
424 | } | ||
425 | return __mlx4_mr_alloc_icm(dev, index); | ||
426 | } | ||
427 | |||
428 | static void __mlx4_mr_free_icm(struct mlx4_dev *dev, u32 index) | ||
429 | { | ||
430 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; | ||
431 | |||
432 | mlx4_table_put(dev, &mr_table->dmpt_table, index); | ||
433 | } | ||
434 | |||
435 | static void mlx4_mr_free_icm(struct mlx4_dev *dev, u32 index) | ||
436 | { | ||
437 | u64 in_param; | ||
438 | |||
439 | if (mlx4_is_mfunc(dev)) { | ||
440 | set_param_l(&in_param, index); | ||
441 | if (mlx4_cmd(dev, in_param, RES_MPT, RES_OP_MAP_ICM, | ||
442 | MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, | ||
443 | MLX4_CMD_WRAPPED)) | ||
444 | mlx4_warn(dev, "Failed to free icm of mr index:%d\n", | ||
445 | index); | ||
446 | return; | ||
447 | } | ||
448 | return __mlx4_mr_free_icm(dev, index); | ||
449 | } | ||
450 | |||
451 | int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, | ||
452 | int npages, int page_shift, struct mlx4_mr *mr) | ||
453 | { | ||
454 | u32 index; | ||
455 | int err; | ||
456 | |||
457 | index = mlx4_mr_reserve(dev); | ||
458 | if (index == -1) | ||
459 | return -ENOMEM; | ||
460 | |||
461 | err = mlx4_mr_alloc_reserved(dev, index, pd, iova, size, | ||
462 | access, npages, page_shift, mr); | ||
287 | if (err) | 463 | if (err) |
288 | mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index); | 464 | mlx4_mr_release(dev, index); |
289 | 465 | ||
290 | return err; | 466 | return err; |
291 | } | 467 | } |
292 | EXPORT_SYMBOL_GPL(mlx4_mr_alloc); | 468 | EXPORT_SYMBOL_GPL(mlx4_mr_alloc); |
293 | 469 | ||
294 | void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr) | 470 | static void mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr) |
295 | { | 471 | { |
296 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
297 | int err; | 472 | int err; |
298 | 473 | ||
299 | if (mr->enabled) { | 474 | if (mr->enabled == MLX4_MR_EN_HW) { |
300 | err = mlx4_HW2SW_MPT(dev, NULL, | 475 | err = mlx4_HW2SW_MPT(dev, NULL, |
301 | key_to_hw_index(mr->key) & | 476 | key_to_hw_index(mr->key) & |
302 | (dev->caps.num_mpts - 1)); | 477 | (dev->caps.num_mpts - 1)); |
303 | if (err) | 478 | if (err) |
304 | mlx4_warn(dev, "HW2SW_MPT failed (%d)\n", err); | 479 | mlx4_warn(dev, "xxx HW2SW_MPT failed (%d)\n", err); |
305 | } | ||
306 | 480 | ||
481 | mr->enabled = MLX4_MR_EN_SW; | ||
482 | } | ||
307 | mlx4_mtt_cleanup(dev, &mr->mtt); | 483 | mlx4_mtt_cleanup(dev, &mr->mtt); |
308 | mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, key_to_hw_index(mr->key)); | 484 | } |
485 | EXPORT_SYMBOL_GPL(mlx4_mr_free_reserved); | ||
486 | |||
487 | void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr) | ||
488 | { | ||
489 | mlx4_mr_free_reserved(dev, mr); | ||
490 | if (mr->enabled) | ||
491 | mlx4_mr_free_icm(dev, key_to_hw_index(mr->key)); | ||
492 | mlx4_mr_release(dev, key_to_hw_index(mr->key)); | ||
309 | } | 493 | } |
310 | EXPORT_SYMBOL_GPL(mlx4_mr_free); | 494 | EXPORT_SYMBOL_GPL(mlx4_mr_free); |
311 | 495 | ||
312 | int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) | 496 | int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) |
313 | { | 497 | { |
314 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; | ||
315 | struct mlx4_cmd_mailbox *mailbox; | 498 | struct mlx4_cmd_mailbox *mailbox; |
316 | struct mlx4_mpt_entry *mpt_entry; | 499 | struct mlx4_mpt_entry *mpt_entry; |
317 | int err; | 500 | int err; |
318 | 501 | ||
319 | err = mlx4_table_get(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); | 502 | err = mlx4_mr_alloc_icm(dev, key_to_hw_index(mr->key)); |
320 | if (err) | 503 | if (err) |
321 | return err; | 504 | return err; |
322 | 505 | ||
@@ -363,8 +546,7 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) | |||
363 | mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); | 546 | mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); |
364 | goto err_cmd; | 547 | goto err_cmd; |
365 | } | 548 | } |
366 | 549 | mr->enabled = MLX4_MR_EN_HW; | |
367 | mr->enabled = 1; | ||
368 | 550 | ||
369 | mlx4_free_cmd_mailbox(dev, mailbox); | 551 | mlx4_free_cmd_mailbox(dev, mailbox); |
370 | 552 | ||
@@ -374,7 +556,7 @@ err_cmd: | |||
374 | mlx4_free_cmd_mailbox(dev, mailbox); | 556 | mlx4_free_cmd_mailbox(dev, mailbox); |
375 | 557 | ||
376 | err_table: | 558 | err_table: |
377 | mlx4_table_put(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); | 559 | mlx4_mr_free_icm(dev, key_to_hw_index(mr->key)); |
378 | return err; | 560 | return err; |
379 | } | 561 | } |
380 | EXPORT_SYMBOL_GPL(mlx4_mr_enable); | 562 | EXPORT_SYMBOL_GPL(mlx4_mr_enable); |
@@ -413,27 +595,74 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, | |||
413 | return 0; | 595 | return 0; |
414 | } | 596 | } |
415 | 597 | ||
416 | int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, | 598 | static int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, |
417 | int start_index, int npages, u64 *page_list) | 599 | int start_index, int npages, u64 *page_list) |
418 | { | 600 | { |
601 | int err = 0; | ||
419 | int chunk; | 602 | int chunk; |
420 | int err; | ||
421 | |||
422 | if (mtt->order < 0) | ||
423 | return -EINVAL; | ||
424 | 603 | ||
425 | while (npages > 0) { | 604 | while (npages > 0) { |
426 | chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); | 605 | chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); |
427 | err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); | 606 | err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); |
428 | if (err) | 607 | if (err) |
429 | return err; | 608 | return err; |
430 | |||
431 | npages -= chunk; | 609 | npages -= chunk; |
432 | start_index += chunk; | 610 | start_index += chunk; |
433 | page_list += chunk; | 611 | page_list += chunk; |
434 | } | 612 | } |
613 | return err; | ||
614 | } | ||
435 | 615 | ||
436 | return 0; | 616 | int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, |
617 | int start_index, int npages, u64 *page_list) | ||
618 | { | ||
619 | struct mlx4_cmd_mailbox *mailbox = NULL; | ||
620 | __be64 *inbox = NULL; | ||
621 | int chunk; | ||
622 | int err = 0; | ||
623 | int i; | ||
624 | |||
625 | if (mtt->order < 0) | ||
626 | return -EINVAL; | ||
627 | |||
628 | if (mlx4_is_mfunc(dev)) { | ||
629 | mailbox = mlx4_alloc_cmd_mailbox(dev); | ||
630 | if (IS_ERR(mailbox)) | ||
631 | return PTR_ERR(mailbox); | ||
632 | inbox = mailbox->buf; | ||
633 | |||
634 | while (npages > 0) { | ||
635 | int s = mtt->first_seg * dev->caps.mtts_per_seg + | ||
636 | start_index; | ||
637 | chunk = min_t(int, MLX4_MAILBOX_SIZE / sizeof(u64) - | ||
638 | dev->caps.mtts_per_seg, npages); | ||
639 | if (s / (PAGE_SIZE / sizeof(u64)) != | ||
640 | (s + chunk - 1) / (PAGE_SIZE / sizeof(u64))) | ||
641 | chunk = PAGE_SIZE / sizeof(u64) - | ||
642 | (s % (PAGE_SIZE / sizeof(u64))); | ||
643 | |||
644 | inbox[0] = cpu_to_be64(mtt->first_seg * | ||
645 | dev->caps.mtts_per_seg + | ||
646 | start_index); | ||
647 | inbox[1] = 0; | ||
648 | for (i = 0; i < chunk; ++i) | ||
649 | inbox[i + 2] = cpu_to_be64(page_list[i] | | ||
650 | MLX4_MTT_FLAG_PRESENT); | ||
651 | err = mlx4_WRITE_MTT(dev, mailbox, chunk); | ||
652 | if (err) { | ||
653 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
654 | return err; | ||
655 | } | ||
656 | |||
657 | npages -= chunk; | ||
658 | start_index += chunk; | ||
659 | page_list += chunk; | ||
660 | } | ||
661 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
662 | return err; | ||
663 | } | ||
664 | |||
665 | return __mlx4_write_mtt(dev, mtt, start_index, npages, page_list); | ||
437 | } | 666 | } |
438 | EXPORT_SYMBOL_GPL(mlx4_write_mtt); | 667 | EXPORT_SYMBOL_GPL(mlx4_write_mtt); |
439 | 668 | ||
@@ -463,9 +692,18 @@ EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); | |||
463 | 692 | ||
464 | int mlx4_init_mr_table(struct mlx4_dev *dev) | 693 | int mlx4_init_mr_table(struct mlx4_dev *dev) |
465 | { | 694 | { |
466 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; | 695 | struct mlx4_priv *priv = mlx4_priv(dev); |
696 | struct mlx4_mr_table *mr_table = &priv->mr_table; | ||
467 | int err; | 697 | int err; |
468 | 698 | ||
699 | if (!is_power_of_2(dev->caps.num_mpts)) | ||
700 | return -EINVAL; | ||
701 | |||
702 | /* Nothing to do for slaves - all MR handling is forwarded | ||
703 | * to the master */ | ||
704 | if (mlx4_is_slave(dev)) | ||
705 | return 0; | ||
706 | |||
469 | err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts, | 707 | err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts, |
470 | ~0, dev->caps.reserved_mrws, 0); | 708 | ~0, dev->caps.reserved_mrws, 0); |
471 | if (err) | 709 | if (err) |
@@ -477,7 +715,10 @@ int mlx4_init_mr_table(struct mlx4_dev *dev) | |||
477 | goto err_buddy; | 715 | goto err_buddy; |
478 | 716 | ||
479 | if (dev->caps.reserved_mtts) { | 717 | if (dev->caps.reserved_mtts) { |
480 | if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) { | 718 | priv->reserved_mtts = |
719 | mlx4_alloc_mtt_range(dev, | ||
720 | fls(dev->caps.reserved_mtts - 1)); | ||
721 | if (priv->reserved_mtts < 0) { | ||
481 | mlx4_warn(dev, "MTT table of order %d is too small.\n", | 722 | mlx4_warn(dev, "MTT table of order %d is too small.\n", |
482 | mr_table->mtt_buddy.max_order); | 723 | mr_table->mtt_buddy.max_order); |
483 | err = -ENOMEM; | 724 | err = -ENOMEM; |
@@ -498,8 +739,14 @@ err_buddy: | |||
498 | 739 | ||
499 | void mlx4_cleanup_mr_table(struct mlx4_dev *dev) | 740 | void mlx4_cleanup_mr_table(struct mlx4_dev *dev) |
500 | { | 741 | { |
501 | struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; | 742 | struct mlx4_priv *priv = mlx4_priv(dev); |
743 | struct mlx4_mr_table *mr_table = &priv->mr_table; | ||
502 | 744 | ||
745 | if (mlx4_is_slave(dev)) | ||
746 | return; | ||
747 | if (priv->reserved_mtts >= 0) | ||
748 | mlx4_free_mtt_range(dev, priv->reserved_mtts, | ||
749 | fls(dev->caps.reserved_mtts - 1)); | ||
503 | mlx4_buddy_cleanup(&mr_table->mtt_buddy); | 750 | mlx4_buddy_cleanup(&mr_table->mtt_buddy); |
504 | mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); | 751 | mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); |
505 | } | 752 | } |
@@ -620,6 +867,46 @@ err_free: | |||
620 | } | 867 | } |
621 | EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); | 868 | EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); |
622 | 869 | ||
870 | static int mlx4_fmr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, | ||
871 | u32 pd, u32 access, int max_pages, | ||
872 | int max_maps, u8 page_shift, struct mlx4_fmr *fmr) | ||
873 | { | ||
874 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
875 | int err = -ENOMEM; | ||
876 | |||
877 | if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32) | ||
878 | return -EINVAL; | ||
879 | |||
880 | /* All MTTs must fit in the same page */ | ||
881 | if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) | ||
882 | return -EINVAL; | ||
883 | |||
884 | fmr->page_shift = page_shift; | ||
885 | fmr->max_pages = max_pages; | ||
886 | fmr->max_maps = max_maps; | ||
887 | fmr->maps = 0; | ||
888 | |||
889 | err = mlx4_mr_alloc_reserved(dev, mridx, pd, 0, 0, access, max_pages, | ||
890 | page_shift, &fmr->mr); | ||
891 | if (err) | ||
892 | return err; | ||
893 | |||
894 | fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, | ||
895 | fmr->mr.mtt.first_seg, | ||
896 | &fmr->dma_handle); | ||
897 | if (!fmr->mtts) { | ||
898 | err = -ENOMEM; | ||
899 | goto err_free; | ||
900 | } | ||
901 | |||
902 | return 0; | ||
903 | |||
904 | err_free: | ||
905 | mlx4_mr_free_reserved(dev, &fmr->mr); | ||
906 | return err; | ||
907 | } | ||
908 | EXPORT_SYMBOL_GPL(mlx4_fmr_alloc_reserved); | ||
909 | |||
623 | int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) | 910 | int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) |
624 | { | 911 | { |
625 | struct mlx4_priv *priv = mlx4_priv(dev); | 912 | struct mlx4_priv *priv = mlx4_priv(dev); |
@@ -641,12 +928,32 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_enable); | |||
641 | void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, | 928 | void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, |
642 | u32 *lkey, u32 *rkey) | 929 | u32 *lkey, u32 *rkey) |
643 | { | 930 | { |
931 | struct mlx4_cmd_mailbox *mailbox; | ||
932 | int err; | ||
933 | |||
644 | if (!fmr->maps) | 934 | if (!fmr->maps) |
645 | return; | 935 | return; |
646 | 936 | ||
647 | fmr->maps = 0; | 937 | fmr->maps = 0; |
648 | 938 | ||
649 | *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; | 939 | mailbox = mlx4_alloc_cmd_mailbox(dev); |
940 | if (IS_ERR(mailbox)) { | ||
941 | err = PTR_ERR(mailbox); | ||
942 | printk(KERN_WARNING "mlx4_ib: mlx4_alloc_cmd_mailbox" | ||
943 | " failed (%d)\n", err); | ||
944 | return; | ||
945 | } | ||
946 | |||
947 | err = mlx4_HW2SW_MPT(dev, NULL, | ||
948 | key_to_hw_index(fmr->mr.key) & | ||
949 | (dev->caps.num_mpts - 1)); | ||
950 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
951 | if (err) { | ||
952 | printk(KERN_WARNING "mlx4_ib: mlx4_HW2SW_MPT failed (%d)\n", | ||
953 | err); | ||
954 | return; | ||
955 | } | ||
956 | fmr->mr.enabled = MLX4_MR_EN_SW; | ||
650 | } | 957 | } |
651 | EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); | 958 | EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); |
652 | 959 | ||
@@ -655,13 +962,25 @@ int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) | |||
655 | if (fmr->maps) | 962 | if (fmr->maps) |
656 | return -EBUSY; | 963 | return -EBUSY; |
657 | 964 | ||
658 | fmr->mr.enabled = 0; | ||
659 | mlx4_mr_free(dev, &fmr->mr); | 965 | mlx4_mr_free(dev, &fmr->mr); |
966 | fmr->mr.enabled = MLX4_MR_DISABLED; | ||
660 | 967 | ||
661 | return 0; | 968 | return 0; |
662 | } | 969 | } |
663 | EXPORT_SYMBOL_GPL(mlx4_fmr_free); | 970 | EXPORT_SYMBOL_GPL(mlx4_fmr_free); |
664 | 971 | ||
972 | static int mlx4_fmr_free_reserved(struct mlx4_dev *dev, struct mlx4_fmr *fmr) | ||
973 | { | ||
974 | if (fmr->maps) | ||
975 | return -EBUSY; | ||
976 | |||
977 | mlx4_mr_free_reserved(dev, &fmr->mr); | ||
978 | fmr->mr.enabled = MLX4_MR_DISABLED; | ||
979 | |||
980 | return 0; | ||
981 | } | ||
982 | EXPORT_SYMBOL_GPL(mlx4_fmr_free_reserved); | ||
983 | |||
665 | int mlx4_SYNC_TPT(struct mlx4_dev *dev) | 984 | int mlx4_SYNC_TPT(struct mlx4_dev *dev) |
666 | { | 985 | { |
667 | return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000, | 986 | return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000, |