Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.32 666 lines 16 kB view raw
1/* 2 * Copyright (c) 2004 Topspin Communications. All rights reserved. 3 * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 */ 34 35#include <linux/errno.h> 36 37#include <linux/mlx4/cmd.h> 38 39#include "mlx4.h" 40#include "icm.h" 41 42/* 43 * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. 44 */ 45struct mlx4_mpt_entry { 46 __be32 flags; 47 __be32 qpn; 48 __be32 key; 49 __be32 pd_flags; 50 __be64 start; 51 __be64 length; 52 __be32 lkey; 53 __be32 win_cnt; 54 u8 reserved1[3]; 55 u8 mtt_rep; 56 __be64 mtt_seg; 57 __be32 mtt_sz; 58 __be32 entity_size; 59 __be32 first_byte_offset; 60} __attribute__((packed)); 61 62#define MLX4_MPT_FLAG_SW_OWNS (0xfUL << 28) 63#define MLX4_MPT_FLAG_FREE (0x3UL << 28) 64#define MLX4_MPT_FLAG_MIO (1 << 17) 65#define MLX4_MPT_FLAG_BIND_ENABLE (1 << 15) 66#define MLX4_MPT_FLAG_PHYSICAL (1 << 9) 67#define MLX4_MPT_FLAG_REGION (1 << 8) 68 69#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 27) 70#define MLX4_MPT_PD_FLAG_RAE (1 << 28) 71#define MLX4_MPT_PD_FLAG_EN_INV (3 << 24) 72 73#define MLX4_MPT_STATUS_SW 0xF0 74#define MLX4_MPT_STATUS_HW 0x00 75 76static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order) 77{ 78 int o; 79 int m; 80 u32 seg; 81 82 spin_lock(&buddy->lock); 83 84 for (o = order; o <= buddy->max_order; ++o) 85 if (buddy->num_free[o]) { 86 m = 1 << (buddy->max_order - o); 87 seg = find_first_bit(buddy->bits[o], m); 88 if (seg < m) 89 goto found; 90 } 91 92 spin_unlock(&buddy->lock); 93 return -1; 94 95 found: 96 clear_bit(seg, buddy->bits[o]); 97 --buddy->num_free[o]; 98 99 while (o > order) { 100 --o; 101 seg <<= 1; 102 set_bit(seg ^ 1, buddy->bits[o]); 103 ++buddy->num_free[o]; 104 } 105 106 spin_unlock(&buddy->lock); 107 108 seg <<= order; 109 110 return seg; 111} 112 113static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order) 114{ 115 seg >>= order; 116 117 spin_lock(&buddy->lock); 118 119 while (test_bit(seg ^ 1, buddy->bits[order])) { 120 clear_bit(seg ^ 1, buddy->bits[order]); 121 --buddy->num_free[order]; 122 seg >>= 1; 123 ++order; 124 } 125 126 set_bit(seg, buddy->bits[order]); 127 ++buddy->num_free[order]; 128 129 spin_unlock(&buddy->lock); 130} 131 132static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order) 133{ 134 int i, s; 135 136 buddy->max_order = max_order; 137 spin_lock_init(&buddy->lock); 138 139 buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *), 140 GFP_KERNEL); 141 buddy->num_free = kzalloc((buddy->max_order + 1) * sizeof (int *), 142 GFP_KERNEL); 143 if (!buddy->bits || !buddy->num_free) 144 goto err_out; 145 146 for (i = 0; i <= buddy->max_order; ++i) { 147 s = BITS_TO_LONGS(1 << (buddy->max_order - i)); 148 buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); 149 if (!buddy->bits[i]) 150 goto err_out_free; 151 bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i)); 152 } 153 154 set_bit(0, buddy->bits[buddy->max_order]); 155 buddy->num_free[buddy->max_order] = 1; 156 157 return 0; 158 159err_out_free: 160 for (i = 0; i <= buddy->max_order; ++i) 161 kfree(buddy->bits[i]); 162 163err_out: 164 kfree(buddy->bits); 165 kfree(buddy->num_free); 166 167 return -ENOMEM; 168} 169 170static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy) 171{ 172 int i; 173 174 for (i = 0; i <= buddy->max_order; ++i) 175 kfree(buddy->bits[i]); 176 177 kfree(buddy->bits); 178 kfree(buddy->num_free); 179} 180 181static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) 182{ 183 struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; 184 u32 seg; 185 186 seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, order); 187 if (seg == -1) 188 return -1; 189 190 if (mlx4_table_get_range(dev, &mr_table->mtt_table, seg, 191 seg + (1 << order) - 1)) { 192 mlx4_buddy_free(&mr_table->mtt_buddy, seg, order); 193 return -1; 194 } 195 196 return seg; 197} 198 199int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, 200 struct mlx4_mtt *mtt) 201{ 202 int i; 203 204 if (!npages) { 205 mtt->order = -1; 206 mtt->page_shift = MLX4_ICM_PAGE_SHIFT; 207 return 0; 208 } else 209 mtt->page_shift = page_shift; 210 211 for (mtt->order = 0, i = dev->caps.mtts_per_seg; i < npages; i <<= 1) 212 ++mtt->order; 213 214 mtt->first_seg = mlx4_alloc_mtt_range(dev, mtt->order); 215 if (mtt->first_seg == -1) 216 return -ENOMEM; 217 218 return 0; 219} 220EXPORT_SYMBOL_GPL(mlx4_mtt_init); 221 222void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt) 223{ 224 struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; 225 226 if (mtt->order < 0) 227 return; 228 229 mlx4_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order); 230 mlx4_table_put_range(dev, &mr_table->mtt_table, mtt->first_seg, 231 mtt->first_seg + (1 << mtt->order) - 1); 232} 233EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup); 234 235u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt) 236{ 237 return (u64) mtt->first_seg * dev->caps.mtt_entry_sz; 238} 239EXPORT_SYMBOL_GPL(mlx4_mtt_addr); 240 241static u32 hw_index_to_key(u32 ind) 242{ 243 return (ind >> 24) | (ind << 8); 244} 245 246static u32 key_to_hw_index(u32 key) 247{ 248 return (key << 24) | (key >> 8); 249} 250 251static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, 252 int mpt_index) 253{ 254 return mlx4_cmd(dev, mailbox->dma, mpt_index, 0, MLX4_CMD_SW2HW_MPT, 255 MLX4_CMD_TIME_CLASS_B); 256} 257 258static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, 259 int mpt_index) 260{ 261 return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index, 262 !mailbox, MLX4_CMD_HW2SW_MPT, MLX4_CMD_TIME_CLASS_B); 263} 264 265int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, 266 int npages, int page_shift, struct mlx4_mr *mr) 267{ 268 struct mlx4_priv *priv = mlx4_priv(dev); 269 u32 index; 270 int err; 271 272 index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap); 273 if (index == -1) 274 return -ENOMEM; 275 276 mr->iova = iova; 277 mr->size = size; 278 mr->pd = pd; 279 mr->access = access; 280 mr->enabled = 0; 281 mr->key = hw_index_to_key(index); 282 283 err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt); 284 if (err) 285 mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index); 286 287 return err; 288} 289EXPORT_SYMBOL_GPL(mlx4_mr_alloc); 290 291void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr) 292{ 293 struct mlx4_priv *priv = mlx4_priv(dev); 294 int err; 295 296 if (mr->enabled) { 297 err = mlx4_HW2SW_MPT(dev, NULL, 298 key_to_hw_index(mr->key) & 299 (dev->caps.num_mpts - 1)); 300 if (err) 301 mlx4_warn(dev, "HW2SW_MPT failed (%d)\n", err); 302 } 303 304 mlx4_mtt_cleanup(dev, &mr->mtt); 305 mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, key_to_hw_index(mr->key)); 306} 307EXPORT_SYMBOL_GPL(mlx4_mr_free); 308 309int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) 310{ 311 struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; 312 struct mlx4_cmd_mailbox *mailbox; 313 struct mlx4_mpt_entry *mpt_entry; 314 int err; 315 316 err = mlx4_table_get(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); 317 if (err) 318 return err; 319 320 mailbox = mlx4_alloc_cmd_mailbox(dev); 321 if (IS_ERR(mailbox)) { 322 err = PTR_ERR(mailbox); 323 goto err_table; 324 } 325 mpt_entry = mailbox->buf; 326 327 memset(mpt_entry, 0, sizeof *mpt_entry); 328 329 mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_MIO | 330 MLX4_MPT_FLAG_REGION | 331 mr->access); 332 333 mpt_entry->key = cpu_to_be32(key_to_hw_index(mr->key)); 334 mpt_entry->pd_flags = cpu_to_be32(mr->pd | MLX4_MPT_PD_FLAG_EN_INV); 335 mpt_entry->start = cpu_to_be64(mr->iova); 336 mpt_entry->length = cpu_to_be64(mr->size); 337 mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); 338 339 if (mr->mtt.order < 0) { 340 mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL); 341 mpt_entry->mtt_seg = 0; 342 } else { 343 mpt_entry->mtt_seg = cpu_to_be64(mlx4_mtt_addr(dev, &mr->mtt)); 344 } 345 346 if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) { 347 /* fast register MR in free state */ 348 mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); 349 mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG | 350 MLX4_MPT_PD_FLAG_RAE); 351 mpt_entry->mtt_sz = cpu_to_be32((1 << mr->mtt.order) * 352 dev->caps.mtts_per_seg); 353 } else { 354 mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS); 355 } 356 357 err = mlx4_SW2HW_MPT(dev, mailbox, 358 key_to_hw_index(mr->key) & (dev->caps.num_mpts - 1)); 359 if (err) { 360 mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); 361 goto err_cmd; 362 } 363 364 mr->enabled = 1; 365 366 mlx4_free_cmd_mailbox(dev, mailbox); 367 368 return 0; 369 370err_cmd: 371 mlx4_free_cmd_mailbox(dev, mailbox); 372 373err_table: 374 mlx4_table_put(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); 375 return err; 376} 377EXPORT_SYMBOL_GPL(mlx4_mr_enable); 378 379static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 380 int start_index, int npages, u64 *page_list) 381{ 382 struct mlx4_priv *priv = mlx4_priv(dev); 383 __be64 *mtts; 384 dma_addr_t dma_handle; 385 int i; 386 int s = start_index * sizeof (u64); 387 388 /* All MTTs must fit in the same page */ 389 if (start_index / (PAGE_SIZE / sizeof (u64)) != 390 (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64))) 391 return -EINVAL; 392 393 if (start_index & (dev->caps.mtts_per_seg - 1)) 394 return -EINVAL; 395 396 mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg + 397 s / dev->caps.mtt_entry_sz, &dma_handle); 398 if (!mtts) 399 return -ENOMEM; 400 401 dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, 402 npages * sizeof (u64), DMA_TO_DEVICE); 403 404 for (i = 0; i < npages; ++i) 405 mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); 406 407 dma_sync_single_for_device(&dev->pdev->dev, dma_handle, 408 npages * sizeof (u64), DMA_TO_DEVICE); 409 410 return 0; 411} 412 413int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 414 int start_index, int npages, u64 *page_list) 415{ 416 int chunk; 417 int err; 418 419 if (mtt->order < 0) 420 return -EINVAL; 421 422 while (npages > 0) { 423 chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); 424 err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); 425 if (err) 426 return err; 427 428 npages -= chunk; 429 start_index += chunk; 430 page_list += chunk; 431 } 432 433 return 0; 434} 435EXPORT_SYMBOL_GPL(mlx4_write_mtt); 436 437int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 438 struct mlx4_buf *buf) 439{ 440 u64 *page_list; 441 int err; 442 int i; 443 444 page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL); 445 if (!page_list) 446 return -ENOMEM; 447 448 for (i = 0; i < buf->npages; ++i) 449 if (buf->nbufs == 1) 450 page_list[i] = buf->direct.map + (i << buf->page_shift); 451 else 452 page_list[i] = buf->page_list[i].map; 453 454 err = mlx4_write_mtt(dev, mtt, 0, buf->npages, page_list); 455 456 kfree(page_list); 457 return err; 458} 459EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); 460 461int mlx4_init_mr_table(struct mlx4_dev *dev) 462{ 463 struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; 464 int err; 465 466 err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts, 467 ~0, dev->caps.reserved_mrws, 0); 468 if (err) 469 return err; 470 471 err = mlx4_buddy_init(&mr_table->mtt_buddy, 472 ilog2(dev->caps.num_mtt_segs)); 473 if (err) 474 goto err_buddy; 475 476 if (dev->caps.reserved_mtts) { 477 if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) { 478 mlx4_warn(dev, "MTT table of order %d is too small.\n", 479 mr_table->mtt_buddy.max_order); 480 err = -ENOMEM; 481 goto err_reserve_mtts; 482 } 483 } 484 485 return 0; 486 487err_reserve_mtts: 488 mlx4_buddy_cleanup(&mr_table->mtt_buddy); 489 490err_buddy: 491 mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); 492 493 return err; 494} 495 496void mlx4_cleanup_mr_table(struct mlx4_dev *dev) 497{ 498 struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; 499 500 mlx4_buddy_cleanup(&mr_table->mtt_buddy); 501 mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); 502} 503 504static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list, 505 int npages, u64 iova) 506{ 507 int i, page_mask; 508 509 if (npages > fmr->max_pages) 510 return -EINVAL; 511 512 page_mask = (1 << fmr->page_shift) - 1; 513 514 /* We are getting page lists, so va must be page aligned. */ 515 if (iova & page_mask) 516 return -EINVAL; 517 518 /* Trust the user not to pass misaligned data in page_list */ 519 if (0) 520 for (i = 0; i < npages; ++i) { 521 if (page_list[i] & ~page_mask) 522 return -EINVAL; 523 } 524 525 if (fmr->maps >= fmr->max_maps) 526 return -EINVAL; 527 528 return 0; 529} 530 531int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, 532 int npages, u64 iova, u32 *lkey, u32 *rkey) 533{ 534 u32 key; 535 int i, err; 536 537 err = mlx4_check_fmr(fmr, page_list, npages, iova); 538 if (err) 539 return err; 540 541 ++fmr->maps; 542 543 key = key_to_hw_index(fmr->mr.key); 544 key += dev->caps.num_mpts; 545 *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); 546 547 *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; 548 549 /* Make sure MPT status is visible before writing MTT entries */ 550 wmb(); 551 552 dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, 553 npages * sizeof(u64), DMA_TO_DEVICE); 554 555 for (i = 0; i < npages; ++i) 556 fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); 557 558 dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle, 559 npages * sizeof(u64), DMA_TO_DEVICE); 560 561 fmr->mpt->key = cpu_to_be32(key); 562 fmr->mpt->lkey = cpu_to_be32(key); 563 fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift)); 564 fmr->mpt->start = cpu_to_be64(iova); 565 566 /* Make MTT entries are visible before setting MPT status */ 567 wmb(); 568 569 *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW; 570 571 /* Make sure MPT status is visible before consumer can use FMR */ 572 wmb(); 573 574 return 0; 575} 576EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr); 577 578int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, 579 int max_maps, u8 page_shift, struct mlx4_fmr *fmr) 580{ 581 struct mlx4_priv *priv = mlx4_priv(dev); 582 u64 mtt_seg; 583 int err = -ENOMEM; 584 585 if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32) 586 return -EINVAL; 587 588 /* All MTTs must fit in the same page */ 589 if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) 590 return -EINVAL; 591 592 fmr->page_shift = page_shift; 593 fmr->max_pages = max_pages; 594 fmr->max_maps = max_maps; 595 fmr->maps = 0; 596 597 err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages, 598 page_shift, &fmr->mr); 599 if (err) 600 return err; 601 602 mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz; 603 604 fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, 605 fmr->mr.mtt.first_seg, 606 &fmr->dma_handle); 607 if (!fmr->mtts) { 608 err = -ENOMEM; 609 goto err_free; 610 } 611 612 return 0; 613 614err_free: 615 mlx4_mr_free(dev, &fmr->mr); 616 return err; 617} 618EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); 619 620int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) 621{ 622 struct mlx4_priv *priv = mlx4_priv(dev); 623 int err; 624 625 err = mlx4_mr_enable(dev, &fmr->mr); 626 if (err) 627 return err; 628 629 fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, 630 key_to_hw_index(fmr->mr.key), NULL); 631 if (!fmr->mpt) 632 return -ENOMEM; 633 634 return 0; 635} 636EXPORT_SYMBOL_GPL(mlx4_fmr_enable); 637 638void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, 639 u32 *lkey, u32 *rkey) 640{ 641 if (!fmr->maps) 642 return; 643 644 fmr->maps = 0; 645 646 *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; 647} 648EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); 649 650int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) 651{ 652 if (fmr->maps) 653 return -EBUSY; 654 655 fmr->mr.enabled = 0; 656 mlx4_mr_free(dev, &fmr->mr); 657 658 return 0; 659} 660EXPORT_SYMBOL_GPL(mlx4_fmr_free); 661 662int mlx4_SYNC_TPT(struct mlx4_dev *dev) 663{ 664 return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000); 665} 666EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT);