Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/mlx4/mlx4_ib/mlx4_ib_ah.c
Show All 36 Lines | |||||
#include <rdma/ib_cache.h> | #include <rdma/ib_cache.h> | ||||
#include <linux/slab.h> | #include <linux/slab.h> | ||||
#include <linux/string.h> | #include <linux/string.h> | ||||
#include <linux/etherdevice.h> | #include <linux/etherdevice.h> | ||||
#include "mlx4_ib.h" | #include "mlx4_ib.h" | ||||
static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, | static int create_ib_ah(struct ib_ah *ib_ah, struct ib_ah_attr *ah_attr) | ||||
struct mlx4_ib_ah *ah) | |||||
{ | { | ||||
struct mlx4_dev *dev = to_mdev(pd->device)->dev; | struct ib_pd *pd = ib_ah->pd; | ||||
struct mlx4_ib_ah *ah = to_mah(ib_ah); | |||||
struct mlx4_dev *dev = to_mdev(ib_ah->device)->dev; | |||||
ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); | 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; | ah->av.ib.g_slid = ah_attr->src_path_bits; | ||||
ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); | ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); | ||||
if (ah_attr->ah_flags & IB_AH_GRH) { | if (ah_attr->ah_flags & IB_AH_GRH) { | ||||
ah->av.ib.g_slid |= 0x80; | ah->av.ib.g_slid |= 0x80; | ||||
ah->av.ib.gid_index = ah_attr->grh.sgid_index; | ah->av.ib.gid_index = ah_attr->grh.sgid_index; | ||||
ah->av.ib.hop_limit = ah_attr->grh.hop_limit; | ah->av.ib.hop_limit = ah_attr->grh.hop_limit; | ||||
ah->av.ib.sl_tclass_flowlabel |= | ah->av.ib.sl_tclass_flowlabel |= | ||||
cpu_to_be32((ah_attr->grh.traffic_class << 20) | | cpu_to_be32((ah_attr->grh.traffic_class << 20) | | ||||
ah_attr->grh.flow_label); | ah_attr->grh.flow_label); | ||||
memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); | memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); | ||||
} | } | ||||
ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); | ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); | ||||
if (ah_attr->static_rate) { | if (ah_attr->static_rate) { | ||||
ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; | 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 && | 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)) | !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) | ||||
--ah->av.ib.stat_rate; | --ah->av.ib.stat_rate; | ||||
} | } | ||||
return 0; | |||||
return &ah->ibah; | |||||
} | } | ||||
static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, | static int create_iboe_ah(struct ib_ah *ib_ah, struct ib_ah_attr *ah_attr) | ||||
struct mlx4_ib_ah *ah) | |||||
{ | { | ||||
struct mlx4_ib_dev *ibdev = to_mdev(pd->device); | struct ib_pd *pd = ib_ah->pd; | ||||
struct mlx4_ib_dev *ibdev = to_mdev(ib_ah->device); | |||||
struct mlx4_ib_ah *ah = to_mah(ib_ah); | |||||
struct mlx4_dev *dev = ibdev->dev; | struct mlx4_dev *dev = ibdev->dev; | ||||
int is_mcast = 0; | int is_mcast = 0; | ||||
struct in6_addr in6; | struct in6_addr in6; | ||||
u16 vlan_tag = 0xffff; | u16 vlan_tag = 0xffff; | ||||
union ib_gid sgid; | union ib_gid sgid; | ||||
struct ib_gid_attr gid_attr; | struct ib_gid_attr gid_attr; | ||||
int ret; | int ret; | ||||
memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(in6)); | memcpy(&in6, ah_attr->grh.dgid.raw, sizeof(in6)); | ||||
if (rdma_is_multicast_addr(&in6)) { | if (rdma_is_multicast_addr(&in6)) { | ||||
is_mcast = 1; | is_mcast = 1; | ||||
rdma_get_mcast_mac(&in6, ah->av.eth.mac); | rdma_get_mcast_mac(&in6, ah->av.eth.mac); | ||||
} else { | } else { | ||||
memcpy(ah->av.eth.mac, ah_attr->dmac, ETH_ALEN); | memcpy(ah->av.eth.mac, ah_attr->dmac, ETH_ALEN); | ||||
} | } | ||||
ret = ib_get_cached_gid(pd->device, ah_attr->port_num, | ret = ib_get_cached_gid(pd->device, ah_attr->port_num, | ||||
ah_attr->grh.sgid_index, &sgid, &gid_attr); | ah_attr->grh.sgid_index, &sgid, &gid_attr); | ||||
if (ret) | if (ret) | ||||
return ERR_PTR(ret); | return ret; | ||||
eth_zero_addr(ah->av.eth.s_mac); | eth_zero_addr(ah->av.eth.s_mac); | ||||
if (gid_attr.ndev) { | if (gid_attr.ndev) { | ||||
vlan_tag = rdma_vlan_dev_vlan_id(gid_attr.ndev); | vlan_tag = rdma_vlan_dev_vlan_id(gid_attr.ndev); | ||||
memcpy(ah->av.eth.s_mac, IF_LLADDR(gid_attr.ndev), ETH_ALEN); | memcpy(ah->av.eth.s_mac, IF_LLADDR(gid_attr.ndev), ETH_ALEN); | ||||
if_rele(gid_attr.ndev); | if_rele(gid_attr.ndev); | ||||
} | } | ||||
if (vlan_tag < 0x1000) | if (vlan_tag < 0x1000) | ||||
vlan_tag |= (ah_attr->sl & 7) << 13; | vlan_tag |= (ah_attr->sl & 7) << 13; | ||||
ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); | ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); | ||||
ret = mlx4_ib_gid_index_to_real_index(ibdev, ah_attr->port_num, ah_attr->grh.sgid_index); | ret = mlx4_ib_gid_index_to_real_index(ibdev, ah_attr->port_num, ah_attr->grh.sgid_index); | ||||
if (ret < 0) | if (ret < 0) | ||||
return ERR_PTR(ret); | return ret; | ||||
ah->av.eth.gid_index = ret; | ah->av.eth.gid_index = ret; | ||||
ah->av.eth.vlan = cpu_to_be16(vlan_tag); | ah->av.eth.vlan = cpu_to_be16(vlan_tag); | ||||
ah->av.eth.hop_limit = ah_attr->grh.hop_limit; | ah->av.eth.hop_limit = ah_attr->grh.hop_limit; | ||||
if (ah_attr->static_rate) { | if (ah_attr->static_rate) { | ||||
ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; | 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 && | 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)) | !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support)) | ||||
--ah->av.eth.stat_rate; | --ah->av.eth.stat_rate; | ||||
} | } | ||||
/* | /* | ||||
* HW requires multicast LID so we just choose one. | * HW requires multicast LID so we just choose one. | ||||
*/ | */ | ||||
if (is_mcast) | if (is_mcast) | ||||
ah->av.ib.dlid = cpu_to_be16(0xc000); | ah->av.ib.dlid = cpu_to_be16(0xc000); | ||||
memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); | memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); | ||||
ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 29); | ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 29); | ||||
return &ah->ibah; | return 0; | ||||
} | } | ||||
struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, | int mlx4_ib_create_ah(struct ib_ah *ib_ah, struct ib_ah_attr *ah_attr, | ||||
struct ib_udata *udata) | u32 flags, struct ib_udata *udata) | ||||
{ | { | ||||
struct mlx4_ib_ah *ah; | if (rdma_port_get_link_layer(ib_ah->pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) { | ||||
struct ib_ah *ret; | |||||
ah = kzalloc(sizeof *ah, GFP_ATOMIC); | |||||
if (!ah) | |||||
return ERR_PTR(-ENOMEM); | |||||
if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) { | |||||
if (!(ah_attr->ah_flags & IB_AH_GRH)) { | if (!(ah_attr->ah_flags & IB_AH_GRH)) { | ||||
ret = ERR_PTR(-EINVAL); | return -EINVAL; | ||||
} else { | } else { | ||||
/* | /* | ||||
* TBD: need to handle the case when we get | * TBD: need to handle the case when we get | ||||
* called in an atomic context and there we | * called in an atomic context and there we | ||||
* might sleep. We don't expect this | * might sleep. We don't expect this | ||||
* currently since we're working with link | * currently since we're working with link | ||||
* local addresses which we can translate | * local addresses which we can translate | ||||
* without going to sleep. | * without going to sleep. | ||||
*/ | */ | ||||
ret = create_iboe_ah(pd, ah_attr, ah); | return create_iboe_ah(ib_ah, ah_attr); | ||||
} | } | ||||
} | |||||
return create_ib_ah(ib_ah, ah_attr); | |||||
} | |||||
if (IS_ERR(ret)) | int mlx4_ib_create_ah_slave(struct ib_ah *ah, struct ib_ah_attr *ah_attr, | ||||
kfree(ah); | int slave_sgid_index, u8 *s_mac, u16 vlan_tag) | ||||
{ | |||||
struct ib_ah_attr slave_attr = *ah_attr; | |||||
struct mlx4_ib_ah *mah = to_mah(ah); | |||||
int ret; | |||||
slave_attr.grh.sgid_index = slave_sgid_index; | |||||
ret = mlx4_ib_create_ah(ah, &slave_attr, 0, NULL); | |||||
if (ret) | |||||
return ret; | return ret; | ||||
} else | |||||
return create_ib_ah(pd, ah_attr, ah); /* never fails */ | /* get rid of force-loopback bit */ | ||||
mah->av.ib.port_pd &= cpu_to_be32(0x7FFFFFFF); | |||||
if (rdma_port_get_link_layer(ah->pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) | |||||
memcpy(mah->av.eth.s_mac, s_mac, 6); | |||||
if (vlan_tag < 0x1000) | |||||
vlan_tag |= (ah_attr->sl & 7) << 13; | |||||
mah->av.eth.vlan = cpu_to_be16(vlan_tag); | |||||
return 0; | |||||
} | } | ||||
int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) | int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) | ||||
{ | { | ||||
struct mlx4_ib_ah *ah = to_mah(ibah); | struct mlx4_ib_ah *ah = to_mah(ibah); | ||||
enum rdma_link_layer ll; | enum rdma_link_layer ll; | ||||
memset(ah_attr, 0, sizeof *ah_attr); | memset(ah_attr, 0, sizeof *ah_attr); | ||||
Show All 19 Lines | if (mlx4_ib_ah_grh_present(ah)) { | ||||
ah_attr->grh.hop_limit = ah->av.ib.hop_limit; | ah_attr->grh.hop_limit = ah->av.ib.hop_limit; | ||||
ah_attr->grh.sgid_index = ah->av.ib.gid_index; | ah_attr->grh.sgid_index = ah->av.ib.gid_index; | ||||
memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); | memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
int mlx4_ib_destroy_ah(struct ib_ah *ah) | void mlx4_ib_destroy_ah(struct ib_ah *ah, u32 flags) | ||||
{ | { | ||||
kfree(to_mah(ah)); | return; | ||||
return 0; | |||||
} | } |