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 void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt, 314 int start_index, u64 *buffer_list, int list_len) 315 { 316 u64 __iomem *mtts; 317 int i; 318 319 mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * MTHCA_MTT_SEG_SIZE + 320 start_index * sizeof (u64); 321 for (i = 0; i < list_len; ++i) 322 mthca_write64_raw(cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT), 323 mtts + i); 324 } 325 326 void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt, 327 int start_index, u64 *buffer_list, int list_len) 328 { 329 __be64 *mtts; 330 dma_addr_t dma_handle; 331 int i; 332 int s = start_index * sizeof (u64); 333 334 /* For Arbel, all MTTs must fit in the same page. */ 335 BUG_ON(s / PAGE_SIZE != (s + list_len * sizeof(u64) - 1) / PAGE_SIZE); 336 /* Require full segments */ 337 BUG_ON(s % MTHCA_MTT_SEG_SIZE); 338 339 mtts = mthca_table_find(dev->mr_table.mtt_table, mtt->first_seg + 340 s / MTHCA_MTT_SEG_SIZE, &dma_handle); 341 342 BUG_ON(!mtts); 343 344 for (i = 0; i < list_len; ++i) 345 mtts[i] = cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT); 346 347 dma_sync_single(&dev->pdev->dev, dma_handle, list_len * sizeof (u64), DMA_TO_DEVICE); 348 } 349 350 int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, 351 int start_index, u64 *buffer_list, int list_len) 352 { 353 int size = mthca_write_mtt_size(dev); 354 int chunk; 355 356 if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy) 357 return __mthca_write_mtt(dev, mtt, start_index, buffer_list, list_len); 358 359 while (list_len > 0) { 360 chunk = min(size, list_len); 361 if (mthca_is_memfree(dev)) 362 mthca_arbel_write_mtt_seg(dev, mtt, start_index, 363 buffer_list, chunk); 364 else 365 mthca_tavor_write_mtt_seg(dev, mtt, start_index, 366 buffer_list, chunk); 367 368 list_len -= chunk; 369 start_index += chunk; 370 buffer_list += chunk; 371 } 372 373 return 0; 374 } 375 376 static inline u32 tavor_hw_index_to_key(u32 ind) 377 { 378 return ind; 379 } 380 381 static inline u32 tavor_key_to_hw_index(u32 key) 382 { 383 return key; 384 } 385 386 static inline u32 arbel_hw_index_to_key(u32 ind) 387 { 388 return (ind >> 24) | (ind << 8); 389 } 390 391 static inline u32 arbel_key_to_hw_index(u32 key) 392 { 393 return (key << 24) | (key >> 8); 394 } 395 396 static inline u32 hw_index_to_key(struct mthca_dev *dev, u32 ind) 397 { 398 if (mthca_is_memfree(dev)) 399 return arbel_hw_index_to_key(ind); 400 else 401 return tavor_hw_index_to_key(ind); 402 } 403 404 static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key) 405 { 406 if (mthca_is_memfree(dev)) 407 return arbel_key_to_hw_index(key); 408 else 409 return tavor_key_to_hw_index(key); 410 } 411 412 static inline u32 adjust_key(struct mthca_dev *dev, u32 key) 413 { 414 if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 415 return ((key << 20) & 0x800000) | (key & 0x7fffff); 416 else 417 return key; 418 } 419 420 int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, 421 u64 iova, u64 total_size, u32 access, struct mthca_mr *mr) 422 { 423 struct mthca_mailbox *mailbox; 424 struct mthca_mpt_entry *mpt_entry; 425 u32 key; 426 int i; 427 int err; 428 u8 status; 429 430 WARN_ON(buffer_size_shift >= 32); 431 432 key = mthca_alloc(&dev->mr_table.mpt_alloc); 433 if (key == -1) 434 return -ENOMEM; 435 key = adjust_key(dev, key); 436 mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key); 437 438 if (mthca_is_memfree(dev)) { 439 err = mthca_table_get(dev, dev->mr_table.mpt_table, key); 440 if (err) 441 goto err_out_mpt_free; 442 } 443 444 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 445 if (IS_ERR(mailbox)) { 446 err = PTR_ERR(mailbox); 447 goto err_out_table; 448 } 449 mpt_entry = mailbox->buf; 450 451 mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS | 452 MTHCA_MPT_FLAG_MIO | 453 MTHCA_MPT_FLAG_REGION | 454 access); 455 if (!mr->mtt) 456 mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL); 457 458 mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12); 459 mpt_entry->key = cpu_to_be32(key); 460 mpt_entry->pd = cpu_to_be32(pd); 461 mpt_entry->start = cpu_to_be64(iova); 462 mpt_entry->length = cpu_to_be64(total_size); 463 464 memset(&mpt_entry->lkey, 0, 465 sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey)); 466 467 if (mr->mtt) 468 mpt_entry->mtt_seg = 469 cpu_to_be64(dev->mr_table.mtt_base + 470 mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE); 471 472 if (0) { 473 mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey); 474 for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) { 475 if (i % 4 == 0) 476 printk("[%02x] ", i * 4); 477 printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i])); 478 if ((i + 1) % 4 == 0) 479 printk("\n"); 480 } 481 } 482 483 err = mthca_SW2HW_MPT(dev, mailbox, 484 key & (dev->limits.num_mpts - 1), 485 &status); 486 if (err) { 487 mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err); 488 goto err_out_mailbox; 489 } else if (status) { 490 mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n", 491 status); 492 err = -EINVAL; 493 goto err_out_mailbox; 494 } 495 496 mthca_free_mailbox(dev, mailbox); 497 return err; 498 499 err_out_mailbox: 500 mthca_free_mailbox(dev, mailbox); 501 502 err_out_table: 503 mthca_table_put(dev, dev->mr_table.mpt_table, key); 504 505 err_out_mpt_free: 506 mthca_free(&dev->mr_table.mpt_alloc, key); 507 return err; 508 } 509 510 int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd, 511 u32 access, struct mthca_mr *mr) 512 { 513 mr->mtt = NULL; 514 return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr); 515 } 516 517 int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, 518 u64 *buffer_list, int buffer_size_shift, 519 int list_len, u64 iova, u64 total_size, 520 u32 access, struct mthca_mr *mr) 521 { 522 int err; 523 524 mr->mtt = mthca_alloc_mtt(dev, list_len); 525 if (IS_ERR(mr->mtt)) 526 return PTR_ERR(mr->mtt); 527 528 err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len); 529 if (err) { 530 mthca_free_mtt(dev, mr->mtt); 531 return err; 532 } 533 534 err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova, 535 total_size, access, mr); 536 if (err) 537 mthca_free_mtt(dev, mr->mtt); 538 539 return err; 540 } 541 542 /* Free mr or fmr */ 543 static void mthca_free_region(struct mthca_dev *dev, u32 lkey) 544 { 545 mthca_table_put(dev, dev->mr_table.mpt_table, 546 key_to_hw_index(dev, lkey)); 547 548 mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey)); 549 } 550 551 void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr) 552 { 553 int err; 554 u8 status; 555 556 err = mthca_HW2SW_MPT(dev, NULL, 557 key_to_hw_index(dev, mr->ibmr.lkey) & 558 (dev->limits.num_mpts - 1), 559 &status); 560 if (err) 561 mthca_warn(dev, "HW2SW_MPT failed (%d)\n", err); 562 else if (status) 563 mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n", 564 status); 565 566 mthca_free_region(dev, mr->ibmr.lkey); 567 mthca_free_mtt(dev, mr->mtt); 568 } 569 570 int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd, 571 u32 access, struct mthca_fmr *mr) 572 { 573 struct mthca_mpt_entry *mpt_entry; 574 struct mthca_mailbox *mailbox; 575 u64 mtt_seg; 576 u32 key, idx; 577 u8 status; 578 int list_len = mr->attr.max_pages; 579 int err = -ENOMEM; 580 int i; 581 582 if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32) 583 return -EINVAL; 584 585 /* For Arbel, all MTTs must fit in the same page. */ 586 if (mthca_is_memfree(dev) && 587 mr->attr.max_pages * sizeof *mr->mem.arbel.mtts > PAGE_SIZE) 588 return -EINVAL; 589 590 mr->maps = 0; 591 592 key = mthca_alloc(&dev->mr_table.mpt_alloc); 593 if (key == -1) 594 return -ENOMEM; 595 key = adjust_key(dev, key); 596 597 idx = key & (dev->limits.num_mpts - 1); 598 mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key); 599 600 if (mthca_is_memfree(dev)) { 601 err = mthca_table_get(dev, dev->mr_table.mpt_table, key); 602 if (err) 603 goto err_out_mpt_free; 604 605 mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key, NULL); 606 BUG_ON(!mr->mem.arbel.mpt); 607 } else 608 mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base + 609 sizeof *(mr->mem.tavor.mpt) * idx; 610 611 mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy); 612 if (IS_ERR(mr->mtt)) 613 goto err_out_table; 614 615 mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE; 616 617 if (mthca_is_memfree(dev)) { 618 mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table, 619 mr->mtt->first_seg, 620 &mr->mem.arbel.dma_handle); 621 BUG_ON(!mr->mem.arbel.mtts); 622 } else 623 mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg; 624 625 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 626 if (IS_ERR(mailbox)) 627 goto err_out_free_mtt; 628 629 mpt_entry = mailbox->buf; 630 631 mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS | 632 MTHCA_MPT_FLAG_MIO | 633 MTHCA_MPT_FLAG_REGION | 634 access); 635 636 mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12); 637 mpt_entry->key = cpu_to_be32(key); 638 mpt_entry->pd = cpu_to_be32(pd); 639 memset(&mpt_entry->start, 0, 640 sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, start)); 641 mpt_entry->mtt_seg = cpu_to_be64(dev->mr_table.mtt_base + mtt_seg); 642 643 if (0) { 644 mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey); 645 for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) { 646 if (i % 4 == 0) 647 printk("[%02x] ", i * 4); 648 printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i])); 649 if ((i + 1) % 4 == 0) 650 printk("\n"); 651 } 652 } 653 654 err = mthca_SW2HW_MPT(dev, mailbox, 655 key & (dev->limits.num_mpts - 1), 656 &status); 657 if (err) { 658 mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err); 659 goto err_out_mailbox_free; 660 } 661 if (status) { 662 mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n", 663 status); 664 err = -EINVAL; 665 goto err_out_mailbox_free; 666 } 667 668 mthca_free_mailbox(dev, mailbox); 669 return 0; 670 671 err_out_mailbox_free: 672 mthca_free_mailbox(dev, mailbox); 673 674 err_out_free_mtt: 675 mthca_free_mtt(dev, mr->mtt); 676 677 err_out_table: 678 mthca_table_put(dev, dev->mr_table.mpt_table, key); 679 680 err_out_mpt_free: 681 mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey); 682 return err; 683 } 684 685 int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr) 686 { 687 if (fmr->maps) 688 return -EBUSY; 689 690 mthca_free_region(dev, fmr->ibmr.lkey); 691 mthca_free_mtt(dev, fmr->mtt); 692 693 return 0; 694 } 695 696 static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list, 697 int list_len, u64 iova) 698 { 699 int i, page_mask; 700 701 if (list_len > fmr->attr.max_pages) 702 return -EINVAL; 703 704 page_mask = (1 << fmr->attr.page_shift) - 1; 705 706 /* We are getting page lists, so va must be page aligned. */ 707 if (iova & page_mask) 708 return -EINVAL; 709 710 /* Trust the user not to pass misaligned data in page_list */ 711 if (0) 712 for (i = 0; i < list_len; ++i) { 713 if (page_list[i] & ~page_mask) 714 return -EINVAL; 715 } 716 717 if (fmr->maps >= fmr->attr.max_maps) 718 return -EINVAL; 719 720 return 0; 721 } 722 723 724 int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, 725 int list_len, u64 iova) 726 { 727 struct mthca_fmr *fmr = to_mfmr(ibfmr); 728 struct mthca_dev *dev = to_mdev(ibfmr->device); 729 struct mthca_mpt_entry mpt_entry; 730 u32 key; 731 int i, err; 732 733 err = mthca_check_fmr(fmr, page_list, list_len, iova); 734 if (err) 735 return err; 736 737 ++fmr->maps; 738 739 key = tavor_key_to_hw_index(fmr->ibmr.lkey); 740 key += dev->limits.num_mpts; 741 fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); 742 743 writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); 744 745 for (i = 0; i < list_len; ++i) { 746 __be64 mtt_entry = cpu_to_be64(page_list[i] | 747 MTHCA_MTT_FLAG_PRESENT); 748 mthca_write64_raw(mtt_entry, fmr->mem.tavor.mtts + i); 749 } 750 751 mpt_entry.lkey = cpu_to_be32(key); 752 mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift)); 753 mpt_entry.start = cpu_to_be64(iova); 754 755 __raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key); 756 memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start, 757 offsetof(struct mthca_mpt_entry, window_count) - 758 offsetof(struct mthca_mpt_entry, start)); 759 760 writeb(MTHCA_MPT_STATUS_HW, fmr->mem.tavor.mpt); 761 762 return 0; 763 } 764 765 int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, 766 int list_len, u64 iova) 767 { 768 struct mthca_fmr *fmr = to_mfmr(ibfmr); 769 struct mthca_dev *dev = to_mdev(ibfmr->device); 770 u32 key; 771 int i, err; 772 773 err = mthca_check_fmr(fmr, page_list, list_len, iova); 774 if (err) 775 return err; 776 777 ++fmr->maps; 778 779 key = arbel_key_to_hw_index(fmr->ibmr.lkey); 780 if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 781 key += SINAI_FMR_KEY_INC; 782 else 783 key += dev->limits.num_mpts; 784 fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); 785 786 *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; 787 788 wmb(); 789 790 for (i = 0; i < list_len; ++i) 791 fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] | 792 MTHCA_MTT_FLAG_PRESENT); 793 794 dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle, 795 list_len * sizeof(u64), DMA_TO_DEVICE); 796 797 fmr->mem.arbel.mpt->key = cpu_to_be32(key); 798 fmr->mem.arbel.mpt->lkey = cpu_to_be32(key); 799 fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift)); 800 fmr->mem.arbel.mpt->start = cpu_to_be64(iova); 801 802 wmb(); 803 804 *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_HW; 805 806 wmb(); 807 808 return 0; 809 } 810 811 void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) 812 { 813 u32 key; 814 815 if (!fmr->maps) 816 return; 817 818 key = tavor_key_to_hw_index(fmr->ibmr.lkey); 819 key &= dev->limits.num_mpts - 1; 820 fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); 821 822 fmr->maps = 0; 823 824 writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); 825 } 826 827 void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) 828 { 829 u32 key; 830 831 if (!fmr->maps) 832 return; 833 834 key = arbel_key_to_hw_index(fmr->ibmr.lkey); 835 key &= dev->limits.num_mpts - 1; 836 fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); 837 838 fmr->maps = 0; 839 840 *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; 841 } 842 843 int mthca_init_mr_table(struct mthca_dev *dev) 844 { 845 unsigned long addr; 846 int mpts, mtts, err, i; 847 848 err = mthca_alloc_init(&dev->mr_table.mpt_alloc, 849 dev->limits.num_mpts, 850 ~0, dev->limits.reserved_mrws); 851 if (err) 852 return err; 853 854 if (!mthca_is_memfree(dev) && 855 (dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) 856 dev->limits.fmr_reserved_mtts = 0; 857 else 858 dev->mthca_flags |= MTHCA_FLAG_FMR; 859 860 if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 861 mthca_dbg(dev, "Memory key throughput optimization activated.\n"); 862 863 err = mthca_buddy_init(&dev->mr_table.mtt_buddy, 864 fls(dev->limits.num_mtt_segs - 1)); 865 866 if (err) 867 goto err_mtt_buddy; 868 869 dev->mr_table.tavor_fmr.mpt_base = NULL; 870 dev->mr_table.tavor_fmr.mtt_base = NULL; 871 872 if (dev->limits.fmr_reserved_mtts) { 873 i = fls(dev->limits.fmr_reserved_mtts - 1); 874 875 if (i >= 31) { 876 mthca_warn(dev, "Unable to reserve 2^31 FMR MTTs.\n"); 877 err = -EINVAL; 878 goto err_fmr_mpt; 879 } 880 mpts = mtts = 1 << i; 881 } else { 882 mpts = dev->limits.num_mtt_segs; 883 mtts = dev->limits.num_mpts; 884 } 885 886 if (!mthca_is_memfree(dev) && 887 (dev->mthca_flags & MTHCA_FLAG_FMR)) { 888 889 addr = pci_resource_start(dev->pdev, 4) + 890 ((pci_resource_len(dev->pdev, 4) - 1) & 891 dev->mr_table.mpt_base); 892 893 dev->mr_table.tavor_fmr.mpt_base = 894 ioremap(addr, mpts * sizeof(struct mthca_mpt_entry)); 895 896 if (!dev->mr_table.tavor_fmr.mpt_base) { 897 mthca_warn(dev, "MPT ioremap for FMR failed.\n"); 898 err = -ENOMEM; 899 goto err_fmr_mpt; 900 } 901 902 addr = pci_resource_start(dev->pdev, 4) + 903 ((pci_resource_len(dev->pdev, 4) - 1) & 904 dev->mr_table.mtt_base); 905 906 dev->mr_table.tavor_fmr.mtt_base = 907 ioremap(addr, mtts * MTHCA_MTT_SEG_SIZE); 908 if (!dev->mr_table.tavor_fmr.mtt_base) { 909 mthca_warn(dev, "MTT ioremap for FMR failed.\n"); 910 err = -ENOMEM; 911 goto err_fmr_mtt; 912 } 913 } 914 915 if (dev->limits.fmr_reserved_mtts) { 916 err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, fls(mtts - 1)); 917 if (err) 918 goto err_fmr_mtt_buddy; 919 920 /* Prevent regular MRs from using FMR keys */ 921 err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, fls(mtts - 1)); 922 if (err) 923 goto err_reserve_fmr; 924 925 dev->mr_table.fmr_mtt_buddy = 926 &dev->mr_table.tavor_fmr.mtt_buddy; 927 } else 928 dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy; 929 930 /* FMR table is always the first, take reserved MTTs out of there */ 931 if (dev->limits.reserved_mtts) { 932 i = fls(dev->limits.reserved_mtts - 1); 933 934 if (mthca_alloc_mtt_range(dev, i, 935 dev->mr_table.fmr_mtt_buddy) == -1) { 936 mthca_warn(dev, "MTT table of order %d is too small.\n", 937 dev->mr_table.fmr_mtt_buddy->max_order); 938 err = -ENOMEM; 939 goto err_reserve_mtts; 940 } 941 } 942 943 return 0; 944 945 err_reserve_mtts: 946 err_reserve_fmr: 947 if (dev->limits.fmr_reserved_mtts) 948 mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); 949 950 err_fmr_mtt_buddy: 951 if (dev->mr_table.tavor_fmr.mtt_base) 952 iounmap(dev->mr_table.tavor_fmr.mtt_base); 953 954 err_fmr_mtt: 955 if (dev->mr_table.tavor_fmr.mpt_base) 956 iounmap(dev->mr_table.tavor_fmr.mpt_base); 957 958 err_fmr_mpt: 959 mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); 960 961 err_mtt_buddy: 962 mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); 963 964 return err; 965 } 966 967 void mthca_cleanup_mr_table(struct mthca_dev *dev) 968 { 969 /* XXX check if any MRs are still allocated? */ 970 if (dev->limits.fmr_reserved_mtts) 971 mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); 972 973 mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); 974 975 if (dev->mr_table.tavor_fmr.mtt_base) 976 iounmap(dev->mr_table.tavor_fmr.mtt_base); 977 if (dev->mr_table.tavor_fmr.mpt_base) 978 iounmap(dev->mr_table.tavor_fmr.mpt_base); 979 980 mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); 981 } 982