diff options
author | Roland Dreier <rolandd@cisco.com> | 2005-07-07 20:57:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-07 21:23:49 -0400 |
commit | 56483ec1b70221f8c9838ccc9a89b43d9de66993 (patch) | |
tree | fa91d177d6d7b34e08ee6f16a859db4c7e65bef1 | |
parent | e95975e8b87de47c08e032e7762fc7df7dfc2060 (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>
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_memfree.c | 141 | ||||
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_memfree.h | 14 |
2 files changed, 149 insertions, 6 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 | ||
51 | struct 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 | |||
50 | void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) | 60 | void 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 | ||
347 | static u64 mthca_uarc_virt(struct mthca_dev *dev, int page) | 357 | static 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 | ||
364 | int 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 | |||
420 | out: | ||
421 | up(&db_tab->mutex); | ||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | void 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 | |||
443 | struct 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 | |||
466 | void 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 | |||
354 | int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db) | 484 | int 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, |
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h index fe7be2a6bc4a..4761d844cb5f 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/drivers/infiniband/hw/mthca/mthca_memfree.h | |||
@@ -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 |
@@ -148,7 +149,7 @@ struct mthca_db_table { | |||
148 | struct semaphore mutex; | 149 | struct semaphore mutex; |
149 | }; | 150 | }; |
150 | 151 | ||
151 | enum { | 152 | enum mthca_db_type { |
152 | MTHCA_DB_TYPE_INVALID = 0x0, | 153 | MTHCA_DB_TYPE_INVALID = 0x0, |
153 | MTHCA_DB_TYPE_CQ_SET_CI = 0x1, | 154 | MTHCA_DB_TYPE_CQ_SET_CI = 0x1, |
154 | MTHCA_DB_TYPE_CQ_ARM = 0x2, | 155 | MTHCA_DB_TYPE_CQ_ARM = 0x2, |
@@ -158,6 +159,17 @@ enum { | |||
158 | MTHCA_DB_TYPE_GROUP_SEP = 0x7 | 159 | MTHCA_DB_TYPE_GROUP_SEP = 0x7 |
159 | }; | 160 | }; |
160 | 161 | ||
162 | struct mthca_user_db_table; | ||
163 | struct mthca_uar; | ||
164 | |||
165 | int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, | ||
166 | struct mthca_user_db_table *db_tab, int index, u64 uaddr); | ||
167 | void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar, | ||
168 | struct mthca_user_db_table *db_tab, int index); | ||
169 | struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev); | ||
170 | void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, | ||
171 | struct mthca_user_db_table *db_tab); | ||
172 | |||
161 | int mthca_init_db_tab(struct mthca_dev *dev); | 173 | int mthca_init_db_tab(struct mthca_dev *dev); |
162 | void mthca_cleanup_db_tab(struct mthca_dev *dev); | 174 | void mthca_cleanup_db_tab(struct mthca_dev *dev); |
163 | int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db); | 175 | int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db); |