mlx4: Add support for IBoE - address resolution
PATCH v8 9/11 mlx4: Add support for IBoE - address resolution
The following patch handles address vectors creation for IBoE ports. mlx4 needs the MAC address of the remote node to include it in the WQE of a UD QP or in the QP context of connected QPs. Address resolution is done atomically in the case of a link local address or a multicast GID and otherwise -EINVAL is returned. mlx4 transport packets were changed too to accommodate for IBoE. Multicast groups attach/detach calls dev_mc_add/remove to update the NIC's multicast filters.Since attaching a QP to a multicast group does not require the QP to be in a state different then INIT - this is fine for IB. For IBoE however, we need the port assigned to the QP in order to call dev_mc_add() for the correct netdevice, while port is assigned when moving from INIT to RTR. Hence, we must keep track of all the multicast groups attached to a QP and call dev_mc_add() when the port becomes available.
---
Changes from v7:
1. Fix failure to initialize gid_index in create_iboe_ah()
2. Move call register_netdevice_notifier() after call to ib_register_device()
3. Call flush_workqueue() after unregister notifier to flush any pending work requesets.
4. Change build_mlx_header to match changes to ud_header.c
drivers/infiniband/hw/mlx4/ah.c | 182 ++++++++++--- drivers/infiniband/hw/mlx4/mad.c | 32 ++- drivers/infiniband/hw/mlx4/main.c | 497 +++++++++++++++++++++++++++++--- drivers/infiniband/hw/mlx4/mlx4_ib.h | 35 +++- drivers/infiniband/hw/mlx4/qp.c | 139 +++++++-- drivers/infiniband/hw/mthca/mthca_qp.c | 2 + drivers/net/mlx4/en_port.c | 4 +- drivers/net/mlx4/en_port.h | 3 +- drivers/net/mlx4/fw.c | 3 +- include/linux/mlx4/cmd.h | 1 + include/linux/mlx4/device.h | 31 ++- include/linux/mlx4/qp.h | 7 +- 12 files changed, 819 insertions(+), 117 deletions(-)
drivers/infiniband/hw/mlx4/ah.c +149 -33
@@ -31,63 +31,158 @@*/ #include "mlx4_ib.h" +#include <rdma/ib_addr.h> +#include <linux/inet.h> +#include <linux/string.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 mlx4_dev *dev =to_mdev (pd->device)->dev; -struct mlx4_ib_ah *ah; +struct mlx4_ib_iboe *iboe = &dev->iboe; +struct in6_addr in6; - ah =kmalloc (sizeof *ah,GFP_ATOMIC ); -if (!ah) -return ERR_PTR (-ENOMEM ); + *is_mcast =0 ; +spin_lock (&iboe->lock); +if (!iboe->netdevs[port -1 ]) { +spin_unlock (&iboe->lock); +return -EINVAL ; + } +spin_unlock (&iboe->lock); -memset (&ah->av,0 ,sizeof ah->av); +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 ; - 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 ); +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; + + 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.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 |= + 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.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); +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_0_1, mac,2 ); +memcpy (ah->av.eth.mac_2_5, mac +2 ,4 ); + 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 ); + +if (rdma_port_link_layer (pd->device, ah_attr->port_num) ==IB_LINK_LAYER_ETHERNET ) { +if (!(ah_attr->ah_flags &IB_AH_GRH )) { + ret =ERR_PTR (-EINVAL ); + goto out; + }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); +if (IS_ERR (ret)) + goto out; +else +return ret; + } + }else +return create_ib_ah (pd, ah_attr, ah);/* never fails */ + +out: +kfree (ah); +return ret; +} +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_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 ;
@@ -98,3 +193,24 @@ int mlx4_ib_destroy_ah(struct ib_ah *ah)kfree (to_mah (ah));return 0 ; } + +int mlx4_ib_get_eth_l2_addr (struct ib_device *device,u8 port,union ib_gid *gid, +int sgid_idx,u8 *mac,u16 *vlan_id) +{ +int err; +struct mlx4_ib_dev *ibdev =to_mdev (device); +struct ib_ah_attr ah_attr = { + .port_num = port, + }; +int is_mcast; + +memcpy (ah_attr.grh.dgid.raw, gid,16 ); + err =mlx4_ib_resolve_grh (ibdev, &ah_attr, mac, &is_mcast, port); +if (err) +ERR_PTR (err); + + *vlan_id =0 ; + +return 0 ; +} +
drivers/infiniband/hw/mlx4/mad.c +20 -12
@@ -310,19 +310,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_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 ;
@@ -343,8 +349,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])
drivers/infiniband/hw/mlx4/main.c +462 -35
637 lines not on this page · raw message
drivers/infiniband/hw/mlx4/mlx4_ib.h +33 -2
@@ -112,6 +112,13 @@ enum mlx4_ib_qp_flags { MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = 1 << 1, }; +struct 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,23 @@ 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); + +int mlx4_ib_get_eth_l2_addr (struct ib_device *device,u8 port,union ib_gid *gid, +int sgid_idx,u8 *mac,u16 *vlan_id); +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_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 */
drivers/infiniband/hw/mlx4/qp.c +111 -28
254 lines not on this page · raw message
drivers/infiniband/hw/mthca/mthca_qp.c +2 -0
@@ -1494,7 +1494,9 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,u16 pkey;ib_ud_header_init (256 ,/* assume a MAD */ +1 ,0 ,mthca_ah_grh_present (to_mah (wr->wr.ud.ah)), +0 , &sqp->ud_header); err =mthca_read_ah (dev,to_mah (wr->wr.ud.ah), &sqp->ud_header);
drivers/net/mlx4/en_port.c +2 -2
@@ -127,8 +127,8 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,memset (context,0 ,sizeof *context); context->base_qpn =cpu_to_be32 (base_qpn); - context->promisc =cpu_to_be32 (promisc <<SET_PORT_PROMISC_SHIFT | base_qpn); - context->mcast =cpu_to_be32 (1 <<SET_PORT_PROMISC_SHIFT | base_qpn); + context->promisc =cpu_to_be32 (promisc <<SET_PORT_PROMISC_EN_SHIFT | base_qpn); + context->mcast =cpu_to_be32 (1 <<SET_PORT_PROMISC_MODE_SHIFT | base_qpn); context->intra_no_vlan =0 ; context->no_vlan =MLX4_NO_VLAN_IDX ; context->intra_vlan_miss =0 ;
drivers/net/mlx4/en_port.h +2 -1
@@ -36,7 +36,8 @@#define SET_PORT_GEN_ALL_VALID 0x7 -#define SET_PORT_PROMISC_SHIFT 31 +#define SET_PORT_PROMISC_EN_SHIFT 31 +#define SET_PORT_PROMISC_MODE_SHIFT 30enum {MLX4_CMD_SET_VLAN_FLTR =0x47 ,
drivers/net/mlx4/fw.c +2 -1
@@ -98,7 +98,8 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags) [20] = "Address vector port checking support", [21] = "UD multicast support", [24] = "Demand paging support", - [25] = "Router support" + [25] = "Router support", + [30] = "IBoE support" };int i;
include/linux/mlx4/cmd.h +1 -0
@@ -140,6 +140,7 @@ enum {MLX4_SET_PORT_MAC_TABLE =0x2 ,MLX4_SET_PORT_VLAN_TABLE =0x3 ,MLX4_SET_PORT_PRIO_MAP =0x4 , + MLX4_SET_PORT_GID_TABLE = 0x5, };struct mlx4_dev ;
include/linux/mlx4/device.h +30 -1
@@ -67,7 +67,8 @@ enum {MLX4_DEV_CAP_FLAG_ATOMIC =1 <<18 ,MLX4_DEV_CAP_FLAG_RAW_MCAST =1 <<19 ,MLX4_DEV_CAP_FLAG_UD_AV_PORT =1 <<20 , -MLX4_DEV_CAP_FLAG_UD_MCAST =1 <<21 +MLX4_DEV_CAP_FLAG_UD_MCAST =1 <<21 , +MLX4_DEV_CAP_FLAG_IBOE =1 <<30 }; enum {
@@ -373,6 +374,28 @@ 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_0_1[2 ]; +u8 mac_2_5[4 ]; +}; + +union mlx4_ext_av { +struct mlx4_av ib; +struct mlx4_eth_av eth; +}; +struct mlx4_dev {struct pci_dev *pdev;unsigned long flags;
@@ -401,6 +424,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);
include/linux/mlx4/qp.h +5 -2
@@ -112,7 +112,8 @@ struct mlx4_qp_path {u8 snooper_flags;u8 reserved3[2 ];u8 counter_index; -u8 reserved4[7 ]; +u8 reserved4; +u8 dmac[6 ]; };struct mlx4_qp_context {
@@ -166,6 +167,7 @@ enum {MLX4_WQE_CTRL_TCP_UDP_CSUM =1 <<5 ,MLX4_WQE_CTRL_INS_VLAN =1 <<6 ,MLX4_WQE_CTRL_STRONG_ORDER =1 <<7 , + MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0, }; struct mlx4_wqe_ctrl_seg {
@@ -219,7 +221,8 @@ struct mlx4_wqe_datagram_seg {__be32 av[8 ];__be32 dqpn;__be32 qkey; -__be32 reservd[2 ]; +__be16 vlan; +u8 mac[6 ]; };struct mlx4_wqe_lso_seg {
Signature · 6 lines
1.7.0 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
include/linux/mlx4/device.h struct mlx4_av { · line 391
Quoted 2 lines
include/linux/mlx4/device.h +2
-0+u8 mac_0_1[2 ]; +u8 mac_2_5[4 ];
This looks a bit odd. Any reason why you don't just have "u8 mac[6];" in this structure?
Signature · 6 lines
Roland Dreier <[email protected]> || For corporate legal information go to: http://www.cisco.com/web/about/doing_business/legal/cri/index.html -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): adabpckuaim.fsf-BjVyx320WGW9gfZ95n9DRSW4+XlvGpQz@public.gmane.org
Quoted 5 lines · Roland Dreier
include/linux/mlx4/device.h struct mlx4_av { · line 391
Quoted 2 lines
include/linux/mlx4/device.h +2
-0+u8 mac_0_1[2 ]; +u8 mac_2_5[4 ];This looks a bit odd. Any reason why you don't just have "u8 mac[6];" in this structure?
We can get rid of this crap. I think the origin of this is a limitation of ib_pack() to deal with fields that cross a dword boundary which should not avoid us from using mac[6] here.