mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
IB/mlx4: Add support for IBoE
Add support for IBoE to mlx4_ib. The bulk of the code is handling the new address vector fields; mlx4 needs the MAC address of a remote node to include it in a WQE (for datagrams) or in the QP context (for connected QPs). Address resolution is done by assuming all unicast GIDs are either link-local IPv6 addresses. Multicast group attach/detach needs to update the NIC's multicast filters; but since attaching a QP to a multicast group can be done before the QP is bound to a port, for IBoE we need to keep track of all multicast groups that a QP is attached too before it transitions from INIT to RTR (since it does not have a port in the INIT state). Signed-off-by: Eli Cohen <eli@mellanox.co.il> [ Many things cleaned up and otherwise monkeyed with; hope I didn't introduce too many bugs. - Roland ] Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
@@ -30,66 +30,153 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <rdma/ib_addr.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "mlx4_ib.h"
|
||||
|
||||
struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
|
||||
int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr,
|
||||
u8 *mac, int *is_mcast, u8 port)
|
||||
{
|
||||
struct in6_addr in6;
|
||||
|
||||
*is_mcast = 0;
|
||||
|
||||
memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6);
|
||||
if (rdma_link_local_addr(&in6))
|
||||
rdma_get_ll_mac(&in6, mac);
|
||||
else if (rdma_is_multicast_addr(&in6)) {
|
||||
rdma_get_mcast_mac(&in6, mac);
|
||||
*is_mcast = 1;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
|
||||
struct mlx4_ib_ah *ah)
|
||||
{
|
||||
struct mlx4_dev *dev = to_mdev(pd->device)->dev;
|
||||
struct mlx4_ib_ah *ah;
|
||||
|
||||
ah = kmalloc(sizeof *ah, GFP_ATOMIC);
|
||||
ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
|
||||
ah->av.ib.g_slid = ah_attr->src_path_bits;
|
||||
if (ah_attr->ah_flags & IB_AH_GRH) {
|
||||
ah->av.ib.g_slid |= 0x80;
|
||||
ah->av.ib.gid_index = ah_attr->grh.sgid_index;
|
||||
ah->av.ib.hop_limit = ah_attr->grh.hop_limit;
|
||||
ah->av.ib.sl_tclass_flowlabel |=
|
||||
cpu_to_be32((ah_attr->grh.traffic_class << 20) |
|
||||
ah_attr->grh.flow_label);
|
||||
memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16);
|
||||
}
|
||||
|
||||
ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid);
|
||||
if (ah_attr->static_rate) {
|
||||
ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
|
||||
while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
|
||||
!(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support))
|
||||
--ah->av.ib.stat_rate;
|
||||
}
|
||||
ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
|
||||
|
||||
return &ah->ibah;
|
||||
}
|
||||
|
||||
static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
|
||||
struct mlx4_ib_ah *ah)
|
||||
{
|
||||
struct mlx4_ib_dev *ibdev = to_mdev(pd->device);
|
||||
struct mlx4_dev *dev = ibdev->dev;
|
||||
u8 mac[6];
|
||||
int err;
|
||||
int is_mcast;
|
||||
|
||||
err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
memcpy(ah->av.eth.mac, mac, 6);
|
||||
ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
|
||||
ah->av.eth.gid_index = ah_attr->grh.sgid_index;
|
||||
if (ah_attr->static_rate) {
|
||||
ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
|
||||
while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
|
||||
!(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
|
||||
--ah->av.eth.stat_rate;
|
||||
}
|
||||
|
||||
/*
|
||||
* HW requires multicast LID so we just choose one.
|
||||
*/
|
||||
if (is_mcast)
|
||||
ah->av.ib.dlid = cpu_to_be16(0xc000);
|
||||
|
||||
memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16);
|
||||
ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
|
||||
|
||||
return &ah->ibah;
|
||||
}
|
||||
|
||||
struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
|
||||
{
|
||||
struct mlx4_ib_ah *ah;
|
||||
struct ib_ah *ret;
|
||||
|
||||
ah = kzalloc(sizeof *ah, GFP_ATOMIC);
|
||||
if (!ah)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memset(&ah->av, 0, sizeof ah->av);
|
||||
if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) {
|
||||
if (!(ah_attr->ah_flags & IB_AH_GRH)) {
|
||||
ret = ERR_PTR(-EINVAL);
|
||||
} else {
|
||||
/*
|
||||
* TBD: need to handle the case when we get
|
||||
* called in an atomic context and there we
|
||||
* might sleep. We don't expect this
|
||||
* currently since we're working with link
|
||||
* local addresses which we can translate
|
||||
* without going to sleep.
|
||||
*/
|
||||
ret = create_iboe_ah(pd, ah_attr, ah);
|
||||
}
|
||||
|
||||
ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
|
||||
ah->av.g_slid = ah_attr->src_path_bits;
|
||||
ah->av.dlid = cpu_to_be16(ah_attr->dlid);
|
||||
if (ah_attr->static_rate) {
|
||||
ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
|
||||
while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
|
||||
!(1 << ah->av.stat_rate & dev->caps.stat_rate_support))
|
||||
--ah->av.stat_rate;
|
||||
}
|
||||
ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
|
||||
if (ah_attr->ah_flags & IB_AH_GRH) {
|
||||
ah->av.g_slid |= 0x80;
|
||||
ah->av.gid_index = ah_attr->grh.sgid_index;
|
||||
ah->av.hop_limit = ah_attr->grh.hop_limit;
|
||||
ah->av.sl_tclass_flowlabel |=
|
||||
cpu_to_be32((ah_attr->grh.traffic_class << 20) |
|
||||
ah_attr->grh.flow_label);
|
||||
memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16);
|
||||
}
|
||||
if (IS_ERR(ret))
|
||||
kfree(ah);
|
||||
|
||||
return &ah->ibah;
|
||||
return ret;
|
||||
} else
|
||||
return create_ib_ah(pd, ah_attr, ah); /* never fails */
|
||||
}
|
||||
|
||||
int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
|
||||
{
|
||||
struct mlx4_ib_ah *ah = to_mah(ibah);
|
||||
enum rdma_link_layer ll;
|
||||
|
||||
memset(ah_attr, 0, sizeof *ah_attr);
|
||||
ah_attr->dlid = be16_to_cpu(ah->av.dlid);
|
||||
ah_attr->sl = be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
|
||||
ah_attr->port_num = be32_to_cpu(ah->av.port_pd) >> 24;
|
||||
if (ah->av.stat_rate)
|
||||
ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET;
|
||||
ah_attr->src_path_bits = ah->av.g_slid & 0x7F;
|
||||
ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
|
||||
ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24;
|
||||
ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num);
|
||||
ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0;
|
||||
if (ah->av.ib.stat_rate)
|
||||
ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET;
|
||||
ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F;
|
||||
|
||||
if (mlx4_ib_ah_grh_present(ah)) {
|
||||
ah_attr->ah_flags = IB_AH_GRH;
|
||||
|
||||
ah_attr->grh.traffic_class =
|
||||
be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20;
|
||||
be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20;
|
||||
ah_attr->grh.flow_label =
|
||||
be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff;
|
||||
ah_attr->grh.hop_limit = ah->av.hop_limit;
|
||||
ah_attr->grh.sgid_index = ah->av.gid_index;
|
||||
memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, 16);
|
||||
be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff;
|
||||
ah_attr->grh.hop_limit = ah->av.ib.hop_limit;
|
||||
ah_attr->grh.sgid_index = ah->av.ib.gid_index;
|
||||
memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -311,19 +311,25 @@ int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
|
||||
struct ib_mad_agent *agent;
|
||||
int p, q;
|
||||
int ret;
|
||||
enum rdma_link_layer ll;
|
||||
|
||||
for (p = 0; p < dev->num_ports; ++p)
|
||||
for (p = 0; p < dev->num_ports; ++p) {
|
||||
ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1);
|
||||
for (q = 0; q <= 1; ++q) {
|
||||
agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
|
||||
q ? IB_QPT_GSI : IB_QPT_SMI,
|
||||
NULL, 0, send_handler,
|
||||
NULL, NULL);
|
||||
if (IS_ERR(agent)) {
|
||||
ret = PTR_ERR(agent);
|
||||
goto err;
|
||||
}
|
||||
dev->send_agent[p][q] = agent;
|
||||
if (ll == IB_LINK_LAYER_INFINIBAND) {
|
||||
agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
|
||||
q ? IB_QPT_GSI : IB_QPT_SMI,
|
||||
NULL, 0, send_handler,
|
||||
NULL, NULL);
|
||||
if (IS_ERR(agent)) {
|
||||
ret = PTR_ERR(agent);
|
||||
goto err;
|
||||
}
|
||||
dev->send_agent[p][q] = agent;
|
||||
} else
|
||||
dev->send_agent[p][q] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -344,8 +350,10 @@ void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
|
||||
for (p = 0; p < dev->num_ports; ++p) {
|
||||
for (q = 0; q <= 1; ++q) {
|
||||
agent = dev->send_agent[p][q];
|
||||
dev->send_agent[p][q] = NULL;
|
||||
ib_unregister_mad_agent(agent);
|
||||
if (agent) {
|
||||
dev->send_agent[p][q] = NULL;
|
||||
ib_unregister_mad_agent(agent);
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->sm_ah[p])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -112,6 +112,13 @@ enum mlx4_ib_qp_flags {
|
||||
MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = 1 << 1,
|
||||
};
|
||||
|
||||
struct mlx4_ib_gid_entry {
|
||||
struct list_head list;
|
||||
union ib_gid gid;
|
||||
int added;
|
||||
u8 port;
|
||||
};
|
||||
|
||||
struct mlx4_ib_qp {
|
||||
struct ib_qp ibqp;
|
||||
struct mlx4_qp mqp;
|
||||
@@ -138,6 +145,8 @@ struct mlx4_ib_qp {
|
||||
u8 resp_depth;
|
||||
u8 sq_no_prefetch;
|
||||
u8 state;
|
||||
int mlx_type;
|
||||
struct list_head gid_list;
|
||||
};
|
||||
|
||||
struct mlx4_ib_srq {
|
||||
@@ -157,7 +166,14 @@ struct mlx4_ib_srq {
|
||||
|
||||
struct mlx4_ib_ah {
|
||||
struct ib_ah ibah;
|
||||
struct mlx4_av av;
|
||||
union mlx4_ext_av av;
|
||||
};
|
||||
|
||||
struct mlx4_ib_iboe {
|
||||
spinlock_t lock;
|
||||
struct net_device *netdevs[MLX4_MAX_PORTS];
|
||||
struct notifier_block nb;
|
||||
union ib_gid gid_table[MLX4_MAX_PORTS][128];
|
||||
};
|
||||
|
||||
struct mlx4_ib_dev {
|
||||
@@ -176,6 +192,7 @@ struct mlx4_ib_dev {
|
||||
|
||||
struct mutex cap_mask_mutex;
|
||||
bool ib_active;
|
||||
struct mlx4_ib_iboe iboe;
|
||||
};
|
||||
|
||||
static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev)
|
||||
@@ -314,9 +331,20 @@ int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages,
|
||||
int mlx4_ib_unmap_fmr(struct list_head *fmr_list);
|
||||
int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr);
|
||||
|
||||
int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr,
|
||||
u8 *mac, int *is_mcast, u8 port);
|
||||
|
||||
static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah)
|
||||
{
|
||||
return !!(ah->av.g_slid & 0x80);
|
||||
u8 port = be32_to_cpu(ah->av.ib.port_pd) >> 24 & 3;
|
||||
|
||||
if (rdma_port_get_link_layer(ah->ibah.device, port) == IB_LINK_LAYER_ETHERNET)
|
||||
return 1;
|
||||
|
||||
return !!(ah->av.ib.g_slid & 0x80);
|
||||
}
|
||||
|
||||
int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
|
||||
union ib_gid *gid);
|
||||
|
||||
#endif /* MLX4_IB_H */
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <linux/log2.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <rdma/ib_cache.h>
|
||||
#include <rdma/ib_pack.h>
|
||||
@@ -48,17 +49,25 @@ enum {
|
||||
|
||||
enum {
|
||||
MLX4_IB_DEFAULT_SCHED_QUEUE = 0x83,
|
||||
MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f
|
||||
MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f,
|
||||
MLX4_IB_LINK_TYPE_IB = 0,
|
||||
MLX4_IB_LINK_TYPE_ETH = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
/*
|
||||
* Largest possible UD header: send with GRH and immediate data.
|
||||
* Largest possible UD header: send with GRH and immediate
|
||||
* data plus 14 bytes for an Ethernet header. (LRH would only
|
||||
* use 8 bytes, so Ethernet is the biggest case)
|
||||
*/
|
||||
MLX4_IB_UD_HEADER_SIZE = 72,
|
||||
MLX4_IB_UD_HEADER_SIZE = 78,
|
||||
MLX4_IB_LSO_HEADER_SPARE = 128,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX4_IB_IBOE_ETHERTYPE = 0x8915
|
||||
};
|
||||
|
||||
struct mlx4_ib_sqp {
|
||||
struct mlx4_ib_qp qp;
|
||||
int pkey_index;
|
||||
@@ -462,6 +471,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
|
||||
mutex_init(&qp->mutex);
|
||||
spin_lock_init(&qp->sq.lock);
|
||||
spin_lock_init(&qp->rq.lock);
|
||||
INIT_LIST_HEAD(&qp->gid_list);
|
||||
|
||||
qp->state = IB_QPS_RESET;
|
||||
if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
|
||||
@@ -649,6 +659,16 @@ static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *re
|
||||
}
|
||||
}
|
||||
|
||||
static void del_gid_entries(struct mlx4_ib_qp *qp)
|
||||
{
|
||||
struct mlx4_ib_gid_entry *ge, *tmp;
|
||||
|
||||
list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
|
||||
list_del(&ge->list);
|
||||
kfree(ge);
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
|
||||
int is_user)
|
||||
{
|
||||
@@ -695,6 +715,8 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
|
||||
if (!qp->ibqp.srq)
|
||||
mlx4_db_free(dev->dev, &qp->db);
|
||||
}
|
||||
|
||||
del_gid_entries(qp);
|
||||
}
|
||||
|
||||
struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
|
||||
@@ -852,6 +874,12 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
|
||||
static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
|
||||
struct mlx4_qp_path *path, u8 port)
|
||||
{
|
||||
int err;
|
||||
int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) ==
|
||||
IB_LINK_LAYER_ETHERNET;
|
||||
u8 mac[6];
|
||||
int is_mcast;
|
||||
|
||||
path->grh_mylmc = ah->src_path_bits & 0x7f;
|
||||
path->rlid = cpu_to_be16(ah->dlid);
|
||||
if (ah->static_rate) {
|
||||
@@ -882,9 +910,35 @@ static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
|
||||
path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
|
||||
((port - 1) << 6) | ((ah->sl & 0xf) << 2);
|
||||
|
||||
if (is_eth) {
|
||||
if (!(ah->ah_flags & IB_AH_GRH))
|
||||
return -1;
|
||||
|
||||
err = mlx4_ib_resolve_grh(dev, ah, mac, &is_mcast, port);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memcpy(path->dmac, mac, 6);
|
||||
path->ackto = MLX4_IB_LINK_TYPE_ETH;
|
||||
/* use index 0 into MAC table for IBoE */
|
||||
path->grh_mylmc &= 0x80;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
|
||||
{
|
||||
struct mlx4_ib_gid_entry *ge, *tmp;
|
||||
|
||||
list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
|
||||
if (!ge->added && mlx4_ib_add_mc(dev, qp, &ge->gid)) {
|
||||
ge->added = 1;
|
||||
ge->port = qp->port;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
|
||||
const struct ib_qp_attr *attr, int attr_mask,
|
||||
enum ib_qp_state cur_state, enum ib_qp_state new_state)
|
||||
@@ -980,7 +1034,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
|
||||
}
|
||||
|
||||
if (attr_mask & IB_QP_TIMEOUT) {
|
||||
context->pri_path.ackto = attr->timeout << 3;
|
||||
context->pri_path.ackto |= attr->timeout << 3;
|
||||
optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT;
|
||||
}
|
||||
|
||||
@@ -1118,8 +1172,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
|
||||
qp->atomic_rd_en = attr->qp_access_flags;
|
||||
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
|
||||
qp->resp_depth = attr->max_dest_rd_atomic;
|
||||
if (attr_mask & IB_QP_PORT)
|
||||
if (attr_mask & IB_QP_PORT) {
|
||||
qp->port = attr->port_num;
|
||||
update_mcg_macs(dev, qp);
|
||||
}
|
||||
if (attr_mask & IB_QP_ALT_PATH)
|
||||
qp->alt_port = attr->alt_port_num;
|
||||
|
||||
@@ -1226,35 +1282,45 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
|
||||
int header_size;
|
||||
int spc;
|
||||
int i;
|
||||
int is_eth;
|
||||
int is_grh;
|
||||
|
||||
send_size = 0;
|
||||
for (i = 0; i < wr->num_sge; ++i)
|
||||
send_size += wr->sg_list[i].length;
|
||||
|
||||
ib_ud_header_init(send_size, 1, 0, mlx4_ib_ah_grh_present(ah), 0, &sqp->ud_header);
|
||||
is_eth = rdma_port_get_link_layer(sqp->qp.ibqp.device, sqp->qp.port) == IB_LINK_LAYER_ETHERNET;
|
||||
is_grh = mlx4_ib_ah_grh_present(ah);
|
||||
ib_ud_header_init(send_size, !is_eth, is_eth, is_grh, 0, &sqp->ud_header);
|
||||
|
||||
sqp->ud_header.lrh.service_level =
|
||||
be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
|
||||
sqp->ud_header.lrh.destination_lid = ah->av.dlid;
|
||||
sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.g_slid & 0x7f);
|
||||
if (mlx4_ib_ah_grh_present(ah)) {
|
||||
if (!is_eth) {
|
||||
sqp->ud_header.lrh.service_level =
|
||||
be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
|
||||
sqp->ud_header.lrh.destination_lid = ah->av.ib.dlid;
|
||||
sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.ib.g_slid & 0x7f);
|
||||
}
|
||||
|
||||
if (is_grh) {
|
||||
sqp->ud_header.grh.traffic_class =
|
||||
(be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20) & 0xff;
|
||||
(be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff;
|
||||
sqp->ud_header.grh.flow_label =
|
||||
ah->av.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
|
||||
sqp->ud_header.grh.hop_limit = ah->av.hop_limit;
|
||||
ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.port_pd) >> 24,
|
||||
ah->av.gid_index, &sqp->ud_header.grh.source_gid);
|
||||
ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
|
||||
sqp->ud_header.grh.hop_limit = ah->av.ib.hop_limit;
|
||||
ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24,
|
||||
ah->av.ib.gid_index, &sqp->ud_header.grh.source_gid);
|
||||
memcpy(sqp->ud_header.grh.destination_gid.raw,
|
||||
ah->av.dgid, 16);
|
||||
ah->av.ib.dgid, 16);
|
||||
}
|
||||
|
||||
mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
|
||||
mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
|
||||
(sqp->ud_header.lrh.destination_lid ==
|
||||
IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) |
|
||||
(sqp->ud_header.lrh.service_level << 8));
|
||||
mlx->rlid = sqp->ud_header.lrh.destination_lid;
|
||||
|
||||
if (!is_eth) {
|
||||
mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
|
||||
(sqp->ud_header.lrh.destination_lid ==
|
||||
IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) |
|
||||
(sqp->ud_header.lrh.service_level << 8));
|
||||
mlx->rlid = sqp->ud_header.lrh.destination_lid;
|
||||
}
|
||||
|
||||
switch (wr->opcode) {
|
||||
case IB_WR_SEND:
|
||||
@@ -1270,9 +1336,21 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0;
|
||||
if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
|
||||
sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
|
||||
if (is_eth) {
|
||||
u8 *smac;
|
||||
|
||||
memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
|
||||
/* FIXME: cache smac value? */
|
||||
smac = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]->dev_addr;
|
||||
memcpy(sqp->ud_header.eth.smac_h, smac, 6);
|
||||
if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
|
||||
mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
|
||||
sqp->ud_header.eth.type = cpu_to_be16(MLX4_IB_IBOE_ETHERTYPE);
|
||||
} else {
|
||||
sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0;
|
||||
if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
|
||||
sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
|
||||
}
|
||||
sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
|
||||
if (!sqp->qp.ibqp.qp_num)
|
||||
ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey);
|
||||
@@ -1434,6 +1512,8 @@ static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
|
||||
memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
|
||||
dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
|
||||
dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
|
||||
dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan;
|
||||
memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6);
|
||||
}
|
||||
|
||||
static void set_mlx_icrc_seg(void *dseg)
|
||||
|
||||
@@ -374,6 +374,27 @@ struct mlx4_av {
|
||||
u8 dgid[16];
|
||||
};
|
||||
|
||||
struct mlx4_eth_av {
|
||||
__be32 port_pd;
|
||||
u8 reserved1;
|
||||
u8 smac_idx;
|
||||
u16 reserved2;
|
||||
u8 reserved3;
|
||||
u8 gid_index;
|
||||
u8 stat_rate;
|
||||
u8 hop_limit;
|
||||
__be32 sl_tclass_flowlabel;
|
||||
u8 dgid[16];
|
||||
u32 reserved4[2];
|
||||
__be16 vlan;
|
||||
u8 mac[6];
|
||||
};
|
||||
|
||||
union mlx4_ext_av {
|
||||
struct mlx4_av ib;
|
||||
struct mlx4_eth_av eth;
|
||||
};
|
||||
|
||||
struct mlx4_dev {
|
||||
struct pci_dev *pdev;
|
||||
unsigned long flags;
|
||||
@@ -402,6 +423,12 @@ struct mlx4_init_port_param {
|
||||
if (((type) == MLX4_PORT_TYPE_IB ? (dev)->caps.port_mask : \
|
||||
~(dev)->caps.port_mask) & 1 << ((port) - 1))
|
||||
|
||||
#define mlx4_foreach_ib_transport_port(port, dev) \
|
||||
for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \
|
||||
if (((dev)->caps.port_mask & 1 << ((port) - 1)) || \
|
||||
((dev)->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
|
||||
|
||||
|
||||
int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
|
||||
struct mlx4_buf *buf);
|
||||
void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf);
|
||||
|
||||
Reference in New Issue
Block a user