RDMA/core: Get xmit slave for LAG
authorMaor Gottlieb <maorg@mellanox.com>
Thu, 30 Apr 2020 19:21:44 +0000 (22:21 +0300)
committerJason Gunthorpe <jgg@mellanox.com>
Sat, 2 May 2020 23:19:54 +0000 (20:19 -0300)
Add a call to rdma_lag_get_ah_roce_slave() when the address handle is
created. Lower driver can use it to select the QP's affinity port.

Link: https://lore.kernel.org/r/20200430192146.12863-15-maorg@mellanox.com
Signed-off-by: Maor Gottlieb <maorg@mellanox.com>
Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/core/verbs.c
include/rdma/ib_verbs.h

index 86be8a5..bf0249f 100644 (file)
@@ -50,6 +50,7 @@
 #include <rdma/ib_cache.h>
 #include <rdma/ib_addr.h>
 #include <rdma/rw.h>
+#include <rdma/lag.h>
 
 #include "core_priv.h"
 #include <trace/events/rdma_core.h>
@@ -500,7 +501,8 @@ rdma_update_sgid_attr(struct rdma_ah_attr *ah_attr,
 static struct ib_ah *_rdma_create_ah(struct ib_pd *pd,
                                     struct rdma_ah_attr *ah_attr,
                                     u32 flags,
-                                    struct ib_udata *udata)
+                                    struct ib_udata *udata,
+                                    struct net_device *xmit_slave)
 {
        struct rdma_ah_init_attr init_attr = {};
        struct ib_device *device = pd->device;
@@ -524,6 +526,7 @@ static struct ib_ah *_rdma_create_ah(struct ib_pd *pd,
        ah->sgid_attr = rdma_update_sgid_attr(ah_attr, NULL);
        init_attr.ah_attr = ah_attr;
        init_attr.flags = flags;
+       init_attr.xmit_slave = xmit_slave;
 
        ret = device->ops.create_ah(ah, &init_attr, udata);
        if (ret) {
@@ -550,15 +553,22 @@ struct ib_ah *rdma_create_ah(struct ib_pd *pd, struct rdma_ah_attr *ah_attr,
                             u32 flags)
 {
        const struct ib_gid_attr *old_sgid_attr;
+       struct net_device *slave;
        struct ib_ah *ah;
        int ret;
 
        ret = rdma_fill_sgid_attr(pd->device, ah_attr, &old_sgid_attr);
        if (ret)
                return ERR_PTR(ret);
-
-       ah = _rdma_create_ah(pd, ah_attr, flags, NULL);
-
+       slave = rdma_lag_get_ah_roce_slave(pd->device, ah_attr,
+                                          (flags & RDMA_CREATE_AH_SLEEPABLE) ?
+                                          GFP_KERNEL : GFP_ATOMIC);
+       if (IS_ERR(slave)) {
+               rdma_unfill_sgid_attr(ah_attr, old_sgid_attr);
+               return (void *)slave;
+       }
+       ah = _rdma_create_ah(pd, ah_attr, flags, NULL, slave);
+       rdma_lag_put_ah_roce_slave(slave);
        rdma_unfill_sgid_attr(ah_attr, old_sgid_attr);
        return ah;
 }
@@ -597,7 +607,8 @@ struct ib_ah *rdma_create_user_ah(struct ib_pd *pd,
                }
        }
 
-       ah = _rdma_create_ah(pd, ah_attr, RDMA_CREATE_AH_SLEEPABLE, udata);
+       ah = _rdma_create_ah(pd, ah_attr, RDMA_CREATE_AH_SLEEPABLE,
+                            udata, NULL);
 
 out:
        rdma_unfill_sgid_attr(ah_attr, old_sgid_attr);
@@ -1636,11 +1647,35 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
        const struct ib_gid_attr *old_sgid_attr_alt_av;
        int ret;
 
+       attr->xmit_slave = NULL;
        if (attr_mask & IB_QP_AV) {
                ret = rdma_fill_sgid_attr(qp->device, &attr->ah_attr,
                                          &old_sgid_attr_av);
                if (ret)
                        return ret;
+
+               if (attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE &&
+                   is_qp_type_connected(qp)) {
+                       struct net_device *slave;
+
+                       /*
+                        * If the user provided the qp_attr then we have to
+                        * resolve it. Kerne users have to provide already
+                        * resolved rdma_ah_attr's.
+                        */
+                       if (udata) {
+                               ret = ib_resolve_eth_dmac(qp->device,
+                                                         &attr->ah_attr);
+                               if (ret)
+                                       goto out_av;
+                       }
+                       slave = rdma_lag_get_ah_roce_slave(qp->device,
+                                                          &attr->ah_attr,
+                                                          GFP_KERNEL);
+                       if (IS_ERR(slave))
+                               goto out_av;
+                       attr->xmit_slave = slave;
+               }
        }
        if (attr_mask & IB_QP_ALT_PATH) {
                /*
@@ -1667,18 +1702,6 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
                }
        }
 
-       /*
-        * If the user provided the qp_attr then we have to resolve it. Kernel
-        * users have to provide already resolved rdma_ah_attr's
-        */
-       if (udata && (attr_mask & IB_QP_AV) &&
-           attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE &&
-           is_qp_type_connected(qp)) {
-               ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr);
-               if (ret)
-                       goto out;
-       }
-
        if (rdma_ib_or_roce(qp->device, port)) {
                if (attr_mask & IB_QP_RQ_PSN && attr->rq_psn & ~0xffffff) {
                        dev_warn(&qp->device->dev,
@@ -1720,8 +1743,10 @@ out:
        if (attr_mask & IB_QP_ALT_PATH)
                rdma_unfill_sgid_attr(&attr->alt_ah_attr, old_sgid_attr_alt_av);
 out_av:
-       if (attr_mask & IB_QP_AV)
+       if (attr_mask & IB_QP_AV) {
+               rdma_lag_put_ah_roce_slave(attr->xmit_slave);
                rdma_unfill_sgid_attr(&attr->ah_attr, old_sgid_attr_av);
+       }
        return ret;
 }
 
index e6c18ec..8d29f2f 100644 (file)
@@ -883,6 +883,7 @@ __attribute_const__ enum ib_rate mult_to_ib_rate(int mult);
 struct rdma_ah_init_attr {
        struct rdma_ah_attr *ah_attr;
        u32 flags;
+       struct net_device *xmit_slave;
 };
 
 enum rdma_ah_attr_type {
@@ -1272,6 +1273,7 @@ struct ib_qp_attr {
        u8                      alt_port_num;
        u8                      alt_timeout;
        u32                     rate_limit;
+       struct net_device       *xmit_slave;
 };
 
 enum ib_wr_opcode {