OSDN Git Service

IB/core: Use GID table in AH creation and dmac resolution
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / infiniband / core / verbs.c
index 6012f5e..46d97f0 100644 (file)
@@ -41,6 +41,9 @@
 #include <linux/export.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <net/addrconf.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_cache.h>
@@ -308,6 +311,35 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
 }
 EXPORT_SYMBOL(ib_create_ah);
 
+struct find_gid_index_context {
+       u16 vlan_id;
+};
+
+static bool find_gid_index(const union ib_gid *gid,
+                          const struct ib_gid_attr *gid_attr,
+                          void *context)
+{
+       struct find_gid_index_context *ctx =
+               (struct find_gid_index_context *)context;
+
+       if ((!!(ctx->vlan_id != 0xffff) == !is_vlan_dev(gid_attr->ndev)) ||
+           (is_vlan_dev(gid_attr->ndev) &&
+            vlan_dev_vlan_id(gid_attr->ndev) != ctx->vlan_id))
+               return false;
+
+       return true;
+}
+
+static int get_sgid_index_from_eth(struct ib_device *device, u8 port_num,
+                                  u16 vlan_id, const union ib_gid *sgid,
+                                  u16 *gid_index)
+{
+       struct find_gid_index_context context = {.vlan_id = vlan_id};
+
+       return ib_find_gid_by_filter(device, sgid, port_num, find_gid_index,
+                                    &context, gid_index);
+}
+
 int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
                       const struct ib_wc *wc, const struct ib_grh *grh,
                       struct ib_ah_attr *ah_attr)
@@ -318,21 +350,30 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
 
        memset(ah_attr, 0, sizeof *ah_attr);
        if (rdma_cap_eth_ah(device, port_num)) {
+               u16 vlan_id = wc->wc_flags & IB_WC_WITH_VLAN ?
+                               wc->vlan_id : 0xffff;
+
                if (!(wc->wc_flags & IB_WC_GRH))
                        return -EPROTOTYPE;
 
-               if (wc->wc_flags & IB_WC_WITH_SMAC &&
-                   wc->wc_flags & IB_WC_WITH_VLAN) {
-                       memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
-                       ah_attr->vlan_id = wc->vlan_id;
-               } else {
+               if (!(wc->wc_flags & IB_WC_WITH_SMAC) ||
+                   !(wc->wc_flags & IB_WC_WITH_VLAN)) {
                        ret = rdma_addr_find_dmac_by_grh(&grh->dgid, &grh->sgid,
-                                       ah_attr->dmac, &ah_attr->vlan_id);
+                                                        ah_attr->dmac,
+                                                        wc->wc_flags & IB_WC_WITH_VLAN ?
+                                                        NULL : &vlan_id,
+                                                        0);
                        if (ret)
                                return ret;
                }
-       } else {
-               ah_attr->vlan_id = 0xffff;
+
+               ret = get_sgid_index_from_eth(device, port_num, vlan_id,
+                                             &grh->dgid, &gid_index);
+               if (ret)
+                       return ret;
+
+               if (wc->wc_flags & IB_WC_WITH_SMAC)
+                       memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
        }
 
        ah_attr->dlid = wc->slid;
@@ -344,10 +385,13 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
                ah_attr->ah_flags = IB_AH_GRH;
                ah_attr->grh.dgid = grh->sgid;
 
-               ret = ib_find_cached_gid(device, &grh->dgid,
-                                        NULL, &port_num, &gid_index);
-               if (ret)
-                       return ret;
+               if (!rdma_cap_eth_ah(device, port_num)) {
+                       ret = ib_find_cached_gid_by_port(device, &grh->dgid,
+                                                        port_num, NULL,
+                                                        &gid_index);
+                       if (ret)
+                               return ret;
+               }
 
                ah_attr->grh.sgid_index = (u8) gid_index;
                flow_class = be32_to_cpu(grh->version_tclass_flow);
@@ -617,9 +661,7 @@ EXPORT_SYMBOL(ib_create_qp);
 static const struct {
        int                     valid;
        enum ib_qp_attr_mask    req_param[IB_QPT_MAX];
-       enum ib_qp_attr_mask    req_param_add_eth[IB_QPT_MAX];
        enum ib_qp_attr_mask    opt_param[IB_QPT_MAX];
-       enum ib_qp_attr_mask    opt_param_add_eth[IB_QPT_MAX];
 } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
        [IB_QPS_RESET] = {
                [IB_QPS_RESET] = { .valid = 1 },
@@ -700,12 +742,6 @@ static const struct {
                                                IB_QP_MAX_DEST_RD_ATOMIC        |
                                                IB_QP_MIN_RNR_TIMER),
                        },
-                       .req_param_add_eth = {
-                               [IB_QPT_RC]  = (IB_QP_SMAC),
-                               [IB_QPT_UC]  = (IB_QP_SMAC),
-                               [IB_QPT_XRC_INI]  = (IB_QP_SMAC),
-                               [IB_QPT_XRC_TGT]  = (IB_QP_SMAC)
-                       },
                        .opt_param = {
                                 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX               |
                                                 IB_QP_QKEY),
@@ -726,21 +762,7 @@ static const struct {
                                 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX               |
                                                 IB_QP_QKEY),
                         },
-                       .opt_param_add_eth = {
-                               [IB_QPT_RC]  = (IB_QP_ALT_SMAC                  |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID),
-                               [IB_QPT_UC]  = (IB_QP_ALT_SMAC                  |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID),
-                               [IB_QPT_XRC_INI]  = (IB_QP_ALT_SMAC                     |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID),
-                               [IB_QPT_XRC_TGT]  = (IB_QP_ALT_SMAC                     |
-                                               IB_QP_VID                       |
-                                               IB_QP_ALT_VID)
-                       }
-               }
+               },
        },
        [IB_QPS_RTR]   = {
                [IB_QPS_RESET] = { .valid = 1 },
@@ -962,13 +984,6 @@ int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
        req_param = qp_state_table[cur_state][next_state].req_param[type];
        opt_param = qp_state_table[cur_state][next_state].opt_param[type];
 
-       if (ll == IB_LINK_LAYER_ETHERNET) {
-               req_param |= qp_state_table[cur_state][next_state].
-                       req_param_add_eth[type];
-               opt_param |= qp_state_table[cur_state][next_state].
-                       opt_param_add_eth[type];
-       }
-
        if ((mask & req_param) != req_param)
                return 0;
 
@@ -979,41 +994,52 @@ int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
 }
 EXPORT_SYMBOL(ib_modify_qp_is_ok);
 
-int ib_resolve_eth_l2_attrs(struct ib_qp *qp,
-                           struct ib_qp_attr *qp_attr, int *qp_attr_mask)
+int ib_resolve_eth_dmac(struct ib_qp *qp,
+                       struct ib_qp_attr *qp_attr, int *qp_attr_mask)
 {
        int           ret = 0;
-       union ib_gid  sgid;
 
-       if ((*qp_attr_mask & IB_QP_AV)  &&
-           (rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num))) {
-               ret = ib_query_gid(qp->device, qp_attr->ah_attr.port_num,
-                                  qp_attr->ah_attr.grh.sgid_index, &sgid,
-                                  NULL);
-               if (ret)
-                       goto out;
+       if (*qp_attr_mask & IB_QP_AV) {
+               if (qp_attr->ah_attr.port_num < rdma_start_port(qp->device) ||
+                   qp_attr->ah_attr.port_num > rdma_end_port(qp->device))
+                       return -EINVAL;
+
+               if (!rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num))
+                       return 0;
+
                if (rdma_link_local_addr((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw)) {
-                       rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw, qp_attr->ah_attr.dmac);
-                       rdma_get_ll_mac((struct in6_addr *)sgid.raw, qp_attr->smac);
-                       if (!(*qp_attr_mask & IB_QP_VID))
-                               qp_attr->vlan_id = rdma_get_vlan_id(&sgid);
+                       rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw,
+                                       qp_attr->ah_attr.dmac);
                } else {
-                       ret = rdma_addr_find_dmac_by_grh(&sgid, &qp_attr->ah_attr.grh.dgid,
-                                       qp_attr->ah_attr.dmac, &qp_attr->vlan_id);
-                       if (ret)
-                               goto out;
-                       ret = rdma_addr_find_smac_by_sgid(&sgid, qp_attr->smac, NULL);
-                       if (ret)
+                       union ib_gid            sgid;
+                       struct ib_gid_attr      sgid_attr;
+                       int                     ifindex;
+
+                       ret = ib_query_gid(qp->device,
+                                          qp_attr->ah_attr.port_num,
+                                          qp_attr->ah_attr.grh.sgid_index,
+                                          &sgid, &sgid_attr);
+
+                       if (ret || !sgid_attr.ndev) {
+                               if (!ret)
+                                       ret = -ENXIO;
                                goto out;
+                       }
+
+                       ifindex = sgid_attr.ndev->ifindex;
+
+                       ret = rdma_addr_find_dmac_by_grh(&sgid,
+                                                        &qp_attr->ah_attr.grh.dgid,
+                                                        qp_attr->ah_attr.dmac,
+                                                        NULL, ifindex);
+
+                       dev_put(sgid_attr.ndev);
                }
-               *qp_attr_mask |= IB_QP_SMAC;
-               if (qp_attr->vlan_id < 0xFFFF)
-                       *qp_attr_mask |= IB_QP_VID;
        }
 out:
        return ret;
 }
-EXPORT_SYMBOL(ib_resolve_eth_l2_attrs);
+EXPORT_SYMBOL(ib_resolve_eth_dmac);
 
 
 int ib_modify_qp(struct ib_qp *qp,
@@ -1022,7 +1048,7 @@ int ib_modify_qp(struct ib_qp *qp,
 {
        int ret;
 
-       ret = ib_resolve_eth_l2_attrs(qp, qp_attr, &qp_attr_mask);
+       ret = ib_resolve_eth_dmac(qp, qp_attr, &qp_attr_mask);
        if (ret)
                return ret;