diff options
Diffstat (limited to 'drivers/infiniband/hw/mlx4/ah.c')
-rw-r--r-- | drivers/infiniband/hw/mlx4/ah.c | 163 |
1 files changed, 130 insertions, 33 deletions
diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c index 11a236f8d884..4b8f9c49397e 100644 --- a/drivers/infiniband/hw/mlx4/ah.c +++ b/drivers/infiniband/hw/mlx4/ah.c | |||
@@ -30,66 +30,163 @@ | |||
30 | * SOFTWARE. | 30 | * SOFTWARE. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <rdma/ib_addr.h> | ||
34 | #include <rdma/ib_cache.h> | ||
35 | |||
33 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/inet.h> | ||
38 | #include <linux/string.h> | ||
34 | 39 | ||
35 | #include "mlx4_ib.h" | 40 | #include "mlx4_ib.h" |
36 | 41 | ||
37 | struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | 42 | int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, |
43 | u8 *mac, int *is_mcast, u8 port) | ||
38 | { | 44 | { |
39 | struct mlx4_dev *dev = to_mdev(pd->device)->dev; | 45 | struct in6_addr in6; |
40 | struct mlx4_ib_ah *ah; | ||
41 | 46 | ||
42 | ah = kmalloc(sizeof *ah, GFP_ATOMIC); | 47 | *is_mcast = 0; |
43 | if (!ah) | ||
44 | return ERR_PTR(-ENOMEM); | ||
45 | 48 | ||
46 | memset(&ah->av, 0, sizeof ah->av); | 49 | memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6); |
50 | if (rdma_link_local_addr(&in6)) | ||
51 | rdma_get_ll_mac(&in6, mac); | ||
52 | else if (rdma_is_multicast_addr(&in6)) { | ||
53 | rdma_get_mcast_mac(&in6, mac); | ||
54 | *is_mcast = 1; | ||
55 | } else | ||
56 | return -EINVAL; | ||
47 | 57 | ||
48 | ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); | 58 | return 0; |
49 | ah->av.g_slid = ah_attr->src_path_bits; | 59 | } |
50 | ah->av.dlid = cpu_to_be16(ah_attr->dlid); | 60 | |
51 | if (ah_attr->static_rate) { | 61 | static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, |
52 | ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; | 62 | struct mlx4_ib_ah *ah) |
53 | while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && | 63 | { |
54 | !(1 << ah->av.stat_rate & dev->caps.stat_rate_support)) | 64 | struct mlx4_dev *dev = to_mdev(pd->device)->dev; |
55 | --ah->av.stat_rate; | 65 | |
56 | } | 66 | ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); |
57 | ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); | 67 | ah->av.ib.g_slid = ah_attr->src_path_bits; |
58 | if (ah_attr->ah_flags & IB_AH_GRH) { | 68 | if (ah_attr->ah_flags & IB_AH_GRH) { |
59 | ah->av.g_slid |= 0x80; | 69 | ah->av.ib.g_slid |= 0x80; |
60 | ah->av.gid_index = ah_attr->grh.sgid_index; | 70 | ah->av.ib.gid_index = ah_attr->grh.sgid_index; |
61 | ah->av.hop_limit = ah_attr->grh.hop_limit; | 71 | ah->av.ib.hop_limit = ah_attr->grh.hop_limit; |
62 | ah->av.sl_tclass_flowlabel |= | 72 | ah->av.ib.sl_tclass_flowlabel |= |
63 | cpu_to_be32((ah_attr->grh.traffic_class << 20) | | 73 | cpu_to_be32((ah_attr->grh.traffic_class << 20) | |
64 | ah_attr->grh.flow_label); | 74 | ah_attr->grh.flow_label); |
65 | memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16); | 75 | memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); |
76 | } | ||
77 | |||
78 | ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); | ||
79 | if (ah_attr->static_rate) { | ||
80 | ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; | ||
81 | while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && | ||
82 | !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) | ||
83 | --ah->av.ib.stat_rate; | ||
66 | } | 84 | } |
85 | ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); | ||
67 | 86 | ||
68 | return &ah->ibah; | 87 | return &ah->ibah; |
69 | } | 88 | } |
70 | 89 | ||
90 | static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, | ||
91 | struct mlx4_ib_ah *ah) | ||
92 | { | ||
93 | struct mlx4_ib_dev *ibdev = to_mdev(pd->device); | ||
94 | struct mlx4_dev *dev = ibdev->dev; | ||
95 | union ib_gid sgid; | ||
96 | u8 mac[6]; | ||
97 | int err; | ||
98 | int is_mcast; | ||
99 | u16 vlan_tag; | ||
100 | |||
101 | err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num); | ||
102 | if (err) | ||
103 | return ERR_PTR(err); | ||
104 | |||
105 | memcpy(ah->av.eth.mac, mac, 6); | ||
106 | err = ib_get_cached_gid(pd->device, ah_attr->port_num, ah_attr->grh.sgid_index, &sgid); | ||
107 | if (err) | ||
108 | return ERR_PTR(err); | ||
109 | vlan_tag = rdma_get_vlan_id(&sgid); | ||
110 | if (vlan_tag < 0x1000) | ||
111 | vlan_tag |= (ah_attr->sl & 7) << 13; | ||
112 | ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); | ||
113 | ah->av.eth.gid_index = ah_attr->grh.sgid_index; | ||
114 | ah->av.eth.vlan = cpu_to_be16(vlan_tag); | ||
115 | if (ah_attr->static_rate) { | ||
116 | ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; | ||
117 | while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && | ||
118 | !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support)) | ||
119 | --ah->av.eth.stat_rate; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * HW requires multicast LID so we just choose one. | ||
124 | */ | ||
125 | if (is_mcast) | ||
126 | ah->av.ib.dlid = cpu_to_be16(0xc000); | ||
127 | |||
128 | memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); | ||
129 | ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); | ||
130 | |||
131 | return &ah->ibah; | ||
132 | } | ||
133 | |||
134 | struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | ||
135 | { | ||
136 | struct mlx4_ib_ah *ah; | ||
137 | struct ib_ah *ret; | ||
138 | |||
139 | ah = kzalloc(sizeof *ah, GFP_ATOMIC); | ||
140 | if (!ah) | ||
141 | return ERR_PTR(-ENOMEM); | ||
142 | |||
143 | if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) { | ||
144 | if (!(ah_attr->ah_flags & IB_AH_GRH)) { | ||
145 | ret = ERR_PTR(-EINVAL); | ||
146 | } else { | ||
147 | /* | ||
148 | * TBD: need to handle the case when we get | ||
149 | * called in an atomic context and there we | ||
150 | * might sleep. We don't expect this | ||
151 | * currently since we're working with link | ||
152 | * local addresses which we can translate | ||
153 | * without going to sleep. | ||
154 | */ | ||
155 | ret = create_iboe_ah(pd, ah_attr, ah); | ||
156 | } | ||
157 | |||
158 | if (IS_ERR(ret)) | ||
159 | kfree(ah); | ||
160 | |||
161 | return ret; | ||
162 | } else | ||
163 | return create_ib_ah(pd, ah_attr, ah); /* never fails */ | ||
164 | } | ||
165 | |||
71 | int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) | 166 | int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) |
72 | { | 167 | { |
73 | struct mlx4_ib_ah *ah = to_mah(ibah); | 168 | struct mlx4_ib_ah *ah = to_mah(ibah); |
169 | enum rdma_link_layer ll; | ||
74 | 170 | ||
75 | memset(ah_attr, 0, sizeof *ah_attr); | 171 | memset(ah_attr, 0, sizeof *ah_attr); |
76 | ah_attr->dlid = be16_to_cpu(ah->av.dlid); | 172 | ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; |
77 | ah_attr->sl = be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28; | 173 | ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24; |
78 | ah_attr->port_num = be32_to_cpu(ah->av.port_pd) >> 24; | 174 | ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num); |
79 | if (ah->av.stat_rate) | 175 | ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0; |
80 | ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET; | 176 | if (ah->av.ib.stat_rate) |
81 | ah_attr->src_path_bits = ah->av.g_slid & 0x7F; | 177 | ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; |
178 | ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F; | ||
82 | 179 | ||
83 | if (mlx4_ib_ah_grh_present(ah)) { | 180 | if (mlx4_ib_ah_grh_present(ah)) { |
84 | ah_attr->ah_flags = IB_AH_GRH; | 181 | ah_attr->ah_flags = IB_AH_GRH; |
85 | 182 | ||
86 | ah_attr->grh.traffic_class = | 183 | ah_attr->grh.traffic_class = |
87 | be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20; | 184 | be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20; |
88 | ah_attr->grh.flow_label = | 185 | ah_attr->grh.flow_label = |
89 | be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff; | 186 | be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff; |
90 | ah_attr->grh.hop_limit = ah->av.hop_limit; | 187 | ah_attr->grh.hop_limit = ah->av.ib.hop_limit; |
91 | ah_attr->grh.sgid_index = ah->av.gid_index; | 188 | ah_attr->grh.sgid_index = ah->av.ib.gid_index; |
92 | memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, 16); | 189 | memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); |
93 | } | 190 | } |
94 | 191 | ||
95 | return 0; | 192 | return 0; |