aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/mthca/mthca_memfree.c
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2005-07-07 20:57:16 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:49 -0400
commit56483ec1b70221f8c9838ccc9a89b43d9de66993 (patch)
treefa91d177d6d7b34e08ee6f16a859db4c7e65bef1 /drivers/infiniband/hw/mthca/mthca_memfree.c
parente95975e8b87de47c08e032e7762fc7df7dfc2060 (diff)
[PATCH] IB uverbs: add mthca user doorbell record support
Add support for userspace doorbell records to mthca. Signed-off-by: Roland Dreier <rolandd@cisco.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/infiniband/hw/mthca/mthca_memfree.c')
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c141
1 files changed, 136 insertions, 5 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 6d3b05dd9e3f..2a8646150355 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 2 * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
3 * Copyright (c) 2005 Cisco Systems. All rights reserved.
3 * 4 *
4 * This software is available to you under a choice of one of two 5 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU 6 * licenses. You may choose to be licensed under the terms of the GNU
@@ -47,6 +48,15 @@ enum {
47 MTHCA_TABLE_CHUNK_SIZE = 1 << 18 48 MTHCA_TABLE_CHUNK_SIZE = 1 << 18
48}; 49};
49 50
51struct mthca_user_db_table {
52 struct semaphore mutex;
53 struct {
54 u64 uvirt;
55 struct scatterlist mem;
56 int refcount;
57 } page[0];
58};
59
50void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) 60void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
51{ 61{
52 struct mthca_icm_chunk *chunk, *tmp; 62 struct mthca_icm_chunk *chunk, *tmp;
@@ -344,13 +354,133 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
344 kfree(table); 354 kfree(table);
345} 355}
346 356
347static u64 mthca_uarc_virt(struct mthca_dev *dev, int page) 357static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page)
348{ 358{
349 return dev->uar_table.uarc_base + 359 return dev->uar_table.uarc_base +
350 dev->driver_uar.index * dev->uar_table.uarc_size + 360 uar->index * dev->uar_table.uarc_size +
351 page * 4096; 361 page * 4096;
352} 362}
353 363
364int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
365 struct mthca_user_db_table *db_tab, int index, u64 uaddr)
366{
367 int ret = 0;
368 u8 status;
369 int i;
370
371 if (!mthca_is_memfree(dev))
372 return 0;
373
374 if (index < 0 || index > dev->uar_table.uarc_size / 8)
375 return -EINVAL;
376
377 down(&db_tab->mutex);
378
379 i = index / MTHCA_DB_REC_PER_PAGE;
380
381 if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE) ||
382 (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) ||
383 (uaddr & 4095)) {
384 ret = -EINVAL;
385 goto out;
386 }
387
388 if (db_tab->page[i].refcount) {
389 ++db_tab->page[i].refcount;
390 goto out;
391 }
392
393 ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0,
394 &db_tab->page[i].mem.page, NULL);
395 if (ret < 0)
396 goto out;
397
398 db_tab->page[i].mem.length = 4096;
399 db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
400
401 ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
402 if (ret < 0) {
403 put_page(db_tab->page[i].mem.page);
404 goto out;
405 }
406
407 ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem),
408 mthca_uarc_virt(dev, uar, i), &status);
409 if (!ret && status)
410 ret = -EINVAL;
411 if (ret) {
412 pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
413 put_page(db_tab->page[i].mem.page);
414 goto out;
415 }
416
417 db_tab->page[i].uvirt = uaddr;
418 db_tab->page[i].refcount = 1;
419
420out:
421 up(&db_tab->mutex);
422 return ret;
423}
424
425void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
426 struct mthca_user_db_table *db_tab, int index)
427{
428 if (!mthca_is_memfree(dev))
429 return;
430
431 /*
432 * To make our bookkeeping simpler, we don't unmap DB
433 * pages until we clean up the whole db table.
434 */
435
436 down(&db_tab->mutex);
437
438 --db_tab->page[index / MTHCA_DB_REC_PER_PAGE].refcount;
439
440 up(&db_tab->mutex);
441}
442
443struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev)
444{
445 struct mthca_user_db_table *db_tab;
446 int npages;
447 int i;
448
449 if (!mthca_is_memfree(dev))
450 return NULL;
451
452 npages = dev->uar_table.uarc_size / 4096;
453 db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL);
454 if (!db_tab)
455 return ERR_PTR(-ENOMEM);
456
457 init_MUTEX(&db_tab->mutex);
458 for (i = 0; i < npages; ++i) {
459 db_tab->page[i].refcount = 0;
460 db_tab->page[i].uvirt = 0;
461 }
462
463 return db_tab;
464}
465
466void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
467 struct mthca_user_db_table *db_tab)
468{
469 int i;
470 u8 status;
471
472 if (!mthca_is_memfree(dev))
473 return;
474
475 for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) {
476 if (db_tab->page[i].uvirt) {
477 mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
478 pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
479 put_page(db_tab->page[i].mem.page);
480 }
481 }
482}
483
354int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db) 484int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
355{ 485{
356 int group; 486 int group;
@@ -407,7 +537,8 @@ int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
407 } 537 }
408 memset(page->db_rec, 0, 4096); 538 memset(page->db_rec, 0, 4096);
409 539
410 ret = mthca_MAP_ICM_page(dev, page->mapping, mthca_uarc_virt(dev, i), &status); 540 ret = mthca_MAP_ICM_page(dev, page->mapping,
541 mthca_uarc_virt(dev, &dev->driver_uar, i), &status);
411 if (!ret && status) 542 if (!ret && status)
412 ret = -EINVAL; 543 ret = -EINVAL;
413 if (ret) { 544 if (ret) {
@@ -461,7 +592,7 @@ void mthca_free_db(struct mthca_dev *dev, int type, int db_index)
461 592
462 if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) && 593 if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) &&
463 i >= dev->db_tab->max_group1 - 1) { 594 i >= dev->db_tab->max_group1 - 1) {
464 mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status); 595 mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
465 596
466 dma_free_coherent(&dev->pdev->dev, 4096, 597 dma_free_coherent(&dev->pdev->dev, 4096,
467 page->db_rec, page->mapping); 598 page->db_rec, page->mapping);
@@ -530,7 +661,7 @@ void mthca_cleanup_db_tab(struct mthca_dev *dev)
530 if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE)) 661 if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE))
531 mthca_warn(dev, "Kernel UARC page %d not empty\n", i); 662 mthca_warn(dev, "Kernel UARC page %d not empty\n", i);
532 663
533 mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status); 664 mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
534 665
535 dma_free_coherent(&dev->pdev->dev, 4096, 666 dma_free_coherent(&dev->pdev->dev, 4096,
536 dev->db_tab->page[i].db_rec, 667 dev->db_tab->page[i].db_rec,