| @@ -53,6 +53,7 @@ static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, · 52 unmodified lines |
| 53 | 53 | struct mlx4_ib_cq *recv_cq); |
| 54 | 54 | static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, |
| 55 | 55 | struct mlx4_ib_cq *recv_cq); |
| 56 | +static int _mlx4_ib_modify_wq(struct ib_wq *ibwq, enum ib_wq_state new_state); |
| 56 | 57 | |
| 57 | 58 | enum { |
| 58 | 59 | MLX4_IB_ACK_REQ_FREQ = 8, |
| @@ -650,6 +651,212 @@ static void mlx4_ib_free_qp_counter(struct mlx4_ib_dev *dev, · 591 unmodified lines |
| 650 | 651 | qp->counter_index = NULL; |
| 651 | 652 | } |
| 652 | 653 | |
| 654 | +static int set_qp_rss(struct mlx4_ib_dev *dev, struct mlx4_ib_rss *rss_ctx, |
| 655 | + struct ib_qp_init_attr *init_attr, |
| 656 | + struct mlx4_ib_create_qp_rss *ucmd) |
| 657 | +{ |
| 658 | + rss_ctx->base_qpn_tbl_sz = init_attr->rwq_ind_tbl->ind_tbl[0]->wq_num | |
| 659 | + (init_attr->rwq_ind_tbl->log_ind_tbl_size << 24); |
| 660 | + |
| 661 | + if ((ucmd->rx_hash_function == MLX4_IB_RX_HASH_FUNC_TOEPLITZ) && |
| 662 | + (dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP)) { |
| 663 | + memcpy(rss_ctx->rss_key, ucmd->rx_hash_key, |
| 664 | + MLX4_EN_RSS_KEY_SIZE); |
| 665 | + } else { |
| 666 | + pr_debug("RX Hash function is not supported\n"); |
| 667 | + return (-EOPNOTSUPP); |
| 668 | + } |
| 669 | + |
| 670 | + if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV4) && |
| 671 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV4)) { |
| 672 | + rss_ctx->flags = MLX4_RSS_IPV4; |
| 673 | + } else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV4) || |
| 674 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV4)) { |
| 675 | + pr_debug("RX Hash fields_mask is not supported - both IPv4 SRC and DST must be set\n"); |
| 676 | + return (-EOPNOTSUPP); |
| 677 | + } |
| 678 | + |
| 679 | + if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV6) && |
| 680 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV6)) { |
| 681 | + rss_ctx->flags |= MLX4_RSS_IPV6; |
| 682 | + } else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV6) || |
| 683 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV6)) { |
| 684 | + pr_debug("RX Hash fields_mask is not supported - both IPv6 SRC and DST must be set\n"); |
| 685 | + return (-EOPNOTSUPP); |
| 686 | + } |
| 687 | + |
| 688 | + if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_UDP) && |
| 689 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_UDP)) { |
| 690 | + if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UDP_RSS)) { |
| 691 | + pr_debug("RX Hash fields_mask for UDP is not supported\n"); |
| 692 | + return (-EOPNOTSUPP); |
| 693 | + } |
| 694 | + |
| 695 | + if (rss_ctx->flags & MLX4_RSS_IPV4) { |
| 696 | + rss_ctx->flags |= MLX4_RSS_UDP_IPV4; |
| 697 | + } else if (rss_ctx->flags & MLX4_RSS_IPV6) { |
| 698 | + rss_ctx->flags |= MLX4_RSS_UDP_IPV6; |
| 699 | + } else { |
| 700 | + pr_debug("RX Hash fields_mask is not supported - UDP must be set with IPv4 or IPv6\n"); |
| 701 | + return (-EOPNOTSUPP); |
| 702 | + } |
| 703 | + } else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_UDP) || |
| 704 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_UDP)) { |
| 705 | + pr_debug("RX Hash fields_mask is not supported - both UDP SRC and DST must be set\n"); |
| 706 | + return (-EOPNOTSUPP); |
| 707 | + } |
| 708 | + |
| 709 | + if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) && |
| 710 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) { |
| 711 | + if (rss_ctx->flags & MLX4_RSS_IPV4) { |
| 712 | + rss_ctx->flags |= MLX4_RSS_TCP_IPV4; |
| 713 | + } else if (rss_ctx->flags & MLX4_RSS_IPV6) { |
| 714 | + rss_ctx->flags |= MLX4_RSS_TCP_IPV6; |
| 715 | + } else { |
| 716 | + pr_debug("RX Hash fields_mask is not supported - TCP must be set with IPv4 or IPv6\n"); |
| 717 | + return (-EOPNOTSUPP); |
| 718 | + } |
| 719 | + |
| 720 | + } else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) || |
| 721 | + (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) { |
| 722 | + pr_debug("RX Hash fields_mask is not supported - both TCP SRC and DST must be set\n"); |
| 723 | + return (-EOPNOTSUPP); |
| 724 | + } |
| 725 | + |
| 726 | + return 0; |
| 727 | +} |
| 728 | + |
| 729 | +static int create_qp_rss(struct mlx4_ib_dev *dev, struct ib_pd *ibpd, |
| 730 | + struct ib_qp_init_attr *init_attr, |
| 731 | + struct mlx4_ib_create_qp_rss *ucmd, |
| 732 | + struct mlx4_ib_qp *qp) |
| 733 | +{ |
| 734 | + int qpn; |
| 735 | + int err; |
| 736 | + |
| 737 | + qp->mqp.usage = MLX4_RES_USAGE_USER_VERBS; |
| 738 | + |
| 739 | + err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn, 0, qp->mqp.usage); |
| 740 | + if (err) |
| 741 | + return err; |
| 742 | + |
| 743 | + err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp); |
| 744 | + if (err) |
| 745 | + goto err_qpn; |
| 746 | + |
| 747 | + mutex_init(&qp->mutex); |
| 748 | + |
| 749 | + INIT_LIST_HEAD(&qp->gid_list); |
| 750 | + INIT_LIST_HEAD(&qp->steering_rules); |
| 751 | + |
| 752 | + qp->mlx4_ib_qp_type = MLX4_IB_QPT_RAW_ETHERTYPE; |
| 753 | + qp->state = IB_QPS_RESET; |
| 754 | + |
| 755 | + /* Set dummy send resources to be compatible with HV and PRM */ |
| 756 | + qp->sq_no_prefetch = 1; |
| 757 | + qp->sq.wqe_cnt = 1; |
| 758 | + qp->sq.wqe_shift = MLX4_IB_MIN_SQ_STRIDE; |
| 759 | + qp->buf_size = qp->sq.wqe_cnt << MLX4_IB_MIN_SQ_STRIDE; |
| 760 | + qp->mtt = (to_mqp( |
| 761 | + (struct ib_qp *)init_attr->rwq_ind_tbl->ind_tbl[0]))->mtt; |
| 762 | + |
| 763 | + qp->rss_ctx = kzalloc(sizeof(*qp->rss_ctx), GFP_KERNEL); |
| 764 | + if (!qp->rss_ctx) { |
| 765 | + err = -ENOMEM; |
| 766 | + goto err_qp_alloc; |
| 767 | + } |
| 768 | + |
| 769 | + err = set_qp_rss(dev, qp->rss_ctx, init_attr, ucmd); |
| 770 | + if (err) |
| 771 | + goto err; |
| 772 | + |
| 773 | + return 0; |
| 774 | + |
| 775 | +err: |
| 776 | + kfree(qp->rss_ctx); |
| 777 | + |
| 778 | +err_qp_alloc: |
| 779 | + mlx4_qp_remove(dev->dev, &qp->mqp); |
| 780 | + mlx4_qp_free(dev->dev, &qp->mqp); |
| 781 | + |
| 782 | +err_qpn: |
| 783 | + mlx4_qp_release_range(dev->dev, qpn, 1); |
| 784 | + return err; |
| 785 | +} |
| 786 | + |
| 787 | +static struct ib_qp *_mlx4_ib_create_qp_rss(struct ib_pd *pd, |
| 788 | + struct ib_qp_init_attr *init_attr, |
| 789 | + struct ib_udata *udata) |
| 790 | +{ |
| 791 | + struct mlx4_ib_qp *qp; |
| 792 | + struct mlx4_ib_create_qp_rss ucmd = {}; |
| 793 | + size_t required_cmd_sz; |
| 794 | + int err; |
| 795 | + |
| 796 | + if (!udata) { |
| 797 | + pr_debug("RSS QP with NULL udata\n"); |
| 798 | + return ERR_PTR(-EINVAL); |
| 799 | + } |
| 800 | + |
| 801 | + if (udata->outlen) |
| 802 | + return ERR_PTR(-EOPNOTSUPP); |
| 803 | + |
| 804 | + required_cmd_sz = offsetof(typeof(ucmd), reserved1) + |
| 805 | + sizeof(ucmd.reserved1); |
| 806 | + if (udata->inlen < required_cmd_sz) { |
| 807 | + pr_debug("invalid inlen\n"); |
| 808 | + return ERR_PTR(-EINVAL); |
| 809 | + } |
| 810 | + |
| 811 | + if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) { |
| 812 | + pr_debug("copy failed\n"); |
| 813 | + return ERR_PTR(-EFAULT); |
| 814 | + } |
| 815 | + |
| 816 | + if (ucmd.comp_mask || ucmd.reserved1) |
| 817 | + return ERR_PTR(-EOPNOTSUPP); |
| 818 | + |
| 819 | + if (udata->inlen > sizeof(ucmd) && |
| 820 | + !ib_is_udata_cleared(udata, sizeof(ucmd), |
| 821 | + udata->inlen - sizeof(ucmd))) { |
| 822 | + pr_debug("inlen is not supported\n"); |
| 823 | + return ERR_PTR(-EOPNOTSUPP); |
| 824 | + } |
| 825 | + |
| 826 | + if (init_attr->qp_type != IB_QPT_RAW_PACKET) { |
| 827 | + pr_debug("RSS QP with unsupported QP type %d\n", |
| 828 | + init_attr->qp_type); |
| 829 | + return ERR_PTR(-EOPNOTSUPP); |
| 830 | + } |
| 831 | + |
| 832 | + if (init_attr->create_flags) { |
| 833 | + pr_debug("RSS QP doesn't support create flags\n"); |
| 834 | + return ERR_PTR(-EOPNOTSUPP); |
| 835 | + } |
| 836 | + |
| 837 | + if (init_attr->send_cq || init_attr->cap.max_send_wr) { |
| 838 | + pr_debug("RSS QP with unsupported send attributes\n"); |
| 839 | + return ERR_PTR(-EOPNOTSUPP); |
| 840 | + } |
| 841 | + |
| 842 | + qp = kzalloc(sizeof(*qp), GFP_KERNEL); |
| 843 | + if (!qp) |
| 844 | + return ERR_PTR(-ENOMEM); |
| 845 | + |
| 846 | + qp->pri.vid = 0xFFFF; |
| 847 | + qp->alt.vid = 0xFFFF; |
| 848 | + |
| 849 | + err = create_qp_rss(to_mdev(pd->device), pd, init_attr, &ucmd, qp); |
| 850 | + if (err) { |
| 851 | + kfree(qp); |
| 852 | + return ERR_PTR(err); |
| 853 | + } |
| 854 | + |
| 855 | + qp->ibqp.qp_num = qp->mqp.qpn; |
| 856 | + |
| 857 | + return &qp->ibqp; |
| 858 | +} |
| 859 | + |
| 653 | 860 | /* |
| 654 | 861 | * This function allocates a WQN from a range which is consecutive and aligned |
| 655 | 862 | * to its size. In case the range is full, then it creates a new range and |
| @@ -1186,6 +1393,36 @@ static void get_cqs(struct mlx4_ib_qp *qp, enum mlx4_ib_source_type src, · 530 unmodified lines |
| 1186 | 1393 | } |
| 1187 | 1394 | } |
| 1188 | 1395 | |
| 1396 | +static void destroy_qp_rss(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) |
| 1397 | +{ |
| 1398 | + if (qp->state != IB_QPS_RESET) { |
| 1399 | + int i; |
| 1400 | + |
| 1401 | + for (i = 0; i < (1 << qp->ibqp.rwq_ind_tbl->log_ind_tbl_size); |
| 1402 | + i++) { |
| 1403 | + struct ib_wq *ibwq = qp->ibqp.rwq_ind_tbl->ind_tbl[i]; |
| 1404 | + struct mlx4_ib_qp *wq = to_mqp((struct ib_qp *)ibwq); |
| 1405 | + |
| 1406 | + mutex_lock(&wq->mutex); |
| 1407 | + |
| 1408 | + wq->rss_usecnt--; |
| 1409 | + |
| 1410 | + mutex_unlock(&wq->mutex); |
| 1411 | + } |
| 1412 | + |
| 1413 | + if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), |
| 1414 | + MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp)) |
| 1415 | + pr_warn("modify QP %06x to RESET failed.\n", |
| 1416 | + qp->mqp.qpn); |
| 1417 | + } |
| 1418 | + |
| 1419 | + mlx4_qp_remove(dev->dev, &qp->mqp); |
| 1420 | + mlx4_qp_free(dev->dev, &qp->mqp); |
| 1421 | + mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1); |
| 1422 | + del_gid_entries(qp); |
| 1423 | + kfree(qp->rss_ctx); |
| 1424 | +} |
| 1425 | + |
| 1189 | 1426 | static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, |
| 1190 | 1427 | enum mlx4_ib_source_type src, int is_user) |
| 1191 | 1428 | { |
| @@ -1303,6 +1540,9 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd, · 111 unmodified lines |
| 1303 | 1540 | int sup_u_create_flags = MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK; |
| 1304 | 1541 | u16 xrcdn = 0; |
| 1305 | 1542 | |
| 1543 | + if (init_attr->rwq_ind_tbl) |
| 1544 | + return _mlx4_ib_create_qp_rss(pd, init_attr, udata); |
| 1545 | + |
| 1306 | 1546 | /* |
| 1307 | 1547 | * We only support LSO, vendor flag1, and multicast loopback blocking, |
| 1308 | 1548 | * and only for kernel UD QPs. |
| @@ -1444,7 +1684,6 @@ static int _mlx4_ib_destroy_qp(struct ib_qp *qp) · 135 unmodified lines |
| 1444 | 1684 | { |
| 1445 | 1685 | struct mlx4_ib_dev *dev = to_mdev(qp->device); |
| 1446 | 1686 | struct mlx4_ib_qp *mqp = to_mqp(qp); |
| 1447 | | − struct mlx4_ib_pd *pd; |
| 1448 | 1687 | |
| 1449 | 1688 | if (is_qp0(dev, mqp)) |
| 1450 | 1689 | mlx4_CLOSE_PORT(dev->dev, mqp->port); |
| @@ -1459,8 +1698,14 @@ static int _mlx4_ib_destroy_qp(struct ib_qp *qp) · 8 unmodified lines |
| 1459 | 1698 | if (mqp->counter_index) |
| 1460 | 1699 | mlx4_ib_free_qp_counter(dev, mqp); |
| 1461 | 1700 | |
| 1462 | | − pd = get_pd(mqp); |
| 1463 | | − destroy_qp_common(dev, mqp, MLX4_IB_QP_SRC, !!pd->ibpd.uobject); |
| 1701 | + if (qp->rwq_ind_tbl) { |
| 1702 | + destroy_qp_rss(dev, mqp); |
| 1703 | + } else { |
| 1704 | + struct mlx4_ib_pd *pd; |
| 1705 | + |
| 1706 | + pd = get_pd(mqp); |
| 1707 | + destroy_qp_common(dev, mqp, MLX4_IB_QP_SRC, !!pd->ibpd.uobject); |
| 1708 | + } |
| 1464 | 1709 | |
| 1465 | 1710 | if (is_sqp(dev, mqp)) |
| 1466 | 1711 | kfree(to_msqp(mqp)); |
| @@ -1783,12 +2028,116 @@ static u8 gid_type_to_qpc(enum ib_gid_type gid_type) · 316 unmodified lines |
| 1783 | 2028 | } |
| 1784 | 2029 | } |
| 1785 | 2030 | |
| 2031 | +/* |
| 2032 | + * Go over all RSS QP's childes (WQs) and apply their HW state according to |
| 2033 | + * their logic state if the RSS QP is the first RSS QP associated for the WQ. |
| 2034 | + */ |
| 2035 | +static int bringup_rss_rwqs(struct ib_rwq_ind_table *ind_tbl, u8 port_num) |
| 2036 | +{ |
| 2037 | + int i; |
| 2038 | + int err; |
| 2039 | + |
| 2040 | + for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) { |
| 2041 | + struct ib_wq *ibwq = ind_tbl->ind_tbl[i]; |
| 2042 | + struct mlx4_ib_qp *wq = to_mqp((struct ib_qp *)ibwq); |
| 2043 | + |
| 2044 | + mutex_lock(&wq->mutex); |
| 2045 | + |
| 2046 | + /* Mlx4_ib restrictions: |
| 2047 | + * WQ's is associated to a port according to the RSS QP it is |
| 2048 | + * associates to. |
| 2049 | + * In case the WQ is associated to a different port by another |
| 2050 | + * RSS QP, return a failure. |
| 2051 | + */ |
| 2052 | + if ((wq->rss_usecnt > 0) && (wq->port != port_num)) { |
| 2053 | + err = -EINVAL; |
| 2054 | + mutex_unlock(&wq->mutex); |
| 2055 | + break; |
| 2056 | + } |
| 2057 | + wq->port = port_num; |
| 2058 | + if ((wq->rss_usecnt == 0) && (ibwq->state == IB_WQS_RDY)) { |
| 2059 | + err = _mlx4_ib_modify_wq(ibwq, IB_WQS_RDY); |
| 2060 | + if (err) { |
| 2061 | + mutex_unlock(&wq->mutex); |
| 2062 | + break; |
| 2063 | + } |
| 2064 | + } |
| 2065 | + wq->rss_usecnt++; |
| 2066 | + |
| 2067 | + mutex_unlock(&wq->mutex); |
| 2068 | + } |
| 2069 | + |
| 2070 | + if (i && err) { |
| 2071 | + int j; |
| 2072 | + |
| 2073 | + for (j = (i - 1); j >= 0; j--) { |
| 2074 | + struct ib_wq *ibwq = ind_tbl->ind_tbl[j]; |
| 2075 | + struct mlx4_ib_qp *wq = to_mqp((struct ib_qp *)ibwq); |
| 2076 | + |
| 2077 | + mutex_lock(&wq->mutex); |
| 2078 | + |
| 2079 | + if ((wq->rss_usecnt == 1) && |
| 2080 | + (ibwq->state == IB_WQS_RDY)) |
| 2081 | + if (_mlx4_ib_modify_wq(ibwq, IB_WQS_RESET)) |
| 2082 | + pr_warn("failed to reverse WQN=0x%06x\n", |
| 2083 | + ibwq->wq_num); |
| 2084 | + wq->rss_usecnt--; |
| 2085 | + |
| 2086 | + mutex_unlock(&wq->mutex); |
| 2087 | + } |
| 2088 | + } |
| 2089 | + |
| 2090 | + return err; |
| 2091 | +} |
| 2092 | + |
| 2093 | +static void bring_down_rss_rwqs(struct ib_rwq_ind_table *ind_tbl) |
| 2094 | +{ |
| 2095 | + int i; |
| 2096 | + |
| 2097 | + for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) { |
| 2098 | + struct ib_wq *ibwq = ind_tbl->ind_tbl[i]; |
| 2099 | + struct mlx4_ib_qp *wq = to_mqp((struct ib_qp *)ibwq); |
| 2100 | + |
| 2101 | + mutex_lock(&wq->mutex); |
| 2102 | + |
| 2103 | + if ((wq->rss_usecnt == 1) && (ibwq->state == IB_WQS_RDY)) |
| 2104 | + if (_mlx4_ib_modify_wq(ibwq, IB_WQS_RESET)) |
| 2105 | + pr_warn("failed to reverse WQN=%x\n", |
| 2106 | + ibwq->wq_num); |
| 2107 | + wq->rss_usecnt--; |
| 2108 | + |
| 2109 | + mutex_unlock(&wq->mutex); |
| 2110 | + } |
| 2111 | +} |
| 2112 | + |
| 2113 | +static void fill_qp_rss_context(struct mlx4_qp_context *context, |
| 2114 | + struct mlx4_ib_qp *qp) |
| 2115 | +{ |
| 2116 | + struct mlx4_rss_context *rss_context; |
| 2117 | + |
| 2118 | + rss_context = (void *)context + offsetof(struct mlx4_qp_context, |
| 2119 | + pri_path) + MLX4_RSS_OFFSET_IN_QPC_PRI_PATH; |
| 2120 | + |
| 2121 | + rss_context->base_qpn = cpu_to_be32(qp->rss_ctx->base_qpn_tbl_sz); |
| 2122 | + rss_context->default_qpn = |
| 2123 | + cpu_to_be32(qp->rss_ctx->base_qpn_tbl_sz & 0xffffff); |
| 2124 | + if (qp->rss_ctx->flags & (MLX4_RSS_UDP_IPV4 | MLX4_RSS_UDP_IPV6)) |
| 2125 | + rss_context->base_qpn_udp = rss_context->default_qpn; |
| 2126 | + rss_context->flags = qp->rss_ctx->flags; |
| 2127 | + /* Currently support just toeplitz */ |
| 2128 | + rss_context->hash_fn = MLX4_RSS_HASH_TOP; |
| 2129 | + |
| 2130 | + memcpy(rss_context->rss_key, qp->rss_ctx->rss_key, |
| 2131 | + MLX4_EN_RSS_KEY_SIZE); |
| 2132 | +} |
| 2133 | + |
| 1786 | 2134 | static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, |
| 1787 | 2135 | const struct ib_qp_attr *attr, int attr_mask, |
| 1788 | 2136 | enum ib_qp_state cur_state, enum ib_qp_state new_state) |
| 1789 | 2137 | { |
| 1790 | 2138 | struct ib_uobject *ibuobject; |
| 1791 | 2139 | struct ib_srq *ibsrq; |
| 2140 | + struct ib_rwq_ind_table *rwq_ind_tbl; |
| 1792 | 2141 | enum ib_qp_type qp_type; |
| 1793 | 2142 | struct mlx4_ib_dev *dev; |
| 1794 | 2143 | struct mlx4_ib_qp *qp; |
| @@ -1804,23 +2153,25 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, · 9 unmodified lines |
| 1804 | 2153 | if (src_type == MLX4_IB_RWQ_SRC) { |
| 1805 | 2154 | struct ib_wq *ibwq; |
| 1806 | 2155 | |
| 1807 | | − ibwq = (struct ib_wq *)src; |
| 1808 | | − ibuobject = ibwq->uobject; |
| 1809 | | − ibsrq = NULL; |
| 1810 | | − qp_type = IB_QPT_RAW_PACKET; |
| 1811 | | − qp = to_mqp((struct ib_qp *)ibwq); |
| 1812 | | − dev = to_mdev(ibwq->device); |
| 1813 | | − pd = to_mpd(ibwq->pd); |
| 2156 | + ibwq = (struct ib_wq *)src; |
| 2157 | + ibuobject = ibwq->uobject; |
| 2158 | + ibsrq = NULL; |
| 2159 | + rwq_ind_tbl = NULL; |
| 2160 | + qp_type = IB_QPT_RAW_PACKET; |
| 2161 | + qp = to_mqp((struct ib_qp *)ibwq); |
| 2162 | + dev = to_mdev(ibwq->device); |
| 2163 | + pd = to_mpd(ibwq->pd); |
| 1814 | 2164 | } else { |
| 1815 | 2165 | struct ib_qp *ibqp; |
| 1816 | 2166 | |
| 1817 | | − ibqp = (struct ib_qp *)src; |
| 1818 | | − ibuobject = ibqp->uobject; |
| 1819 | | − ibsrq = ibqp->srq; |
| 1820 | | − qp_type = ibqp->qp_type; |
| 1821 | | − qp = to_mqp(ibqp); |
| 1822 | | − dev = to_mdev(ibqp->device); |
| 1823 | | − pd = get_pd(qp); |
| 2167 | + ibqp = (struct ib_qp *)src; |
| 2168 | + ibuobject = ibqp->uobject; |
| 2169 | + ibsrq = ibqp->srq; |
| 2170 | + rwq_ind_tbl = ibqp->rwq_ind_tbl; |
| 2171 | + qp_type = ibqp->qp_type; |
| 2172 | + qp = to_mqp(ibqp); |
| 2173 | + dev = to_mdev(ibqp->device); |
| 2174 | + pd = get_pd(qp); |
| 1824 | 2175 | } |
| 1825 | 2176 | |
| 1826 | 2177 | /* APM is not supported under RoCE */ |
| @@ -1836,6 +2187,11 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, · 9 unmodified lines |
| 1836 | 2187 | context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) | |
| 1837 | 2188 | (to_mlx4_st(dev, qp->mlx4_ib_qp_type) << 16)); |
| 1838 | 2189 | |
| 2190 | + if (rwq_ind_tbl) { |
| 2191 | + fill_qp_rss_context(context, qp); |
| 2192 | + context->flags |= cpu_to_be32(1 << MLX4_RSS_QPC_FLAG_OFFSET); |
| 2193 | + } |
| 2194 | + |
| 1839 | 2195 | if (!(attr_mask & IB_QP_PATH_MIG_STATE)) |
| 1840 | 2196 | context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); |
| 1841 | 2197 | else { |
| @@ -1876,9 +2232,11 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, · 34 unmodified lines |
| 1876 | 2232 | ilog2(dev->dev->caps.max_msg_sz); |
| 1877 | 2233 | } |
| 1878 | 2234 | |
| 1879 | | − if (qp->rq.wqe_cnt) |
| 1880 | | − context->rq_size_stride = ilog2(qp->rq.wqe_cnt) << 3; |
| 1881 | | − context->rq_size_stride |= qp->rq.wqe_shift - 4; |
| 2235 | + if (!rwq_ind_tbl) { /* PRM RSS receive side should be left zeros */ |
| 2236 | + if (qp->rq.wqe_cnt) |
| 2237 | + context->rq_size_stride = ilog2(qp->rq.wqe_cnt) << 3; |
| 2238 | + context->rq_size_stride |= qp->rq.wqe_shift - 4; |
| 2239 | + } |
| 1882 | 2240 | |
| 1883 | 2241 | if (qp->sq.wqe_cnt) |
| 1884 | 2242 | context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3; |
| @@ -2031,8 +2389,14 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, · 146 unmodified lines |
| 2031 | 2389 | optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH; |
| 2032 | 2390 | } |
| 2033 | 2391 | |
| 2034 | | − get_cqs(qp, src_type, &send_cq, &recv_cq); |
| 2035 | | − context->pd = cpu_to_be32(pd->pdn); |
| 2392 | + context->pd = cpu_to_be32(pd->pdn); |
| 2393 | + |
| 2394 | + if (!rwq_ind_tbl) { |
| 2395 | + get_cqs(qp, src_type, &send_cq, &recv_cq); |
| 2396 | + } else { /* Set dummy CQs to be compatible with HV and PRM */ |
| 2397 | + send_cq = to_mcq(rwq_ind_tbl->ind_tbl[0]->cq); |
| 2398 | + recv_cq = send_cq; |
| 2399 | + } |
| 2036 | 2400 | context->cqn_send = cpu_to_be32(send_cq->mcq.cqn); |
| 2037 | 2401 | context->cqn_recv = cpu_to_be32(recv_cq->mcq.cqn); |
| 2038 | 2402 | context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28); |
| @@ -2358,6 +2722,11 @@ out: · 319 unmodified lines |
| 2358 | 2722 | return err; |
| 2359 | 2723 | } |
| 2360 | 2724 | |
| 2725 | +enum { |
| 2726 | + MLX4_IB_MODIFY_QP_RSS_SUP_ATTR_MSK = (IB_QP_STATE | |
| 2727 | + IB_QP_PORT), |
| 2728 | +}; |
| 2729 | + |
| 2361 | 2730 | static int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, |
| 2362 | 2731 | int attr_mask, struct ib_udata *udata) |
| 2363 | 2732 | { |
| @@ -2388,6 +2757,27 @@ static int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, · 24 unmodified lines |
| 2388 | 2757 | goto out; |
| 2389 | 2758 | } |
| 2390 | 2759 | |
| 2760 | + if (ibqp->rwq_ind_tbl) { |
| 2761 | + if (!(((cur_state == IB_QPS_RESET) && |
| 2762 | + (new_state == IB_QPS_INIT)) || |
| 2763 | + ((cur_state == IB_QPS_INIT) && |
| 2764 | + (new_state == IB_QPS_RTR)))) { |
| 2765 | + pr_debug("qpn 0x%x: RSS QP unsupported transition %d to %d\n", |
| 2766 | + ibqp->qp_num, cur_state, new_state); |
| 2767 | + |
| 2768 | + err = -EOPNOTSUPP; |
| 2769 | + goto out; |
| 2770 | + } |
| 2771 | + |
| 2772 | + if (attr_mask & ~MLX4_IB_MODIFY_QP_RSS_SUP_ATTR_MSK) { |
| 2773 | + pr_debug("qpn 0x%x: RSS QP unsupported attribute mask 0x%x for transition %d to %d\n", |
| 2774 | + ibqp->qp_num, attr_mask, cur_state, new_state); |
| 2775 | + |
| 2776 | + err = -EOPNOTSUPP; |
| 2777 | + goto out; |
| 2778 | + } |
| 2779 | + } |
| 2780 | + |
| 2391 | 2781 | if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT)) { |
| 2392 | 2782 | if ((cur_state == IB_QPS_RESET) && (new_state == IB_QPS_INIT)) { |
| 2393 | 2783 | if ((ibqp->qp_type == IB_QPT_RC) || |
| @@ -2452,9 +2842,18 @@ static int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, · 58 unmodified lines |
| 2452 | 2842 | goto out; |
| 2453 | 2843 | } |
| 2454 | 2844 | |
| 2845 | + if (ibqp->rwq_ind_tbl && (new_state == IB_QPS_INIT)) { |
| 2846 | + err = bringup_rss_rwqs(ibqp->rwq_ind_tbl, attr->port_num); |
| 2847 | + if (err) |
| 2848 | + goto out; |
| 2849 | + } |
| 2850 | + |
| 2455 | 2851 | err = __mlx4_ib_modify_qp(ibqp, MLX4_IB_QP_SRC, attr, attr_mask, |
| 2456 | 2852 | cur_state, new_state); |
| 2457 | 2853 | |
| 2854 | + if (ibqp->rwq_ind_tbl && err) |
| 2855 | + bring_down_rss_rwqs(ibqp->rwq_ind_tbl); |
| 2856 | + |
| 2458 | 2857 | if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT)) |
| 2459 | 2858 | attr->port_num = 1; |
| 2460 | 2859 | |
| @@ -3643,6 +4042,9 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr · 1182 unmodified lines |
| 3643 | 4042 | int mlx4_state; |
| 3644 | 4043 | int err = 0; |
| 3645 | 4044 | |
| 4045 | + if (ibqp->rwq_ind_tbl) |
| 4046 | + return -EOPNOTSUPP; |
| 4047 | + |
| 3646 | 4048 | mutex_lock(&qp->mutex); |
| 3647 | 4049 | |
| 3648 | 4050 | if (qp->state == IB_QPS_RESET) { |
| @@ -3917,6 +4319,11 @@ int mlx4_ib_modify_wq(struct ib_wq *ibwq, struct ib_wq_attr *wq_attr, · 268 unmodified lines |
| 3917 | 4319 | if ((new_state == IB_WQS_ERR) && (cur_state == IB_WQS_RESET)) |
| 3918 | 4320 | return -EINVAL; |
| 3919 | 4321 | |
| 4322 | + /* Need to protect against the parent RSS which also may modify WQ |
| 4323 | + * state. |
| 4324 | + */ |
| 4325 | + mutex_lock(&qp->mutex); |
| 4326 | + |
| 3920 | 4327 | /* Can update HW state only if a RSS QP has already associated to this |
| 3921 | 4328 | * WQ, so we can apply its port on the WQ. |
| 3922 | 4329 | */ |
| @@ -3926,6 +4333,8 @@ int mlx4_ib_modify_wq(struct ib_wq *ibwq, struct ib_wq_attr *wq_attr, · 3 unmodified lines |
| 3926 | 4333 | if (!err) |
| 3927 | 4334 | ibwq->state = new_state; |
| 3928 | 4335 | |
| 4336 | + mutex_unlock(&qp->mutex); |
| 4337 | + |
| 3929 | 4338 | return err; |
| 3930 | 4339 | } |
| 3931 | 4340 | |