diff options
| author | Jack Morgenstein <jackm@dev.mellanox.co.il> | 2012-08-03 04:40:42 -0400 |
|---|---|---|
| committer | Roland Dreier <roland@purestorage.com> | 2012-09-30 23:33:32 -0400 |
| commit | fc06573dfaf8a33bc0533bb70c49de13fa5232a4 (patch) | |
| tree | 034d40d1b3f21a53ff52be78b8fcfea0222aa891 | |
| parent | e2c76824ca16a3e8443cc7b26abcb21af7c27b10 (diff) | |
IB/mlx4: Initialize SR-IOV IB support for slaves in master context
Allocate SR-IOV paravirtualization resources and MAD demuxing contexts
on the master.
This has two parts. The first part is to initialize the structures to
contain the contexts. This is done at master startup time in
mlx4_ib_init_sriov().
The second part is to actually create the tunneling resources required
on the master to support a slave. This is performed the master
detects that a slave has started up (MLX4_DEV_EVENT_SLAVE_INIT event
generated when a slave initializes its comm channel).
For the master, there is no such startup event, so it creates its own
tunneling resources when it starts up. In addition, the master also
creates the real special QPs. The ib_core layer on the master causes
creation of proxy special QPs, since the master is also
paravirtualized at the ib_core layer.
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Roland Dreier <roland@purestorage.com>
| -rw-r--r-- | drivers/infiniband/hw/mlx4/mad.c | 684 | ||||
| -rw-r--r-- | drivers/infiniband/hw/mlx4/main.c | 80 | ||||
| -rw-r--r-- | drivers/infiniband/hw/mlx4/mlx4_ib.h | 34 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 3 | ||||
| -rw-r--r-- | include/linux/mlx4/device.h | 3 | ||||
| -rw-r--r-- | include/linux/mlx4/driver.h | 2 |
6 files changed, 798 insertions, 8 deletions
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 9c2ae7efd00..e98849338a9 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c | |||
| @@ -44,6 +44,35 @@ enum { | |||
| 44 | MLX4_IB_VENDOR_CLASS2 = 0xa | 44 | MLX4_IB_VENDOR_CLASS2 = 0xa |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | #define MLX4_TUN_SEND_WRID_SHIFT 34 | ||
| 48 | #define MLX4_TUN_QPN_SHIFT 32 | ||
| 49 | #define MLX4_TUN_WRID_RECV (((u64) 1) << MLX4_TUN_SEND_WRID_SHIFT) | ||
| 50 | #define MLX4_TUN_SET_WRID_QPN(a) (((u64) ((a) & 0x3)) << MLX4_TUN_QPN_SHIFT) | ||
| 51 | |||
| 52 | #define MLX4_TUN_IS_RECV(a) (((a) >> MLX4_TUN_SEND_WRID_SHIFT) & 0x1) | ||
| 53 | #define MLX4_TUN_WRID_QPN(a) (((a) >> MLX4_TUN_QPN_SHIFT) & 0x3) | ||
| 54 | |||
| 55 | struct mlx4_mad_rcv_buf { | ||
| 56 | struct ib_grh grh; | ||
| 57 | u8 payload[256]; | ||
| 58 | } __packed; | ||
| 59 | |||
| 60 | struct mlx4_mad_snd_buf { | ||
| 61 | u8 payload[256]; | ||
| 62 | } __packed; | ||
| 63 | |||
| 64 | struct mlx4_tunnel_mad { | ||
| 65 | struct ib_grh grh; | ||
| 66 | struct mlx4_ib_tunnel_header hdr; | ||
| 67 | struct ib_mad mad; | ||
| 68 | } __packed; | ||
| 69 | |||
| 70 | struct mlx4_rcv_tunnel_mad { | ||
| 71 | struct mlx4_rcv_tunnel_hdr hdr; | ||
| 72 | struct ib_grh grh; | ||
| 73 | struct ib_mad mad; | ||
| 74 | } __packed; | ||
| 75 | |||
| 47 | int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey, | 76 | int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey, |
| 48 | int port, struct ib_wc *in_wc, struct ib_grh *in_grh, | 77 | int port, struct ib_wc *in_wc, struct ib_grh *in_grh, |
| 49 | void *in_mad, void *response_mad) | 78 | void *in_mad, void *response_mad) |
| @@ -516,3 +545,658 @@ void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num, | |||
| 516 | 545 | ||
| 517 | ib_dispatch_event(&event); | 546 | ib_dispatch_event(&event); |
| 518 | } | 547 | } |
| 548 | |||
| 549 | static void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg) | ||
| 550 | { | ||
| 551 | unsigned long flags; | ||
| 552 | struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; | ||
| 553 | struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); | ||
| 554 | spin_lock_irqsave(&dev->sriov.going_down_lock, flags); | ||
| 555 | if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) | ||
| 556 | queue_work(ctx->wq, &ctx->work); | ||
| 557 | spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); | ||
| 558 | } | ||
| 559 | |||
| 560 | static int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx, | ||
| 561 | struct mlx4_ib_demux_pv_qp *tun_qp, | ||
| 562 | int index) | ||
| 563 | { | ||
| 564 | struct ib_sge sg_list; | ||
| 565 | struct ib_recv_wr recv_wr, *bad_recv_wr; | ||
| 566 | int size; | ||
| 567 | |||
| 568 | size = (tun_qp->qp->qp_type == IB_QPT_UD) ? | ||
| 569 | sizeof (struct mlx4_tunnel_mad) : sizeof (struct mlx4_mad_rcv_buf); | ||
| 570 | |||
| 571 | sg_list.addr = tun_qp->ring[index].map; | ||
| 572 | sg_list.length = size; | ||
| 573 | sg_list.lkey = ctx->mr->lkey; | ||
| 574 | |||
| 575 | recv_wr.next = NULL; | ||
| 576 | recv_wr.sg_list = &sg_list; | ||
| 577 | recv_wr.num_sge = 1; | ||
| 578 | recv_wr.wr_id = (u64) index | MLX4_TUN_WRID_RECV | | ||
| 579 | MLX4_TUN_SET_WRID_QPN(tun_qp->proxy_qpt); | ||
| 580 | ib_dma_sync_single_for_device(ctx->ib_dev, tun_qp->ring[index].map, | ||
| 581 | size, DMA_FROM_DEVICE); | ||
| 582 | return ib_post_recv(tun_qp->qp, &recv_wr, &bad_recv_wr); | ||
| 583 | } | ||
| 584 | |||
| 585 | static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, | ||
| 586 | enum ib_qp_type qp_type, int is_tun) | ||
| 587 | { | ||
| 588 | int i; | ||
| 589 | struct mlx4_ib_demux_pv_qp *tun_qp; | ||
| 590 | int rx_buf_size, tx_buf_size; | ||
| 591 | |||
| 592 | if (qp_type > IB_QPT_GSI) | ||
| 593 | return -EINVAL; | ||
| 594 | |||
| 595 | tun_qp = &ctx->qp[qp_type]; | ||
| 596 | |||
| 597 | tun_qp->ring = kzalloc(sizeof (struct mlx4_ib_buf) * MLX4_NUM_TUNNEL_BUFS, | ||
| 598 | GFP_KERNEL); | ||
| 599 | if (!tun_qp->ring) | ||
| 600 | return -ENOMEM; | ||
| 601 | |||
| 602 | tun_qp->tx_ring = kcalloc(MLX4_NUM_TUNNEL_BUFS, | ||
| 603 | sizeof (struct mlx4_ib_tun_tx_buf), | ||
| 604 | GFP_KERNEL); | ||
| 605 | if (!tun_qp->tx_ring) { | ||
| 606 | kfree(tun_qp->ring); | ||
| 607 | tun_qp->ring = NULL; | ||
| 608 | return -ENOMEM; | ||
| 609 | } | ||
| 610 | |||
| 611 | if (is_tun) { | ||
| 612 | rx_buf_size = sizeof (struct mlx4_tunnel_mad); | ||
| 613 | tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); | ||
| 614 | } else { | ||
| 615 | rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); | ||
| 616 | tx_buf_size = sizeof (struct mlx4_mad_snd_buf); | ||
| 617 | } | ||
| 618 | |||
| 619 | for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { | ||
| 620 | tun_qp->ring[i].addr = kmalloc(rx_buf_size, GFP_KERNEL); | ||
| 621 | if (!tun_qp->ring[i].addr) | ||
| 622 | goto err; | ||
| 623 | tun_qp->ring[i].map = ib_dma_map_single(ctx->ib_dev, | ||
| 624 | tun_qp->ring[i].addr, | ||
| 625 | rx_buf_size, | ||
| 626 | DMA_FROM_DEVICE); | ||
| 627 | } | ||
| 628 | |||
| 629 | for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { | ||
| 630 | tun_qp->tx_ring[i].buf.addr = | ||
| 631 | kmalloc(tx_buf_size, GFP_KERNEL); | ||
| 632 | if (!tun_qp->tx_ring[i].buf.addr) | ||
| 633 | goto tx_err; | ||
| 634 | tun_qp->tx_ring[i].buf.map = | ||
| 635 | ib_dma_map_single(ctx->ib_dev, | ||
| 636 | tun_qp->tx_ring[i].buf.addr, | ||
| 637 | tx_buf_size, | ||
| 638 | DMA_TO_DEVICE); | ||
| 639 | tun_qp->tx_ring[i].ah = NULL; | ||
| 640 | } | ||
| 641 | spin_lock_init(&tun_qp->tx_lock); | ||
| 642 | tun_qp->tx_ix_head = 0; | ||
| 643 | tun_qp->tx_ix_tail = 0; | ||
| 644 | tun_qp->proxy_qpt = qp_type; | ||
| 645 | |||
| 646 | return 0; | ||
| 647 | |||
| 648 | tx_err: | ||
| 649 | while (i > 0) { | ||
| 650 | --i; | ||
| 651 | ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, | ||
| 652 | tx_buf_size, DMA_TO_DEVICE); | ||
| 653 | kfree(tun_qp->tx_ring[i].buf.addr); | ||
| 654 | } | ||
| 655 | kfree(tun_qp->tx_ring); | ||
| 656 | tun_qp->tx_ring = NULL; | ||
| 657 | i = MLX4_NUM_TUNNEL_BUFS; | ||
| 658 | err: | ||
| 659 | while (i > 0) { | ||
| 660 | --i; | ||
| 661 | ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, | ||
| 662 | rx_buf_size, DMA_FROM_DEVICE); | ||
| 663 | kfree(tun_qp->ring[i].addr); | ||
| 664 | } | ||
| 665 | kfree(tun_qp->ring); | ||
| 666 | tun_qp->ring = NULL; | ||
| 667 | return -ENOMEM; | ||
| 668 | } | ||
| 669 | |||
| 670 | static void mlx4_ib_free_pv_qp_bufs(struct mlx4_ib_demux_pv_ctx *ctx, | ||
| 671 | enum ib_qp_type qp_type, int is_tun) | ||
| 672 | { | ||
| 673 | int i; | ||
| 674 | struct mlx4_ib_demux_pv_qp *tun_qp; | ||
| 675 | int rx_buf_size, tx_buf_size; | ||
| 676 | |||
| 677 | if (qp_type > IB_QPT_GSI) | ||
| 678 | return; | ||
| 679 | |||
| 680 | tun_qp = &ctx->qp[qp_type]; | ||
| 681 | if (is_tun) { | ||
| 682 | rx_buf_size = sizeof (struct mlx4_tunnel_mad); | ||
| 683 | tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); | ||
| 684 | } else { | ||
| 685 | rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); | ||
| 686 | tx_buf_size = sizeof (struct mlx4_mad_snd_buf); | ||
| 687 | } | ||
| 688 | |||
| 689 | |||
| 690 | for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { | ||
| 691 | ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, | ||
| 692 | rx_buf_size, DMA_FROM_DEVICE); | ||
| 693 | kfree(tun_qp->ring[i].addr); | ||
| 694 | } | ||
| 695 | |||
| 696 | for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { | ||
| 697 | ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, | ||
| 698 | tx_buf_size, DMA_TO_DEVICE); | ||
| 699 | kfree(tun_qp->tx_ring[i].buf.addr); | ||
| 700 | if (tun_qp->tx_ring[i].ah) | ||
