1 /* 2 * Copyright (c) 2004 Topspin Communications. 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 * $Id: mthca_mr.c 1349 2004-12-16 21:09:43Z roland $ 34 */ 35 36 #include <linux/slab.h> 37 #include <linux/errno.h> 38 39 #include "mthca_dev.h" 40 #include "mthca_cmd.h" 41 #include "mthca_memfree.h" 42 43 struct mthca_mtt { 44 struct mthca_buddy *buddy; 45 int order; 46 u32 first_seg; 47 }; 48 49 /* 50 * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. 51 */ 52 struct mthca_mpt_entry { 53 __be32 flags; 54 __be32 page_size; 55 __be32 key; 56 __be32 pd; 57 __be64 start; 58 __be64 length; 59 __be32 lkey; 60 __be32 window_count; 61 __be32 window_count_limit; 62 __be64 mtt_seg; 63 __be32 mtt_sz; /* Arbel only */ 64 u32 reserved[2]; 65 } __attribute__((packed)); 66 67 #define MTHCA_MPT_FLAG_SW_OWNS (0xfUL << 28) 68 #define MTHCA_MPT_FLAG_MIO (1 << 17) 69 #define MTHCA_MPT_FLAG_BIND_ENABLE (1 << 15) 70 #define MTHCA_MPT_FLAG_PHYSICAL (1 << 9) 71 #define MTHCA_MPT_FLAG_REGION (1 << 8) 72 73 #define MTHCA_MTT_FLAG_PRESENT 1 74 75 #define MTHCA_MPT_STATUS_SW 0xF0 76 #define MTHCA_MPT_STATUS_HW 0x00 77 78 #define SINAI_FMR_KEY_INC 0x1000000 79 80 /* 81 * Buddy allocator for MTT segments (currently not very efficient 82 * since it doesn't keep a free list and just searches linearly 83 * through the bitmaps) 84 */ 85 86 static u32 mthca_buddy_alloc(struct mthca_buddy *buddy, int order) 87 { 88 int o; 89 int m; 90 u32 seg; 91 92 spin_lock(&buddy->lock); 93 94 for (o = order; o <= buddy->max_order; ++o) { 95 m = 1 << (buddy->max_order - o); 96 seg = find_first_bit(buddy->bits[o], m); 97 if (seg < m) 98 goto found; 99 } 100 101 spin_unlock(&buddy->lock); 102 return -1; 103 104 found: 105 clear_bit(seg, buddy->bits[o]); 106 107 while (o > order) { 108 --o; 109 seg <<= 1; 110 set_bit(seg ^ 1, buddy->bits[o]); 111 } 112 113 spin_unlock(&buddy->lock); 114 115 seg <<= order; 116 117 return seg; 118 } 119 120 static void mthca_buddy_free(struct mthca_buddy *buddy, u32 seg, int order) 121 { 122 seg >>= order; 123 124 spin_lock(&buddy->lock); 125 126 while (test_bit(seg ^ 1, buddy->bits[order])) { 127 clear_bit(seg ^ 1, buddy->bits[order]); 128 seg >>= 1; 129 ++order; 130 } 131 132 set_bit(seg, buddy->bits[order]); 133 134 spin_unlock(&buddy->lock); 135 } 136 137 static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order) 138 { 139 int i, s; 140 141 buddy->max_order = max_order; 142 spin_lock_init(&buddy->lock); 143 144 buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *), 145 GFP_KERNEL); 146 if (!buddy->bits) 147 goto err_out; 148 149 for (i = 0; i <= buddy->max_order; ++i) { 150 s = BITS_TO_LONGS(1 << (buddy->max_order - i)); 151 buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); 152 if (!buddy->bits[i]) 153 goto err_out_free; 154 bitmap_zero(buddy->bits[i], 155 1 << (buddy->max_order - i)); 156 } 157 158 set_bit(0, buddy->bits[buddy->max_order]); 159 160 return 0; 161 162 err_out_free: 163 for (i = 0; i <= buddy->max_order; ++i) 164 kfree(buddy->bits[i]); 165 166 kfree(buddy->bits); 167 168 err_out: 169 return -ENOMEM; 170 } 171 172 static void mthca_buddy_cleanup(struct mthca_buddy *buddy) 173 { 174 int i; 175 176 for (i = 0; i <= buddy->max_order; ++i) 177 kfree(buddy->bits[i]); 178 179 kfree(buddy->bits); 180 } 181 182 static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order, 183 struct mthca_buddy *buddy) 184 { 185 u32 seg = mthca_buddy_alloc(buddy, order); 186 187 if (seg == -1) 188 return -1; 189 190 if (mthca_is_memfree(dev)) 191 if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg, 192 seg + (1 << order) - 1)) { 193 mthca_buddy_free(buddy, seg, order); 194 seg = -1; 195 } 196 197 return seg; 198 } 199 200 static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size, 201 struct mthca_buddy *buddy) 202 { 203 struct mthca_mtt *mtt; 204 int i; 205 206 if (size <= 0) 207 return ERR_PTR(-EINVAL); 208 209 mtt = kmalloc(sizeof *mtt, GFP_KERNEL); 210 if (!mtt) 211 return ERR_PTR(-ENOMEM); 212 213 mtt->buddy = buddy; 214 mtt->order = 0; 215 for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1) 216 ++mtt->order; 217 218 mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy); 219 if (mtt->first_seg == -1) { 220 kfree(mtt); 221 return ERR_PTR(-ENOMEM); 222 } 223 224 return mtt; 225 } 226 227 struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size) 228 { 229 return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy); 230 } 231 232 void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt) 233 { 234 if (!mtt) 235 return; 236 237 mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order); 238 239 mthca_table_put_range(dev, dev->mr_table.mtt_table, 240 mtt->first_seg, 241 mtt->first_seg + (1 << mtt->order) - 1); 242 243 kfree(mtt); 244 } 245 246 static int __mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, 247 int start_index, u64 *buffer_list, int list_len) 248 { 249 struct mthca_mailbox *mailbox; 250 __be64 *mtt_entry; 251 int err = 0; 252 u8 status; 253 int i; 254 255 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 256 if (IS_ERR(mailbox)) 257 return PTR_ERR(mailbox); 258 mtt_entry = mailbox->buf; 259 260 while (list_len > 0) { 261 mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base + 262 mtt->first_seg * MTHCA_MTT_SEG_SIZE + 263 start_index * 8); 264 mtt_entry[1] = 0; 265 for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i) 266 mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] | 267 MTHCA_MTT_FLAG_PRESENT); 268 269 /* 270 * If we have an odd number of entries to write, add 271 * one more dummy entry for firmware efficiency. 272 */ 273 if (i & 1) 274 mtt_entry[i + 2] = 0; 275 276 err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status); 277 if (err) { 278 mthca_warn(dev, "WRITE_MTT failed (%d)\n", err); 279 goto out; 280 } 281 if (status) { 282 mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n", 283 status); 284 err = -EINVAL; 285 goto out; 286 } 287 288 list_len -= i; 289 start_index += i; 290 buffer_list += i; 291 } 292 293 out: 294 mthca_free_mailbox(dev, mailbox); 295 return err; 296 } 297 298 int mthca_write_mtt_size(struct mthca_dev *dev) 299 { 300 if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy) 301 /* 302 * Be friendly to WRITE_MTT command 303 * and leave two empty slots for the 304 * index and reserved fields of the 305 * mailbox. 306 */ 307 return PAGE_SIZE / sizeof (u64) - 2; 308 309 /* For Arbel, all MTTs must fit in the same page. */ 310 return mthca_is_memfree(dev) ? (PAGE_SIZE / sizeof (u64)) : 0x7ffffff; 311 } 312 313 static void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, 314 struct mthca_mtt *mtt, int start_index, 315 u64 *buffer_list, int list_len) 316 { 317 u64 __iomem *mtts; 318 int i; 319 320 mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * MTHCA_MTT_SEG_SIZE + 321 start_index * sizeof (u64); 322 for (i = 0; i < list_len; ++i) 323 mthca_write64_raw(cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT), 324 mtts + i); 325 } 326 327 static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, 328 struct mthca_mtt *mtt, int start_index, 329 u64 *buffer_list, int list_len) 330 { 331 __be64 *mtts; 332 dma_addr_t dma_handle; 333 int i; 334 int s = start_index * sizeof (u64); 335 336 /* For Arbel, all MTTs must fit in the same page. */ 337 BUG_ON(s / PAGE_SIZE != (s + list_len * sizeof(u64) - 1) / PAGE_SIZE); 338 /* Require full segments */ 339 BUG_ON(s % MTHCA_MTT_SEG_SIZE); 340 341 mtts = mthca_table_find(dev->mr_table.mtt_table, mtt->first_seg + 342 s / MTHCA_MTT_SEG_SIZE, &dma_handle); 343 344 BUG_ON(!mtts); 345 346 for (i = 0; i < list_len; ++i) 347 mtts[i] = cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT); 348 349 dma_sync_single(&dev->pdev->dev, dma_handle, list_len * sizeof (u64), DMA_TO_DEVICE); 350 } 351 352 int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, 353 int start_index, u64 *buffer_list, int list_len) 354 { 355 int size = mthca_write_mtt_size(dev); 356 int chunk; 357 358 if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy) 359 return __mthca_write_mtt(dev, mtt, start_index, buffer_list, list_len); 360 361 while (list_len > 0) { 362 chunk = min(size, list_len); 363 if (mthca_is_memfree(dev)) 364 mthca_arbel_write_mtt_seg(dev, mtt, start_index, 365 buffer_list, chunk); 366 else 367 mthca_tavor_write_mtt_seg(dev, mtt, start_index, 368 buffer_list, chunk); 369 370 list_len -= chunk; 371 start_index += chunk; 372 buffer_list += chunk; 373 } 374 375 return 0; 376 } 377 378 static inline u32 tavor_hw_index_to_key(u32 ind) 379 { 380 return ind; 381 } 382 383 static inline u32 tavor_key_to_hw_index(u32 key) 384 { 385 return key; 386 } 387 388 static inline u32 arbel_hw_index_to_key(u32 ind) 389 { 390 return (ind >> 24) | (ind << 8); 391 } 392 393 static inline u32 arbel_key_to_hw_index(u32 key) 394 { 395 return (key << 24) | (key >> 8); 396 } 397 398 static inline u32 hw_index_to_key(struct mthca_dev *dev, u32 ind) 399 { 400 if (mthca_is_memfree(dev)) 401 return arbel_hw_index_to_key(ind); 402 else 403 return tavor_hw_index_to_key(ind); 404 } 405 406 static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key) 407 { 408 if (mthca_is_memfree(dev)) 409 return arbel_key_to_hw_index(key); 410 else 411 return tavor_key_to_hw_index(key); 412 } 413 414 static inline u32 adjust_key(struct mthca_dev *dev, u32 key) 415 { 416 if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 417 return ((key << 20) & 0x800000) | (key & 0x7fffff); 418 else 419 return key; 420 } 421 422 int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, 423 u64 iova, u64 total_size, u32 access, struct mthca_mr *mr) 424 { 425 struct mthca_mailbox *mailbox; 426 struct mthca_mpt_entry *mpt_entry; 427 u32 key; 428 int i; 429 int err; 430 u8 status; 431 432 WARN_ON(buffer_size_shift >= 32); 433 434 key = mthca_alloc(&dev->mr_table.mpt_alloc); 435 if (key == -1) 436 return -ENOMEM; 437 key = adjust_key(dev, key); 438 mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key); 439 440 if (mthca_is_memfree(dev)) { 441 err = mthca_table_get(dev, dev->mr_table.mpt_table, key); 442 if (err) 443 goto err_out_mpt_free; 444 } 445 446 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 447 if (IS_ERR(mailbox)) { 448 err = PTR_ERR(mailbox); 449 goto err_out_table; 450 } 451 mpt_entry = mailbox->buf; 452 453 mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS | 454 MTHCA_MPT_FLAG_MIO | 455 MTHCA_MPT_FLAG_REGION | 456 access); 457 if (!mr->mtt) 458 mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL); 459 460 mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12); 461 mpt_entry->key = cpu_to_be32(key); 462 mpt_entry->pd = cpu_to_be32(pd); 463 mpt_entry->start = cpu_to_be64(iova); 464 mpt_entry->length = cpu_to_be64(total_size); 465 466 memset(&mpt_entry->lkey, 0, 467 sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey)); 468 469 if (mr->mtt) 470 mpt_entry->mtt_seg = 471 cpu_to_be64(dev->mr_table.mtt_base + 472 mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE); 473 474 if (0) { 475 mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey); 476 for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) { 477 if (i % 4 == 0) 478 printk("[%02x] ", i * 4); 479 printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i])); 480 if ((i + 1) % 4 == 0) 481 printk("\n"); 482 } 483 } 484 485 err = mthca_SW2HW_MPT(dev, mailbox, 486 key & (dev->limits.num_mpts - 1), 487 &status); 488 if (err) { 489 mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err); 490 goto err_out_mailbox; 491 } else if (status) { 492 mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n", 493 status); 494 err = -EINVAL; 495 goto err_out_mailbox; 496 } 497 498 mthca_free_mailbox(dev, mailbox); 499 return err; 500 501 err_out_mailbox: 502 mthca_free_mailbox(dev, mailbox); 503 504 err_out_table: 505 mthca_table_put(dev, dev->mr_table.mpt_table, key); 506 507 err_out_mpt_free: 508 mthca_free(&dev->mr_table.mpt_alloc, key); 509 return err; 510 } 511 512 int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd, 513 u32 access, struct mthca_mr *mr) 514 { 515 mr->mtt = NULL; 516 return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr); 517 } 518 519 int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, 520 u64 *buffer_list, int buffer_size_shift, 521 int list_len, u64 iova, u64 total_size, 522 u32 access, struct mthca_mr *mr) 523 { 524 int err; 525 526 mr->mtt = mthca_alloc_mtt(dev, list_len); 527 if (IS_ERR(mr->mtt)) 528 return PTR_ERR(mr->mtt); 529 530 err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len); 531 if (err) { 532 mthca_free_mtt(dev, mr->mtt); 533 return err; 534 } 535 536 err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova, 537 total_size, access, mr); 538 if (err) 539 mthca_free_mtt(dev, mr->mtt); 540 541 return err; 542 } 543 544 /* Free mr or fmr */ 545 static void mthca_free_region(struct mthca_dev *dev, u32 lkey) 546 { 547 mthca_table_put(dev, dev->mr_table.mpt_table, 548 key_to_hw_index(dev, lkey)); 549 550 mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey)); 551 } 552 553 void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr) 554 { 555 int err; 556 u8 status; 557 558 err = mthca_HW2SW_MPT(dev, NULL, 559 key_to_hw_index(dev, mr->ibmr.lkey) & 560 (dev->limits.num_mpts - 1), 561 &status); 562 if (err) 563 mthca_warn(dev, "HW2SW_MPT failed (%d)\n", err); 564 else if (status) 565 mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n", 566 status); 567 568 mthca_free_region(dev, mr->ibmr.lkey); 569 mthca_free_mtt(dev, mr->mtt); 570 } 571 572 int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd, 573 u32 access, struct mthca_fmr *mr) 574 { 575 struct mthca_mpt_entry *mpt_entry; 576 struct mthca_mailbox *mailbox; 577 u64 mtt_seg; 578 u32 key, idx; 579 u8 status; 580 int list_len = mr->attr.max_pages; 581 int err = -ENOMEM; 582 int i; 583 584 if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32) 585 return -EINVAL; 586 587 /* For Arbel, all MTTs must fit in the same page. */ 588 if (mthca_is_memfree(dev) && 589 mr->attr.max_pages * sizeof *mr->mem.arbel.mtts > PAGE_SIZE) 590 return -EINVAL; 591 592 mr->maps = 0; 593 594 key = mthca_alloc(&dev->mr_table.mpt_alloc); 595 if (key == -1) 596 return -ENOMEM; 597 key = adjust_key(dev, key); 598 599 idx = key & (dev->limits.num_mpts - 1); 600 mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key); 601 602 if (mthca_is_memfree(dev)) { 603 err = mthca_table_get(dev, dev->mr_table.mpt_table, key); 604 if (err) 605 goto err_out_mpt_free; 606 607 mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key, NULL); 608 BUG_ON(!mr->mem.arbel.mpt); 609 } else 610 mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base + 611 sizeof *(mr->mem.tavor.mpt) * idx; 612 613 mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy); 614 if (IS_ERR(mr->mtt)) 615 goto err_out_table; 616 617 mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE; 618 619 if (mthca_is_memfree(dev)) { 620 mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table, 621 mr->mtt->first_seg, 622 &mr->mem.arbel.dma_handle); 623 BUG_ON(!mr->mem.arbel.mtts); 624 } else 625 mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg; 626 627 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 628 if (IS_ERR(mailbox)) 629 goto err_out_free_mtt; 630 631 mpt_entry = mailbox->buf; 632 633 mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS | 634 MTHCA_MPT_FLAG_MIO | 635 MTHCA_MPT_FLAG_REGION | 636 access); 637 638 mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12); 639 mpt_entry->key = cpu_to_be32(key); 640 mpt_entry->pd = cpu_to_be32(pd); 641 memset(&mpt_entry->start, 0, 642 sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, start)); 643 mpt_entry->mtt_seg = cpu_to_be64(dev->mr_table.mtt_base + mtt_seg); 644 645 if (0) { 646 mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey); 647 for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) { 648 if (i % 4 == 0) 649 printk("[%02x] ", i * 4); 650 printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i])); 651 if ((i + 1) % 4 == 0) 652 printk("\n"); 653 } 654 } 655 656 err = mthca_SW2HW_MPT(dev, mailbox, 657 key & (dev->limits.num_mpts - 1), 658 &status); 659 if (err) { 660 mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err); 661 goto err_out_mailbox_free; 662 } 663 if (status) { 664 mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n", 665 status); 666 err = -EINVAL; 667 goto err_out_mailbox_free; 668 } 669 670 mthca_free_mailbox(dev, mailbox); 671 return 0; 672 673 err_out_mailbox_free: 674 mthca_free_mailbox(dev, mailbox); 675 676 err_out_free_mtt: 677 mthca_free_mtt(dev, mr->mtt); 678 679 err_out_table: 680 mthca_table_put(dev, dev->mr_table.mpt_table, key); 681 682 err_out_mpt_free: 683 mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey); 684 return err; 685 } 686 687 int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr) 688 { 689 if (fmr->maps) 690 return -EBUSY; 691 692 mthca_free_region(dev, fmr->ibmr.lkey); 693 mthca_free_mtt(dev, fmr->mtt); 694 695 return 0; 696 } 697 698 static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list, 699 int list_len, u64 iova) 700 { 701 int i, page_mask; 702 703 if (list_len > fmr->attr.max_pages) 704 return -EINVAL; 705 706 page_mask = (1 << fmr->attr.page_shift) - 1; 707 708 /* We are getting page lists, so va must be page aligned. */ 709 if (iova & page_mask) 710 return -EINVAL; 711 712 /* Trust the user not to pass misaligned data in page_list */ 713 if (0) 714 for (i = 0; i < list_len; ++i) { 715 if (page_list[i] & ~page_mask) 716 return -EINVAL; 717 } 718 719 if (fmr->maps >= fmr->attr.max_maps) 720 return -EINVAL; 721 722 return 0; 723 } 724 725 726 int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, 727 int list_len, u64 iova) 728 { 729 struct mthca_fmr *fmr = to_mfmr(ibfmr); 730 struct mthca_dev *dev = to_mdev(ibfmr->device); 731 struct mthca_mpt_entry mpt_entry; 732 u32 key; 733 int i, err; 734 735 err = mthca_check_fmr(fmr, page_list, list_len, iova); 736 if (err) 737 return err; 738 739 ++fmr->maps; 740 741 key = tavor_key_to_hw_index(fmr->ibmr.lkey); 742 key += dev->limits.num_mpts; 743 fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); 744 745 writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); 746 747 for (i = 0; i < list_len; ++i) { 748 __be64 mtt_entry = cpu_to_be64(page_list[i] | 749 MTHCA_MTT_FLAG_PRESENT); 750 mthca_write64_raw(mtt_entry, fmr->mem.tavor.mtts + i); 751 } 752 753 mpt_entry.lkey = cpu_to_be32(key); 754 mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift)); 755 mpt_entry.start = cpu_to_be64(iova); 756 757 __raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key); 758 memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start, 759 offsetof(struct mthca_mpt_entry, window_count) - 760 offsetof(struct mthca_mpt_entry, start)); 761 762 writeb(MTHCA_MPT_STATUS_HW, fmr->mem.tavor.mpt); 763 764 return 0; 765 } 766 767 int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, 768 int list_len, u64 iova) 769 { 770 struct mthca_fmr *fmr = to_mfmr(ibfmr); 771 struct mthca_dev *dev = to_mdev(ibfmr->device); 772 u32 key; 773 int i, err; 774 775 err = mthca_check_fmr(fmr, page_list, list_len, iova); 776 if (err) 777 return err; 778 779 ++fmr->maps; 780 781 key = arbel_key_to_hw_index(fmr->ibmr.lkey); 782 if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 783 key += SINAI_FMR_KEY_INC; 784 else 785 key += dev->limits.num_mpts; 786 fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); 787 788 *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; 789 790 wmb(); 791 792 for (i = 0; i < list_len; ++i) 793 fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] | 794 MTHCA_MTT_FLAG_PRESENT); 795 796 dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle, 797 list_len * sizeof(u64), DMA_TO_DEVICE); 798 799 fmr->mem.arbel.mpt->key = cpu_to_be32(key); 800 fmr->mem.arbel.mpt->lkey = cpu_to_be32(key); 801 fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift)); 802 fmr->mem.arbel.mpt->start = cpu_to_be64(iova); 803 804 wmb(); 805 806 *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_HW; 807 808 wmb(); 809 810 return 0; 811 } 812 813 void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) 814 { 815 u32 key; 816 817 if (!fmr->maps) 818 return; 819 820 key = tavor_key_to_hw_index(fmr->ibmr.lkey); 821 key &= dev->limits.num_mpts - 1; 822 fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); 823 824 fmr->maps = 0; 825 826 writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); 827 } 828 829 void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) 830 { 831 u32 key; 832 833 if (!fmr->maps) 834 return; 835 836 key = arbel_key_to_hw_index(fmr->ibmr.lkey); 837 key &= dev->limits.num_mpts - 1; 838 key = adjust_key(dev, key); 839 fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); 840 841 fmr->maps = 0; 842 843 *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; 844 } 845 846 int mthca_init_mr_table(struct mthca_dev *dev) 847 { 848 unsigned long addr; 849 int mpts, mtts, err, i; 850 851 err = mthca_alloc_init(&dev->mr_table.mpt_alloc, 852 dev->limits.num_mpts, 853 ~0, dev->limits.reserved_mrws); 854 if (err) 855 return err; 856 857 if (!mthca_is_memfree(dev) && 858 (dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) 859 dev->limits.fmr_reserved_mtts = 0; 860 else 861 dev->mthca_flags |= MTHCA_FLAG_FMR; 862 863 if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 864 mthca_dbg(dev, "Memory key throughput optimization activated.\n"); 865 866 err = mthca_buddy_init(&dev->mr_table.mtt_buddy, 867 fls(dev->limits.num_mtt_segs - 1)); 868 869 if (err) 870 goto err_mtt_buddy; 871 872 dev->mr_table.tavor_fmr.mpt_base = NULL; 873 dev->mr_table.tavor_fmr.mtt_base = NULL; 874 875 if (dev->limits.fmr_reserved_mtts) { 876 i = fls(dev->limits.fmr_reserved_mtts - 1); 877 878 if (i >= 31) { 879 mthca_warn(dev, "Unable to reserve 2^31 FMR MTTs.\n"); 880 err = -EINVAL; 881 goto err_fmr_mpt; 882 } 883 mpts = mtts = 1 << i; 884 } else { 885 mtts = dev->limits.num_mtt_segs; 886 mpts = dev->limits.num_mpts; 887 } 888 889 if (!mthca_is_memfree(dev) && 890 (dev->mthca_flags & MTHCA_FLAG_FMR)) { 891 892 addr = pci_resource_start(dev->pdev, 4) + 893 ((pci_resource_len(dev->pdev, 4) - 1) & 894 dev->mr_table.mpt_base); 895 896 dev->mr_table.tavor_fmr.mpt_base = 897 ioremap(addr, mpts * sizeof(struct mthca_mpt_entry)); 898 899 if (!dev->mr_table.tavor_fmr.mpt_base) { 900 mthca_warn(dev, "MPT ioremap for FMR failed.\n"); 901 err = -ENOMEM; 902 goto err_fmr_mpt; 903 } 904 905 addr = pci_resource_start(dev->pdev, 4) + 906 ((pci_resource_len(dev->pdev, 4) - 1) & 907 dev->mr_table.mtt_base); 908 909 dev->mr_table.tavor_fmr.mtt_base = 910 ioremap(addr, mtts * MTHCA_MTT_SEG_SIZE); 911 if (!dev->mr_table.tavor_fmr.mtt_base) { 912 mthca_warn(dev, "MTT ioremap for FMR failed.\n"); 913 err = -ENOMEM; 914 goto err_fmr_mtt; 915 } 916 } 917 918 if (dev->limits.fmr_reserved_mtts) { 919 err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, fls(mtts - 1)); 920 if (err) 921 goto err_fmr_mtt_buddy; 922 923 /* Prevent regular MRs from using FMR keys */ 924 err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, fls(mtts - 1)); 925 if (err) 926 goto err_reserve_fmr; 927 928 dev->mr_table.fmr_mtt_buddy = 929 &dev->mr_table.tavor_fmr.mtt_buddy; 930 } else 931 dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy; 932 933 /* FMR table is always the first, take reserved MTTs out of there */ 934 if (dev->limits.reserved_mtts) { 935 i = fls(dev->limits.reserved_mtts - 1); 936 937 if (mthca_alloc_mtt_range(dev, i, 938 dev->mr_table.fmr_mtt_buddy) == -1) { 939 mthca_warn(dev, "MTT table of order %d is too small.\n", 940 dev->mr_table.fmr_mtt_buddy->max_order); 941 err = -ENOMEM; 942 goto err_reserve_mtts; 943 } 944 } 945 946 return 0; 947 948 err_reserve_mtts: 949 err_reserve_fmr: 950 if (dev->limits.fmr_reserved_mtts) 951 mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); 952 953 err_fmr_mtt_buddy: 954 if (dev->mr_table.tavor_fmr.mtt_base) 955 iounmap(dev->mr_table.tavor_fmr.mtt_base); 956 957 err_fmr_mtt: 958 if (dev->mr_table.tavor_fmr.mpt_base) 959 iounmap(dev->mr_table.tavor_fmr.mpt_base); 960 961 err_fmr_mpt: 962 mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); 963 964 err_mtt_buddy: 965 mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); 966 967 return err; 968 } 969 970 void mthca_cleanup_mr_table(struct mthca_dev *dev) 971 { 972 /* XXX check if any MRs are still allocated? */ 973 if (dev->limits.fmr_reserved_mtts) 974 mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); 975 976 mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); 977 978 if (dev->mr_table.tavor_fmr.mtt_base) 979 iounmap(dev->mr_table.tavor_fmr.mtt_base); 980 if (dev->mr_table.tavor_fmr.mpt_base) 981 iounmap(dev->mr_table.tavor_fmr.mpt_base); 982 983 mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); 984 } 985