linux/drivers/infiniband/hw/mlx4/ah.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include <rdma/ib_addr.h>
  34#include <rdma/ib_cache.h>
  35
  36#include <linux/slab.h>
  37#include <linux/inet.h>
  38#include <linux/string.h>
  39#include <linux/mlx4/driver.h>
  40
  41#include "mlx4_ib.h"
  42
  43static void create_ib_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr)
  44{
  45        struct mlx4_ib_ah *ah = to_mah(ib_ah);
  46        struct mlx4_dev *dev = to_mdev(ib_ah->device)->dev;
  47
  48        ah->av.ib.port_pd = cpu_to_be32(to_mpd(ib_ah->pd)->pdn |
  49                            (rdma_ah_get_port_num(ah_attr) << 24));
  50        ah->av.ib.g_slid  = rdma_ah_get_path_bits(ah_attr);
  51        ah->av.ib.sl_tclass_flowlabel =
  52                        cpu_to_be32(rdma_ah_get_sl(ah_attr) << 28);
  53        if (rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) {
  54                const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
  55
  56                ah->av.ib.g_slid   |= 0x80;
  57                ah->av.ib.gid_index = grh->sgid_index;
  58                ah->av.ib.hop_limit = grh->hop_limit;
  59                ah->av.ib.sl_tclass_flowlabel |=
  60                        cpu_to_be32((grh->traffic_class << 20) |
  61                                    grh->flow_label);
  62                memcpy(ah->av.ib.dgid, grh->dgid.raw, 16);
  63        }
  64
  65        ah->av.ib.dlid = cpu_to_be16(rdma_ah_get_dlid(ah_attr));
  66        if (rdma_ah_get_static_rate(ah_attr)) {
  67                u8 static_rate = rdma_ah_get_static_rate(ah_attr) +
  68                                        MLX4_STAT_RATE_OFFSET;
  69
  70                while (static_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
  71                       !(1 << static_rate & dev->caps.stat_rate_support))
  72                        --static_rate;
  73                ah->av.ib.stat_rate = static_rate;
  74        }
  75}
  76
  77static int create_iboe_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr)
  78{
  79        struct mlx4_ib_dev *ibdev = to_mdev(ib_ah->device);
  80        struct mlx4_ib_ah *ah = to_mah(ib_ah);
  81        const struct ib_gid_attr *gid_attr;
  82        struct mlx4_dev *dev = ibdev->dev;
  83        int is_mcast = 0;
  84        struct in6_addr in6;
  85        u16 vlan_tag = 0xffff;
  86        const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
  87        int ret;
  88
  89        memcpy(&in6, grh->dgid.raw, sizeof(in6));
  90        if (rdma_is_multicast_addr(&in6))
  91                is_mcast = 1;
  92
  93        memcpy(ah->av.eth.mac, ah_attr->roce.dmac, ETH_ALEN);
  94        eth_zero_addr(ah->av.eth.s_mac);
  95
  96        /*
  97         * If sgid_attr is NULL we are being called by mlx4_ib_create_ah_slave
  98         * and we are directly creating an AV for a slave's gid_index.
  99         */
 100        gid_attr = ah_attr->grh.sgid_attr;
 101        if (gid_attr) {
 102                ret = rdma_read_gid_l2_fields(gid_attr, &vlan_tag,
 103                                              &ah->av.eth.s_mac[0]);
 104                if (ret)
 105                        return ret;
 106
 107                ret = mlx4_ib_gid_index_to_real_index(ibdev, gid_attr);
 108                if (ret < 0)
 109                        return ret;
 110                ah->av.eth.gid_index = ret;
 111        } else {
 112                /* mlx4_ib_create_ah_slave fills in the s_mac and the vlan */
 113                ah->av.eth.gid_index = ah_attr->grh.sgid_index;
 114        }
 115
 116        if (vlan_tag < 0x1000)
 117                vlan_tag |= (rdma_ah_get_sl(ah_attr) & 7) << 13;
 118        ah->av.eth.port_pd = cpu_to_be32(to_mpd(ib_ah->pd)->pdn |
 119                                         (rdma_ah_get_port_num(ah_attr) << 24));
 120        ah->av.eth.vlan = cpu_to_be16(vlan_tag);
 121        ah->av.eth.hop_limit = grh->hop_limit;
 122        if (rdma_ah_get_static_rate(ah_attr)) {
 123                ah->av.eth.stat_rate = rdma_ah_get_static_rate(ah_attr) +
 124                                        MLX4_STAT_RATE_OFFSET;
 125                while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
 126                       !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
 127                        --ah->av.eth.stat_rate;
 128        }
 129        ah->av.eth.sl_tclass_flowlabel |=
 130                        cpu_to_be32((grh->traffic_class << 20) |
 131                                    grh->flow_label);
 132        /*
 133         * HW requires multicast LID so we just choose one.
 134         */
 135        if (is_mcast)
 136                ah->av.ib.dlid = cpu_to_be16(0xc000);
 137
 138        memcpy(ah->av.eth.dgid, grh->dgid.raw, 16);
 139        ah->av.eth.sl_tclass_flowlabel |= cpu_to_be32(rdma_ah_get_sl(ah_attr)
 140                                                      << 29);
 141        return 0;
 142}
 143
 144int mlx4_ib_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr,
 145                      struct ib_udata *udata)
 146{
 147        struct rdma_ah_attr *ah_attr = init_attr->ah_attr;
 148
 149        if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) {
 150                if (!(rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH))
 151                        return -EINVAL;
 152                /*
 153                 * TBD: need to handle the case when we get
 154                 * called in an atomic context and there we
 155                 * might sleep.  We don't expect this
 156                 * currently since we're working with link
 157                 * local addresses which we can translate
 158                 * without going to sleep.
 159                 */
 160                return create_iboe_ah(ib_ah, ah_attr);
 161        }
 162
 163        create_ib_ah(ib_ah, ah_attr);
 164        return 0;
 165}
 166
 167int mlx4_ib_create_ah_slave(struct ib_ah *ah, struct rdma_ah_attr *ah_attr,
 168                            int slave_sgid_index, u8 *s_mac, u16 vlan_tag)
 169{
 170        struct rdma_ah_attr slave_attr = *ah_attr;
 171        struct rdma_ah_init_attr init_attr = {};
 172        struct mlx4_ib_ah *mah = to_mah(ah);
 173        int ret;
 174
 175        slave_attr.grh.sgid_attr = NULL;
 176        slave_attr.grh.sgid_index = slave_sgid_index;
 177        init_attr.ah_attr = &slave_attr;
 178        ret = mlx4_ib_create_ah(ah, &init_attr, NULL);
 179        if (ret)
 180                return ret;
 181
 182        ah->type = ah_attr->type;
 183
 184        /* get rid of force-loopback bit */
 185        mah->av.ib.port_pd &= cpu_to_be32(0x7FFFFFFF);
 186
 187        if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE)
 188                memcpy(mah->av.eth.s_mac, s_mac, 6);
 189
 190        if (vlan_tag < 0x1000)
 191                vlan_tag |= (rdma_ah_get_sl(ah_attr) & 7) << 13;
 192        mah->av.eth.vlan = cpu_to_be16(vlan_tag);
 193
 194        return 0;
 195}
 196
 197int mlx4_ib_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr)
 198{
 199        struct mlx4_ib_ah *ah = to_mah(ibah);
 200        int port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24;
 201
 202        memset(ah_attr, 0, sizeof *ah_attr);
 203        ah_attr->type = ibah->type;
 204
 205        if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) {
 206                rdma_ah_set_dlid(ah_attr, 0);
 207                rdma_ah_set_sl(ah_attr,
 208                               be32_to_cpu(ah->av.eth.sl_tclass_flowlabel)
 209                               >> 29);
 210        } else {
 211                rdma_ah_set_dlid(ah_attr, be16_to_cpu(ah->av.ib.dlid));
 212                rdma_ah_set_sl(ah_attr,
 213                               be32_to_cpu(ah->av.ib.sl_tclass_flowlabel)
 214                               >> 28);
 215        }
 216
 217        rdma_ah_set_port_num(ah_attr, port_num);
 218        if (ah->av.ib.stat_rate)
 219                rdma_ah_set_static_rate(ah_attr,
 220                                        ah->av.ib.stat_rate -
 221                                        MLX4_STAT_RATE_OFFSET);
 222        rdma_ah_set_path_bits(ah_attr, ah->av.ib.g_slid & 0x7F);
 223        if (mlx4_ib_ah_grh_present(ah)) {
 224                u32 tc_fl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel);
 225
 226                rdma_ah_set_grh(ah_attr, NULL,
 227                                tc_fl & 0xfffff, ah->av.ib.gid_index,
 228                                ah->av.ib.hop_limit,
 229                                tc_fl >> 20);
 230                rdma_ah_set_dgid_raw(ah_attr, ah->av.ib.dgid);
 231        }
 232
 233        return 0;
 234}
 235