diff options
author | Amir Vadai <amirv@mellanox.com> | 2015-05-28 15:28:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-30 21:24:39 -0400 |
commit | afb736e9330ad6b2b6935d2f53ded784eb73f12d (patch) | |
tree | 8205643b7d5046211e0ba85ac535432bd04fc863 /drivers/net | |
parent | e586b3b0baee89f4998efd9cc97001c63e3bc744 (diff) |
net/mlx5: Ethernet resource handling files
This patch contains the resource handling files:
- flow_table.c: This file contains the code to handle the low level API
to configure hardware flow table. It is separated from
the flow_table_en.c, because it will be used in the
future by Raw Ethernet QP in mlx5_ib too.
- en_flow_table.[ch]: Ethernet flow steering handling. The flow table
object contain a mapping between flow specs and TIRs.
This mechanism will be used also to configure e-switch
in the future, when SR-IOV support will be added.
- transobj.[ch] - Low level functions to create/modify/destroy the
transport objects: RQ/SQ/TIR/TIS
- vport.[ch] - Handle attributes of a virtual port (vPort) in the
embedded switch. Currently this switch is a passthrough, until SR-IOV
support will be added.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c | 858 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/flow_table.c | 422 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 169 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/transobj.h | 47 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/vport.c | 84 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/vport.h | 41 |
6 files changed, 1621 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c new file mode 100644 index 000000000000..6feebda4b3e4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c | |||
@@ -0,0 +1,858 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015, Mellanox Technologies. 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 <linux/list.h> | ||
34 | #include <linux/ip.h> | ||
35 | #include <linux/ipv6.h> | ||
36 | #include <linux/tcp.h> | ||
37 | #include <linux/mlx5/flow_table.h> | ||
38 | #include "en.h" | ||
39 | |||
40 | enum { | ||
41 | MLX5E_FULLMATCH = 0, | ||
42 | MLX5E_ALLMULTI = 1, | ||
43 | MLX5E_PROMISC = 2, | ||
44 | }; | ||
45 | |||
46 | enum { | ||
47 | MLX5E_UC = 0, | ||
48 | MLX5E_MC_IPV4 = 1, | ||
49 | MLX5E_MC_IPV6 = 2, | ||
50 | MLX5E_MC_OTHER = 3, | ||
51 | }; | ||
52 | |||
53 | enum { | ||
54 | MLX5E_ACTION_NONE = 0, | ||
55 | MLX5E_ACTION_ADD = 1, | ||
56 | MLX5E_ACTION_DEL = 2, | ||
57 | }; | ||
58 | |||
59 | struct mlx5e_eth_addr_hash_node { | ||
60 | struct hlist_node hlist; | ||
61 | u8 action; | ||
62 | struct mlx5e_eth_addr_info ai; | ||
63 | }; | ||
64 | |||
65 | static inline int mlx5e_hash_eth_addr(u8 *addr) | ||
66 | { | ||
67 | return addr[5]; | ||
68 | } | ||
69 | |||
70 | static void mlx5e_add_eth_addr_to_hash(struct hlist_head *hash, u8 *addr) | ||
71 | { | ||
72 | struct mlx5e_eth_addr_hash_node *hn; | ||
73 | int ix = mlx5e_hash_eth_addr(addr); | ||
74 | int found = 0; | ||
75 | |||
76 | hlist_for_each_entry(hn, &hash[ix], hlist) | ||
77 | if (ether_addr_equal_64bits(hn->ai.addr, addr)) { | ||
78 | found = 1; | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | if (found) { | ||
83 | hn->action = MLX5E_ACTION_NONE; | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | hn = kzalloc(sizeof(*hn), GFP_ATOMIC); | ||
88 | if (!hn) | ||
89 | return; | ||
90 | |||
91 | ether_addr_copy(hn->ai.addr, addr); | ||
92 | hn->action = MLX5E_ACTION_ADD; | ||
93 | |||
94 | hlist_add_head(&hn->hlist, &hash[ix]); | ||
95 | } | ||
96 | |||
97 | static void mlx5e_del_eth_addr_from_hash(struct mlx5e_eth_addr_hash_node *hn) | ||
98 | { | ||
99 | hlist_del(&hn->hlist); | ||
100 | kfree(hn); | ||
101 | } | ||
102 | |||
103 | static void mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv, | ||
104 | struct mlx5e_eth_addr_info *ai) | ||
105 | { | ||
106 | void *ft = priv->ft.main; | ||
107 | |||
108 | if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP)) | ||
109 | mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]); | ||
110 | |||
111 | if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP)) | ||
112 | mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]); | ||
113 | |||
114 | if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP)) | ||
115 | mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]); | ||
116 | |||
117 | if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP)) | ||
118 | mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]); | ||
119 | |||
120 | if (ai->tt_vec & (1 << MLX5E_TT_IPV6)) | ||
121 | mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]); | ||
122 | |||
123 | if (ai->tt_vec & (1 << MLX5E_TT_IPV4)) | ||
124 | mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]); | ||
125 | |||
126 | if (ai->tt_vec & (1 << MLX5E_TT_ANY)) | ||
127 | mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]); | ||
128 | } | ||
129 | |||
130 | static int mlx5e_get_eth_addr_type(u8 *addr) | ||
131 | { | ||
132 | if (is_unicast_ether_addr(addr)) | ||
133 | return MLX5E_UC; | ||
134 | |||
135 | if ((addr[0] == 0x01) && | ||
136 | (addr[1] == 0x00) && | ||
137 | (addr[2] == 0x5e) && | ||
138 | !(addr[3] & 0x80)) | ||
139 | return MLX5E_MC_IPV4; | ||
140 | |||
141 | if ((addr[0] == 0x33) && | ||
142 | (addr[1] == 0x33)) | ||
143 | return MLX5E_MC_IPV6; | ||
144 | |||
145 | return MLX5E_MC_OTHER; | ||
146 | } | ||
147 | |||
148 | static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) | ||
149 | { | ||
150 | int eth_addr_type; | ||
151 | u32 ret; | ||
152 | |||
153 | switch (type) { | ||
154 | case MLX5E_FULLMATCH: | ||
155 | eth_addr_type = mlx5e_get_eth_addr_type(ai->addr); | ||
156 | switch (eth_addr_type) { | ||
157 | case MLX5E_UC: | ||
158 | ret = | ||
159 | (1 << MLX5E_TT_IPV4_TCP) | | ||
160 | (1 << MLX5E_TT_IPV6_TCP) | | ||
161 | (1 << MLX5E_TT_IPV4_UDP) | | ||
162 | (1 << MLX5E_TT_IPV6_UDP) | | ||
163 | (1 << MLX5E_TT_IPV4) | | ||
164 | (1 << MLX5E_TT_IPV6) | | ||
165 | (1 << MLX5E_TT_ANY) | | ||
166 | 0; | ||
167 | break; | ||
168 | |||
169 | case MLX5E_MC_IPV4: | ||
170 | ret = | ||
171 | (1 << MLX5E_TT_IPV4_UDP) | | ||
172 | (1 << MLX5E_TT_IPV4) | | ||
173 | 0; | ||
174 | break; | ||
175 | |||
176 | case MLX5E_MC_IPV6: | ||
177 | ret = | ||
178 | (1 << MLX5E_TT_IPV6_UDP) | | ||
179 | (1 << MLX5E_TT_IPV6) | | ||
180 | 0; | ||
181 | break; | ||
182 | |||
183 | case MLX5E_MC_OTHER: | ||
184 | ret = | ||
185 | (1 << MLX5E_TT_ANY) | | ||
186 | 0; | ||
187 | break; | ||
188 | } | ||
189 | |||
190 | break; | ||
191 | |||
192 | case MLX5E_ALLMULTI: | ||
193 | ret = | ||
194 | (1 << MLX5E_TT_IPV4_UDP) | | ||
195 | (1 << MLX5E_TT_IPV6_UDP) | | ||
196 | (1 << MLX5E_TT_IPV4) | | ||
197 | (1 << MLX5E_TT_IPV6) | | ||
198 | (1 << MLX5E_TT_ANY) | | ||
199 | 0; | ||
200 | break; | ||
201 | |||
202 | default: /* MLX5E_PROMISC */ | ||
203 | ret = | ||
204 | (1 << MLX5E_TT_IPV4_TCP) | | ||
205 | (1 << MLX5E_TT_IPV6_TCP) | | ||
206 | (1 << MLX5E_TT_IPV4_UDP) | | ||
207 | (1 << MLX5E_TT_IPV6_UDP) | | ||
208 | (1 << MLX5E_TT_IPV4) | | ||
209 | (1 << MLX5E_TT_IPV6) | | ||
210 | (1 << MLX5E_TT_ANY) | | ||
211 | 0; | ||
212 | break; | ||
213 | } | ||
214 | |||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, | ||
219 | struct mlx5e_eth_addr_info *ai, int type, | ||
220 | void *flow_context, void *match_criteria) | ||
221 | { | ||
222 | u8 match_criteria_enable = 0; | ||
223 | void *match_value; | ||
224 | void *dest; | ||
225 | u8 *dmac; | ||
226 | u8 *match_criteria_dmac; | ||
227 | void *ft = priv->ft.main; | ||
228 | u32 *tirn = priv->tirn; | ||
229 | u32 tt_vec; | ||
230 | int err; | ||
231 | |||
232 | match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); | ||
233 | dmac = MLX5_ADDR_OF(fte_match_param, match_value, | ||
234 | outer_headers.dmac_47_16); | ||
235 | match_criteria_dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, | ||
236 | outer_headers.dmac_47_16); | ||
237 | dest = MLX5_ADDR_OF(flow_context, flow_context, destination); | ||
238 | |||
239 | MLX5_SET(flow_context, flow_context, action, | ||
240 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST); | ||
241 | MLX5_SET(flow_context, flow_context, destination_list_size, 1); | ||
242 | MLX5_SET(dest_format_struct, dest, destination_type, | ||
243 | MLX5_FLOW_CONTEXT_DEST_TYPE_TIR); | ||
244 | |||
245 | switch (type) { | ||
246 | case MLX5E_FULLMATCH: | ||
247 | match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
248 | memset(match_criteria_dmac, 0xff, ETH_ALEN); | ||
249 | ether_addr_copy(dmac, ai->addr); | ||
250 | break; | ||
251 | |||
252 | case MLX5E_ALLMULTI: | ||
253 | match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
254 | match_criteria_dmac[0] = 0x01; | ||
255 | dmac[0] = 0x01; | ||
256 | break; | ||
257 | |||
258 | case MLX5E_PROMISC: | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | tt_vec = mlx5e_get_tt_vec(ai, type); | ||
263 | |||
264 | if (tt_vec & (1 << MLX5E_TT_ANY)) { | ||
265 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
266 | tirn[MLX5E_TT_ANY]); | ||
267 | err = mlx5_add_flow_table_entry(ft, match_criteria_enable, | ||
268 | match_criteria, flow_context, | ||
269 | &ai->ft_ix[MLX5E_TT_ANY]); | ||
270 | if (err) { | ||
271 | mlx5e_del_eth_addr_from_flow_table(priv, ai); | ||
272 | return err; | ||
273 | } | ||
274 | ai->tt_vec |= (1 << MLX5E_TT_ANY); | ||
275 | } | ||
276 | |||
277 | match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
278 | MLX5_SET_TO_ONES(fte_match_param, match_criteria, | ||
279 | outer_headers.ethertype); | ||
280 | |||
281 | if (tt_vec & (1 << MLX5E_TT_IPV4)) { | ||
282 | MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, | ||
283 | ETH_P_IP); | ||
284 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
285 | tirn[MLX5E_TT_IPV4]); | ||
286 | err = mlx5_add_flow_table_entry(ft, match_criteria_enable, | ||
287 | match_criteria, flow_context, | ||
288 | &ai->ft_ix[MLX5E_TT_IPV4]); | ||
289 | if (err) { | ||
290 | mlx5e_del_eth_addr_from_flow_table(priv, ai); | ||
291 | return err; | ||
292 | } | ||
293 | ai->tt_vec |= (1 << MLX5E_TT_IPV4); | ||
294 | } | ||
295 | |||
296 | if (tt_vec & (1 << MLX5E_TT_IPV6)) { | ||
297 | MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, | ||
298 | ETH_P_IPV6); | ||
299 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
300 | tirn[MLX5E_TT_IPV6]); | ||
301 | err = mlx5_add_flow_table_entry(ft, match_criteria_enable, | ||
302 | match_criteria, flow_context, | ||
303 | &ai->ft_ix[MLX5E_TT_IPV6]); | ||
304 | if (err) { | ||
305 | mlx5e_del_eth_addr_from_flow_table(priv, ai); | ||
306 | return err; | ||
307 | } | ||
308 | ai->tt_vec |= (1 << MLX5E_TT_IPV6); | ||
309 | } | ||
310 | |||
311 | MLX5_SET_TO_ONES(fte_match_param, match_criteria, | ||
312 | outer_headers.ip_protocol); | ||
313 | MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, | ||
314 | IPPROTO_UDP); | ||
315 | |||
316 | if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) { | ||
317 | MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, | ||
318 | ETH_P_IP); | ||
319 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
320 | tirn[MLX5E_TT_IPV4_UDP]); | ||
321 | err = mlx5_add_flow_table_entry(ft, match_criteria_enable, | ||
322 | match_criteria, flow_context, | ||
323 | &ai->ft_ix[MLX5E_TT_IPV4_UDP]); | ||
324 | if (err) { | ||
325 | mlx5e_del_eth_addr_from_flow_table(priv, ai); | ||
326 | return err; | ||
327 | } | ||
328 | ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP); | ||
329 | } | ||
330 | |||
331 | if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) { | ||
332 | MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, | ||
333 | ETH_P_IPV6); | ||
334 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
335 | tirn[MLX5E_TT_IPV6_UDP]); | ||
336 | err = mlx5_add_flow_table_entry(ft, match_criteria_enable, | ||
337 | match_criteria, flow_context, | ||
338 | &ai->ft_ix[MLX5E_TT_IPV6_UDP]); | ||
339 | if (err) { | ||
340 | mlx5e_del_eth_addr_from_flow_table(priv, ai); | ||
341 | return err; | ||
342 | } | ||
343 | ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP); | ||
344 | } | ||
345 | |||
346 | MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, | ||
347 | IPPROTO_TCP); | ||
348 | |||
349 | if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) { | ||
350 | MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, | ||
351 | ETH_P_IP); | ||
352 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
353 | tirn[MLX5E_TT_IPV4_TCP]); | ||
354 | err = mlx5_add_flow_table_entry(ft, match_criteria_enable, | ||
355 | match_criteria, flow_context, | ||
356 | &ai->ft_ix[MLX5E_TT_IPV4_TCP]); | ||
357 | if (err) { | ||
358 | mlx5e_del_eth_addr_from_flow_table(priv, ai); | ||
359 | return err; | ||
360 | } | ||
361 | ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP); | ||
362 | } | ||
363 | |||
364 | if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) { | ||
365 | MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, | ||
366 | ETH_P_IPV6); | ||
367 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
368 | tirn[MLX5E_TT_IPV6_TCP]); | ||
369 | err = mlx5_add_flow_table_entry(ft, match_criteria_enable, | ||
370 | match_criteria, flow_context, | ||
371 | &ai->ft_ix[MLX5E_TT_IPV6_TCP]); | ||
372 | if (err) { | ||
373 | mlx5e_del_eth_addr_from_flow_table(priv, ai); | ||
374 | return err; | ||
375 | } | ||
376 | ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP); | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, | ||
383 | struct mlx5e_eth_addr_info *ai, int type) | ||
384 | { | ||
385 | u32 *flow_context; | ||
386 | u32 *match_criteria; | ||
387 | int err; | ||
388 | |||
389 | flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) + | ||
390 | MLX5_ST_SZ_BYTES(dest_format_struct)); | ||
391 | match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); | ||
392 | if (!flow_context || !match_criteria) { | ||
393 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); | ||
394 | err = -ENOMEM; | ||
395 | goto add_eth_addr_rule_out; | ||
396 | } | ||
397 | |||
398 | err = __mlx5e_add_eth_addr_rule(priv, ai, type, flow_context, | ||
399 | match_criteria); | ||
400 | if (err) | ||
401 | netdev_err(priv->netdev, "%s: failed\n", __func__); | ||
402 | |||
403 | add_eth_addr_rule_out: | ||
404 | kvfree(match_criteria); | ||
405 | kvfree(flow_context); | ||
406 | return err; | ||
407 | } | ||
408 | |||
409 | enum mlx5e_vlan_rule_type { | ||
410 | MLX5E_VLAN_RULE_TYPE_UNTAGGED, | ||
411 | MLX5E_VLAN_RULE_TYPE_ANY_VID, | ||
412 | MLX5E_VLAN_RULE_TYPE_MATCH_VID, | ||
413 | }; | ||
414 | |||
415 | static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv, | ||
416 | enum mlx5e_vlan_rule_type rule_type, u16 vid) | ||
417 | { | ||
418 | u8 match_criteria_enable = 0; | ||
419 | u32 *flow_context; | ||
420 | void *match_value; | ||
421 | void *dest; | ||
422 | u32 *match_criteria; | ||
423 | u32 *ft_ix; | ||
424 | int err; | ||
425 | |||
426 | flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) + | ||
427 | MLX5_ST_SZ_BYTES(dest_format_struct)); | ||
428 | match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); | ||
429 | if (!flow_context || !match_criteria) { | ||
430 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); | ||
431 | err = -ENOMEM; | ||
432 | goto add_vlan_rule_out; | ||
433 | } | ||
434 | match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); | ||
435 | dest = MLX5_ADDR_OF(flow_context, flow_context, destination); | ||
436 | |||
437 | MLX5_SET(flow_context, flow_context, action, | ||
438 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST); | ||
439 | MLX5_SET(flow_context, flow_context, destination_list_size, 1); | ||
440 | MLX5_SET(dest_format_struct, dest, destination_type, | ||
441 | MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE); | ||
442 | MLX5_SET(dest_format_struct, dest, destination_id, | ||
443 | mlx5_get_flow_table_id(priv->ft.main)); | ||
444 | |||
445 | match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
446 | MLX5_SET_TO_ONES(fte_match_param, match_criteria, | ||
447 | outer_headers.vlan_tag); | ||
448 | |||
449 | switch (rule_type) { | ||
450 | case MLX5E_VLAN_RULE_TYPE_UNTAGGED: | ||
451 | ft_ix = &priv->vlan.untagged_rule_ft_ix; | ||
452 | break; | ||
453 | case MLX5E_VLAN_RULE_TYPE_ANY_VID: | ||
454 | ft_ix = &priv->vlan.any_vlan_rule_ft_ix; | ||
455 | MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag, | ||
456 | 1); | ||
457 | break; | ||
458 | default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */ | ||
459 | ft_ix = &priv->vlan.active_vlans_ft_ix[vid]; | ||
460 | MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag, | ||
461 | 1); | ||
462 | MLX5_SET_TO_ONES(fte_match_param, match_criteria, | ||
463 | outer_headers.first_vid); | ||
464 | MLX5_SET(fte_match_param, match_value, outer_headers.first_vid, | ||
465 | vid); | ||
466 | break; | ||
467 | } | ||
468 | |||
469 | err = mlx5_add_flow_table_entry(priv->ft.vlan, match_criteria_enable, | ||
470 | match_criteria, flow_context, ft_ix); | ||
471 | if (err) | ||
472 | netdev_err(priv->netdev, "%s: failed\n", __func__); | ||
473 | |||
474 | add_vlan_rule_out: | ||
475 | kvfree(match_criteria); | ||
476 | kvfree(flow_context); | ||
477 | return err; | ||
478 | } | ||
479 | |||
480 | static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv, | ||
481 | enum mlx5e_vlan_rule_type rule_type, u16 vid) | ||
482 | { | ||
483 | switch (rule_type) { | ||
484 | case MLX5E_VLAN_RULE_TYPE_UNTAGGED: | ||
485 | mlx5_del_flow_table_entry(priv->ft.vlan, | ||
486 | priv->vlan.untagged_rule_ft_ix); | ||
487 | break; | ||
488 | case MLX5E_VLAN_RULE_TYPE_ANY_VID: | ||
489 | mlx5_del_flow_table_entry(priv->ft.vlan, | ||
490 | priv->vlan.any_vlan_rule_ft_ix); | ||
491 | break; | ||
492 | case MLX5E_VLAN_RULE_TYPE_MATCH_VID: | ||
493 | mlx5_del_flow_table_entry(priv->ft.vlan, | ||
494 | priv->vlan.active_vlans_ft_ix[vid]); | ||
495 | break; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv) | ||
500 | { | ||
501 | WARN_ON(!mutex_is_locked(&priv->state_lock)); | ||
502 | |||
503 | if (priv->vlan.filter_disabled) { | ||
504 | priv->vlan.filter_disabled = false; | ||
505 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | ||
506 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, | ||
507 | 0); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv) | ||
512 | { | ||
513 | WARN_ON(!mutex_is_locked(&priv->state_lock)); | ||
514 | |||
515 | if (!priv->vlan.filter_disabled) { | ||
516 | priv->vlan.filter_disabled = true; | ||
517 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | ||
518 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, | ||
519 | 0); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, | ||
524 | u16 vid) | ||
525 | { | ||
526 | struct mlx5e_priv *priv = netdev_priv(dev); | ||
527 | int err = 0; | ||
528 | |||
529 | mutex_lock(&priv->state_lock); | ||
530 | |||
531 | set_bit(vid, priv->vlan.active_vlans); | ||
532 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | ||
533 | err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, | ||
534 | vid); | ||
535 | |||
536 | mutex_unlock(&priv->state_lock); | ||
537 | |||
538 | return err; | ||
539 | } | ||
540 | |||
541 | int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, | ||
542 | u16 vid) | ||
543 | { | ||
544 | struct mlx5e_priv *priv = netdev_priv(dev); | ||
545 | |||
546 | mutex_lock(&priv->state_lock); | ||
547 | |||
548 | clear_bit(vid, priv->vlan.active_vlans); | ||
549 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | ||
550 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); | ||
551 | |||
552 | mutex_unlock(&priv->state_lock); | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv) | ||
558 | { | ||
559 | u16 vid; | ||
560 | int err; | ||
561 | |||
562 | for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) { | ||
563 | err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, | ||
564 | vid); | ||
565 | if (err) | ||
566 | return err; | ||
567 | } | ||
568 | |||
569 | err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); | ||
570 | if (err) | ||
571 | return err; | ||
572 | |||
573 | if (priv->vlan.filter_disabled) { | ||
574 | err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, | ||
575 | 0); | ||
576 | if (err) | ||
577 | return err; | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv) | ||
584 | { | ||
585 | u16 vid; | ||
586 | |||
587 | if (priv->vlan.filter_disabled) | ||
588 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); | ||
589 | |||
590 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); | ||
591 | |||
592 | for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) | ||
593 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); | ||
594 | } | ||
595 | |||
596 | #define mlx5e_for_each_hash_node(hn, tmp, hash, i) \ | ||
597 | for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \ | ||
598 | hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist) | ||
599 | |||
600 | static void mlx5e_execute_action(struct mlx5e_priv *priv, | ||
601 | struct mlx5e_eth_addr_hash_node *hn) | ||
602 | { | ||
603 | switch (hn->action) { | ||
604 | case MLX5E_ACTION_ADD: | ||
605 | mlx5e_add_eth_addr_rule(priv, &hn->ai, MLX5E_FULLMATCH); | ||
606 | hn->action = MLX5E_ACTION_NONE; | ||
607 | break; | ||
608 | |||
609 | case MLX5E_ACTION_DEL: | ||
610 | mlx5e_del_eth_addr_from_flow_table(priv, &hn->ai); | ||
611 | mlx5e_del_eth_addr_from_hash(hn); | ||
612 | break; | ||
613 | } | ||
614 | } | ||
615 | |||
616 | static void mlx5e_sync_netdev_addr(struct mlx5e_priv *priv) | ||
617 | { | ||
618 | struct net_device *netdev = priv->netdev; | ||
619 | struct netdev_hw_addr *ha; | ||
620 | |||
621 | netif_addr_lock_bh(netdev); | ||
622 | |||
623 | mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_uc, | ||
624 | priv->netdev->dev_addr); | ||
625 | |||
626 | netdev_for_each_uc_addr(ha, netdev) | ||
627 | mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_uc, ha->addr); | ||
628 | |||
629 | netdev_for_each_mc_addr(ha, netdev) | ||
630 | mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_mc, ha->addr); | ||
631 | |||
632 | netif_addr_unlock_bh(netdev); | ||
633 | } | ||
634 | |||
635 | static void mlx5e_apply_netdev_addr(struct mlx5e_priv *priv) | ||
636 | { | ||
637 | struct mlx5e_eth_addr_hash_node *hn; | ||
638 | struct hlist_node *tmp; | ||
639 | int i; | ||
640 | |||
641 | mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_uc, i) | ||
642 | mlx5e_execute_action(priv, hn); | ||
643 | |||
644 | mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i) | ||
645 | mlx5e_execute_action(priv, hn); | ||
646 | } | ||
647 | |||
648 | static void mlx5e_handle_netdev_addr(struct mlx5e_priv *priv) | ||
649 | { | ||
650 | struct mlx5e_eth_addr_hash_node *hn; | ||
651 | struct hlist_node *tmp; | ||
652 | int i; | ||
653 | |||
654 | mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_uc, i) | ||
655 | hn->action = MLX5E_ACTION_DEL; | ||
656 | mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i) | ||
657 | hn->action = MLX5E_ACTION_DEL; | ||
658 | |||
659 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | ||
660 | mlx5e_sync_netdev_addr(priv); | ||
661 | |||
662 | mlx5e_apply_netdev_addr(priv); | ||
663 | } | ||
664 | |||
665 | void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv) | ||
666 | { | ||
667 | struct mlx5e_eth_addr_db *ea = &priv->eth_addr; | ||
668 | struct net_device *ndev = priv->netdev; | ||
669 | |||
670 | bool rx_mode_enable = test_bit(MLX5E_STATE_OPENED, &priv->state); | ||
671 | bool promisc_enabled = rx_mode_enable && (ndev->flags & IFF_PROMISC); | ||
672 | bool allmulti_enabled = rx_mode_enable && (ndev->flags & IFF_ALLMULTI); | ||
673 | bool broadcast_enabled = rx_mode_enable; | ||
674 | |||
675 | bool enable_promisc = !ea->promisc_enabled && promisc_enabled; | ||
676 | bool disable_promisc = ea->promisc_enabled && !promisc_enabled; | ||
677 | bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled; | ||
678 | bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled; | ||
679 | bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled; | ||
680 | bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled; | ||
681 | |||
682 | if (enable_promisc) | ||
683 | mlx5e_add_eth_addr_rule(priv, &ea->promisc, MLX5E_PROMISC); | ||
684 | if (enable_allmulti) | ||
685 | mlx5e_add_eth_addr_rule(priv, &ea->allmulti, MLX5E_ALLMULTI); | ||
686 | if (enable_broadcast) | ||
687 | mlx5e_add_eth_addr_rule(priv, &ea->broadcast, MLX5E_FULLMATCH); | ||
688 | |||
689 | mlx5e_handle_netdev_addr(priv); | ||
690 | |||
691 | if (disable_broadcast) | ||
692 | mlx5e_del_eth_addr_from_flow_table(priv, &ea->broadcast); | ||
693 | if (disable_allmulti) | ||
694 | mlx5e_del_eth_addr_from_flow_table(priv, &ea->allmulti); | ||
695 | if (disable_promisc) | ||
696 | mlx5e_del_eth_addr_from_flow_table(priv, &ea->promisc); | ||
697 | |||
698 | ea->promisc_enabled = promisc_enabled; | ||
699 | ea->allmulti_enabled = allmulti_enabled; | ||
700 | ea->broadcast_enabled = broadcast_enabled; | ||
701 | } | ||
702 | |||
703 | void mlx5e_set_rx_mode_work(struct work_struct *work) | ||
704 | { | ||
705 | struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, | ||
706 | set_rx_mode_work); | ||
707 | |||
708 | mutex_lock(&priv->state_lock); | ||
709 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | ||
710 | mlx5e_set_rx_mode_core(priv); | ||
711 | mutex_unlock(&priv->state_lock); | ||
712 | } | ||
713 | |||
714 | void mlx5e_init_eth_addr(struct mlx5e_priv *priv) | ||
715 | { | ||
716 | ether_addr_copy(priv->eth_addr.broadcast.addr, priv->netdev->broadcast); | ||
717 | } | ||
718 | |||
719 | static int mlx5e_create_main_flow_table(struct mlx5e_priv *priv) | ||
720 | { | ||
721 | struct mlx5_flow_table_group *g; | ||
722 | u8 *dmac; | ||
723 | |||
724 | g = kcalloc(9, sizeof(*g), GFP_KERNEL); | ||
725 | |||
726 | g[0].log_sz = 2; | ||
727 | g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
728 | MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, | ||
729 | outer_headers.ethertype); | ||
730 | MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, | ||
731 | outer_headers.ip_protocol); | ||
732 | |||
733 | g[1].log_sz = 1; | ||
734 | g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
735 | MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria, | ||
736 | outer_headers.ethertype); | ||
737 | |||
738 | g[2].log_sz = 0; | ||
739 | |||
740 | g[3].log_sz = 14; | ||
741 | g[3].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
742 | dmac = MLX5_ADDR_OF(fte_match_param, g[3].match_criteria, | ||
743 | outer_headers.dmac_47_16); | ||
744 | memset(dmac, 0xff, ETH_ALEN); | ||
745 | MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria, | ||
746 | outer_headers.ethertype); | ||
747 | MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria, | ||
748 | outer_headers.ip_protocol); | ||
749 | |||
750 | g[4].log_sz = 13; | ||
751 | g[4].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
752 | dmac = MLX5_ADDR_OF(fte_match_param, g[4].match_criteria, | ||
753 | outer_headers.dmac_47_16); | ||
754 | memset(dmac, 0xff, ETH_ALEN); | ||
755 | MLX5_SET_TO_ONES(fte_match_param, g[4].match_criteria, | ||
756 | outer_headers.ethertype); | ||
757 | |||
758 | g[5].log_sz = 11; | ||
759 | g[5].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
760 | dmac = MLX5_ADDR_OF(fte_match_param, g[5].match_criteria, | ||
761 | outer_headers.dmac_47_16); | ||
762 | memset(dmac, 0xff, ETH_ALEN); | ||
763 | |||
764 | g[6].log_sz = 2; | ||
765 | g[6].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
766 | dmac = MLX5_ADDR_OF(fte_match_param, g[6].match_criteria, | ||
767 | outer_headers.dmac_47_16); | ||
768 | dmac[0] = 0x01; | ||
769 | MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria, | ||
770 | outer_headers.ethertype); | ||
771 | MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria, | ||
772 | outer_headers.ip_protocol); | ||
773 | |||
774 | g[7].log_sz = 1; | ||
775 | g[7].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
776 | dmac = MLX5_ADDR_OF(fte_match_param, g[7].match_criteria, | ||
777 | outer_headers.dmac_47_16); | ||
778 | dmac[0] = 0x01; | ||
779 | MLX5_SET_TO_ONES(fte_match_param, g[7].match_criteria, | ||
780 | outer_headers.ethertype); | ||
781 | |||
782 | g[8].log_sz = 0; | ||
783 | g[8].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
784 | dmac = MLX5_ADDR_OF(fte_match_param, g[8].match_criteria, | ||
785 | outer_headers.dmac_47_16); | ||
786 | dmac[0] = 0x01; | ||
787 | priv->ft.main = mlx5_create_flow_table(priv->mdev, 1, | ||
788 | MLX5_FLOW_TABLE_TYPE_NIC_RCV, | ||
789 | 9, g); | ||
790 | kfree(g); | ||
791 | |||
792 | return priv->ft.main ? 0 : -ENOMEM; | ||
793 | } | ||
794 | |||
795 | static void mlx5e_destroy_main_flow_table(struct mlx5e_priv *priv) | ||
796 | { | ||
797 | mlx5_destroy_flow_table(priv->ft.main); | ||
798 | } | ||
799 | |||
800 | static int mlx5e_create_vlan_flow_table(struct mlx5e_priv *priv) | ||
801 | { | ||
802 | struct mlx5_flow_table_group *g; | ||
803 | |||
804 | g = kcalloc(2, sizeof(*g), GFP_KERNEL); | ||
805 | if (!g) | ||
806 | return -ENOMEM; | ||
807 | |||
808 | g[0].log_sz = 12; | ||
809 | g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
810 | MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, | ||
811 | outer_headers.vlan_tag); | ||
812 | MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, | ||
813 | outer_headers.first_vid); | ||
814 | |||
815 | /* untagged + any vlan id */ | ||
816 | g[1].log_sz = 1; | ||
817 | g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; | ||
818 | MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria, | ||
819 | outer_headers.vlan_tag); | ||
820 | |||
821 | priv->ft.vlan = mlx5_create_flow_table(priv->mdev, 0, | ||
822 | MLX5_FLOW_TABLE_TYPE_NIC_RCV, | ||
823 | 2, g); | ||
824 | |||
825 | kfree(g); | ||
826 | return priv->ft.vlan ? 0 : -ENOMEM; | ||
827 | } | ||
828 | |||
829 | static void mlx5e_destroy_vlan_flow_table(struct mlx5e_priv *priv) | ||
830 | { | ||
831 | mlx5_destroy_flow_table(priv->ft.vlan); | ||
832 | } | ||
833 | |||
834 | int mlx5e_open_flow_table(struct mlx5e_priv *priv) | ||
835 | { | ||
836 | int err; | ||
837 | |||
838 | err = mlx5e_create_main_flow_table(priv); | ||
839 | if (err) | ||
840 | return err; | ||
841 | |||
842 | err = mlx5e_create_vlan_flow_table(priv); | ||
843 | if (err) | ||
844 | goto err_destroy_main_flow_table; | ||
845 | |||
846 | return 0; | ||
847 | |||
848 | err_destroy_main_flow_table: | ||
849 | mlx5e_destroy_main_flow_table(priv); | ||
850 | |||
851 | return err; | ||
852 | } | ||
853 | |||
854 | void mlx5e_close_flow_table(struct mlx5e_priv *priv) | ||
855 | { | ||
856 | mlx5e_destroy_vlan_flow_table(priv); | ||
857 | mlx5e_destroy_main_flow_table(priv); | ||
858 | } | ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c new file mode 100644 index 000000000000..ca90b9bc3b95 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c | |||
@@ -0,0 +1,422 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. 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 <linux/export.h> | ||
34 | #include <linux/mlx5/driver.h> | ||
35 | #include <linux/mlx5/flow_table.h> | ||
36 | #include "mlx5_core.h" | ||
37 | |||
38 | struct mlx5_ftg { | ||
39 | struct mlx5_flow_table_group g; | ||
40 | u32 id; | ||
41 | u32 start_ix; | ||
42 | }; | ||
43 | |||
44 | struct mlx5_flow_table { | ||
45 | struct mlx5_core_dev *dev; | ||
46 | u8 level; | ||
47 | u8 type; | ||
48 | u32 id; | ||
49 | struct mutex mutex; /* sync bitmap alloc */ | ||
50 | u16 num_groups; | ||
51 | struct mlx5_ftg *group; | ||
52 | unsigned long *bitmap; | ||
53 | u32 size; | ||
54 | }; | ||
55 | |||
56 | static int mlx5_set_flow_entry_cmd(struct mlx5_flow_table *ft, u32 group_ix, | ||
57 | u32 flow_index, void *flow_context) | ||
58 | { | ||
59 | u32 out[MLX5_ST_SZ_DW(set_fte_out)]; | ||
60 | u32 *in; | ||
61 | void *in_flow_context; | ||
62 | int fcdls = | ||
63 | MLX5_GET(flow_context, flow_context, destination_list_size) * | ||
64 | MLX5_ST_SZ_BYTES(dest_format_struct); | ||
65 | int inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fcdls; | ||
66 | int err; | ||
67 | |||
68 | in = mlx5_vzalloc(inlen); | ||
69 | if (!in) { | ||
70 | mlx5_core_warn(ft->dev, "failed to allocate inbox\n"); | ||
71 | return -ENOMEM; | ||
72 | } | ||
73 | |||
74 | MLX5_SET(set_fte_in, in, table_type, ft->type); | ||
75 | MLX5_SET(set_fte_in, in, table_id, ft->id); | ||
76 | MLX5_SET(set_fte_in, in, flow_index, flow_index); | ||
77 | MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); | ||
78 | |||
79 | in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); | ||
80 | memcpy(in_flow_context, flow_context, | ||
81 | MLX5_ST_SZ_BYTES(flow_context) + fcdls); | ||
82 | |||
83 | MLX5_SET(flow_context, in_flow_context, group_id, | ||
84 | ft->group[group_ix].id); | ||
85 | |||
86 | memset(out, 0, sizeof(out)); | ||
87 | err = mlx5_cmd_exec_check_status(ft->dev, in, inlen, out, | ||
88 | sizeof(out)); | ||
89 | kvfree(in); | ||
90 | |||
91 | return err; | ||
92 | } | ||
93 | |||
94 | static void mlx5_del_flow_entry_cmd(struct mlx5_flow_table *ft, u32 flow_index) | ||
95 | { | ||
96 | u32 in[MLX5_ST_SZ_DW(delete_fte_in)]; | ||
97 | u32 out[MLX5_ST_SZ_DW(delete_fte_out)]; | ||
98 | |||
99 | memset(in, 0, sizeof(in)); | ||
100 | memset(out, 0, sizeof(out)); | ||
101 | |||
102 | #define MLX5_SET_DFTEI(p, x, v) MLX5_SET(delete_fte_in, p, x, v) | ||
103 | MLX5_SET_DFTEI(in, table_type, ft->type); | ||
104 | MLX5_SET_DFTEI(in, table_id, ft->id); | ||
105 | MLX5_SET_DFTEI(in, flow_index, flow_index); | ||
106 | MLX5_SET_DFTEI(in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); | ||
107 | |||
108 | mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out)); | ||
109 | } | ||
110 | |||
111 | static void mlx5_destroy_flow_group_cmd(struct mlx5_flow_table *ft, int i) | ||
112 | { | ||
113 | u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)]; | ||
114 | u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)]; | ||
115 | |||
116 | memset(in, 0, sizeof(in)); | ||
117 | memset(out, 0, sizeof(out)); | ||
118 | |||
119 | #define MLX5_SET_DFGI(p, x, v) MLX5_SET(destroy_flow_group_in, p, x, v) | ||
120 | MLX5_SET_DFGI(in, table_type, ft->type); | ||
121 | MLX5_SET_DFGI(in, table_id, ft->id); | ||
122 | MLX5_SET_DFGI(in, opcode, MLX5_CMD_OP_DESTROY_FLOW_GROUP); | ||
123 | MLX5_SET_DFGI(in, group_id, ft->group[i].id); | ||
124 | mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out)); | ||
125 | } | ||
126 | |||
127 | static int mlx5_create_flow_group_cmd(struct mlx5_flow_table *ft, int i) | ||
128 | { | ||
129 | u32 out[MLX5_ST_SZ_DW(create_flow_group_out)]; | ||
130 | u32 *in; | ||
131 | void *in_match_criteria; | ||
132 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | ||
133 | struct mlx5_flow_table_group *g = &ft->group[i].g; | ||
134 | u32 start_ix = ft->group[i].start_ix; | ||
135 | u32 end_ix = start_ix + (1 << g->log_sz) - 1; | ||
136 | int err; | ||
137 | |||
138 | in = mlx5_vzalloc(inlen); | ||
139 | if (!in) { | ||
140 | mlx5_core_warn(ft->dev, "failed to allocate inbox\n"); | ||
141 | return -ENOMEM; | ||
142 | } | ||
143 | in_match_criteria = MLX5_ADDR_OF(create_flow_group_in, in, | ||
144 | match_criteria); | ||
145 | |||
146 | memset(out, 0, sizeof(out)); | ||
147 | |||
148 | #define MLX5_SET_CFGI(p, x, v) MLX5_SET(create_flow_group_in, p, x, v) | ||
149 | MLX5_SET_CFGI(in, table_type, ft->type); | ||
150 | MLX5_SET_CFGI(in, table_id, ft->id); | ||
151 | MLX5_SET_CFGI(in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); | ||
152 | MLX5_SET_CFGI(in, start_flow_index, start_ix); | ||
153 | MLX5_SET_CFGI(in, end_flow_index, end_ix); | ||
154 | MLX5_SET_CFGI(in, match_criteria_enable, g->match_criteria_enable); | ||
155 | |||
156 | memcpy(in_match_criteria, g->match_criteria, | ||
157 | MLX5_ST_SZ_BYTES(fte_match_param)); | ||
158 | |||
159 | err = mlx5_cmd_exec_check_status(ft->dev, in, inlen, out, | ||
160 | sizeof(out)); | ||
161 | if (!err) | ||
162 | ft->group[i].id = MLX5_GET(create_flow_group_out, out, | ||
163 | group_id); | ||
164 | |||
165 | kvfree(in); | ||
166 | |||
167 | return err; | ||
168 | } | ||
169 | |||
170 | static void mlx5_destroy_flow_table_groups(struct mlx5_flow_table *ft) | ||
171 | { | ||
172 | int i; | ||
173 | |||
174 | for (i = 0; i < ft->num_groups; i++) | ||
175 | mlx5_destroy_flow_group_cmd(ft, i); | ||
176 | } | ||
177 | |||
178 | static int mlx5_create_flow_table_groups(struct mlx5_flow_table *ft) | ||
179 | { | ||
180 | int err; | ||
181 | int i; | ||
182 | |||
183 | for (i = 0; i < ft->num_groups; i++) { | ||
184 | err = mlx5_create_flow_group_cmd(ft, i); | ||
185 | if (err) | ||
186 | goto err_destroy_flow_table_groups; | ||
187 | } | ||
188 | |||
189 | return 0; | ||
190 | |||
191 | err_destroy_flow_table_groups: | ||
192 | for (i--; i >= 0; i--) | ||
193 | mlx5_destroy_flow_group_cmd(ft, i); | ||
194 | |||
195 | return err; | ||
196 | } | ||
197 | |||
198 | static int mlx5_create_flow_table_cmd(struct mlx5_flow_table *ft) | ||
199 | { | ||
200 | u32 in[MLX5_ST_SZ_DW(create_flow_table_in)]; | ||
201 | u32 out[MLX5_ST_SZ_DW(create_flow_table_out)]; | ||
202 | int err; | ||
203 | |||
204 | memset(in, 0, sizeof(in)); | ||
205 | |||
206 | MLX5_SET(create_flow_table_in, in, table_type, ft->type); | ||
207 | MLX5_SET(create_flow_table_in, in, level, ft->level); | ||
208 | MLX5_SET(create_flow_table_in, in, log_size, order_base_2(ft->size)); | ||
209 | |||
210 | MLX5_SET(create_flow_table_in, in, opcode, | ||
211 | MLX5_CMD_OP_CREATE_FLOW_TABLE); | ||
212 | |||
213 | memset(out, 0, sizeof(out)); | ||
214 | err = mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, | ||
215 | sizeof(out)); | ||
216 | if (err) | ||
217 | return err; | ||
218 | |||
219 | ft->id = MLX5_GET(create_flow_table_out, out, table_id); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static void mlx5_destroy_flow_table_cmd(struct mlx5_flow_table *ft) | ||
225 | { | ||
226 | u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)]; | ||
227 | u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)]; | ||
228 | |||
229 | memset(in, 0, sizeof(in)); | ||
230 | memset(out, 0, sizeof(out)); | ||
231 | |||
232 | #define MLX5_SET_DFTI(p, x, v) MLX5_SET(destroy_flow_table_in, p, x, v) | ||
233 | MLX5_SET_DFTI(in, table_type, ft->type); | ||
234 | MLX5_SET_DFTI(in, table_id, ft->id); | ||
235 | MLX5_SET_DFTI(in, opcode, MLX5_CMD_OP_DESTROY_FLOW_TABLE); | ||
236 | |||
237 | mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out)); | ||
238 | } | ||
239 | |||
240 | static int mlx5_find_group(struct mlx5_flow_table *ft, u8 match_criteria_enable, | ||
241 | u32 *match_criteria, int *group_ix) | ||
242 | { | ||
243 | void *mc_outer = MLX5_ADDR_OF(fte_match_param, match_criteria, | ||
244 | outer_headers); | ||
245 | void *mc_misc = MLX5_ADDR_OF(fte_match_param, match_criteria, | ||
246 | misc_parameters); | ||
247 | void *mc_inner = MLX5_ADDR_OF(fte_match_param, match_criteria, | ||
248 | inner_headers); | ||
249 | int mc_outer_sz = MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4); | ||
250 | int mc_misc_sz = MLX5_ST_SZ_BYTES(fte_match_set_misc); | ||
251 | int mc_inner_sz = MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4); | ||
252 | int i; | ||
253 | |||
254 | for (i = 0; i < ft->num_groups; i++) { | ||
255 | struct mlx5_flow_table_group *g = &ft->group[i].g; | ||
256 | void *gmc_outer = MLX5_ADDR_OF(fte_match_param, | ||
257 | g->match_criteria, | ||
258 | outer_headers); | ||
259 | void *gmc_misc = MLX5_ADDR_OF(fte_match_param, | ||
260 | g->match_criteria, | ||
261 | misc_parameters); | ||
262 | void *gmc_inner = MLX5_ADDR_OF(fte_match_param, | ||
263 | g->match_criteria, | ||
264 | inner_headers); | ||
265 | |||
266 | if (g->match_criteria_enable != match_criteria_enable) | ||
267 | continue; | ||
268 | |||
269 | if (match_criteria_enable & MLX5_MATCH_OUTER_HEADERS) | ||
270 | if (memcmp(mc_outer, gmc_outer, mc_outer_sz)) | ||
271 | continue; | ||
272 | |||
273 | if (match_criteria_enable & MLX5_MATCH_MISC_PARAMETERS) | ||
274 | if (memcmp(mc_misc, gmc_misc, mc_misc_sz)) | ||
275 | continue; | ||
276 | |||
277 | if (match_criteria_enable & MLX5_MATCH_INNER_HEADERS) | ||
278 | if (memcmp(mc_inner, gmc_inner, mc_inner_sz)) | ||
279 | continue; | ||
280 | |||
281 | *group_ix = i; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | static int alloc_flow_index(struct mlx5_flow_table *ft, int group_ix, u32 *ix) | ||
289 | { | ||
290 | struct mlx5_ftg *g = &ft->group[group_ix]; | ||
291 | int err = 0; | ||
292 | |||
293 | mutex_lock(&ft->mutex); | ||
294 | |||
295 | *ix = find_next_zero_bit(ft->bitmap, ft->size, g->start_ix); | ||
296 | if (*ix >= (g->start_ix + (1 << g->g.log_sz))) | ||
297 | err = -ENOSPC; | ||
298 | else | ||
299 | __set_bit(*ix, ft->bitmap); | ||
300 | |||
301 | mutex_unlock(&ft->mutex); | ||
302 | |||
303 | return err; | ||
304 | } | ||
305 | |||
306 | static void mlx5_free_flow_index(struct mlx5_flow_table *ft, u32 ix) | ||
307 | { | ||
308 | __clear_bit(ix, ft->bitmap); | ||
309 | } | ||
310 | |||
311 | int mlx5_add_flow_table_entry(void *flow_table, u8 match_criteria_enable, | ||
312 | void *match_criteria, void *flow_context, | ||
313 | u32 *flow_index) | ||
314 | { | ||
315 | struct mlx5_flow_table *ft = flow_table; | ||
316 | int group_ix; | ||
317 | int err; | ||
318 | |||
319 | err = mlx5_find_group(ft, match_criteria_enable, match_criteria, | ||
320 | &group_ix); | ||
321 | if (err) { | ||
322 | mlx5_core_warn(ft->dev, "mlx5_find_group failed\n"); | ||
323 | return err; | ||
324 | } | ||
325 | |||
326 | err = alloc_flow_index(ft, group_ix, flow_index); | ||
327 | if (err) { | ||
328 | mlx5_core_warn(ft->dev, "alloc_flow_index failed\n"); | ||
329 | return err; | ||
330 | } | ||
331 | |||
332 | return mlx5_set_flow_entry_cmd(ft, group_ix, *flow_index, flow_context); | ||
333 | } | ||
334 | EXPORT_SYMBOL(mlx5_add_flow_table_entry); | ||
335 | |||
336 | void mlx5_del_flow_table_entry(void *flow_table, u32 flow_index) | ||
337 | { | ||
338 | struct mlx5_flow_table *ft = flow_table; | ||
339 | |||
340 | mlx5_del_flow_entry_cmd(ft, flow_index); | ||
341 | mlx5_free_flow_index(ft, flow_index); | ||
342 | } | ||
343 | EXPORT_SYMBOL(mlx5_del_flow_table_entry); | ||
344 | |||
345 | void *mlx5_create_flow_table(struct mlx5_core_dev *dev, u8 level, u8 table_type, | ||
346 | u16 num_groups, | ||
347 | struct mlx5_flow_table_group *group) | ||
348 | { | ||
349 | struct mlx5_flow_table *ft; | ||
350 | u32 start_ix = 0; | ||
351 | u32 ft_size = 0; | ||
352 | void *gr; | ||
353 | void *bm; | ||
354 | int err; | ||
355 | int i; | ||
356 | |||
357 | for (i = 0; i < num_groups; i++) | ||
358 | ft_size += (1 << group[i].log_sz); | ||
359 | |||
360 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); | ||
361 | gr = kcalloc(num_groups, sizeof(struct mlx5_ftg), GFP_KERNEL); | ||
362 | bm = kcalloc(BITS_TO_LONGS(ft_size), sizeof(uintptr_t), GFP_KERNEL); | ||
363 | if (!ft || !gr || !bm) | ||
364 | goto err_free_ft; | ||
365 | |||
366 | ft->group = gr; | ||
367 | ft->bitmap = bm; | ||
368 | ft->num_groups = num_groups; | ||
369 | ft->level = level; | ||
370 | ft->type = table_type; | ||
371 | ft->size = ft_size; | ||
372 | ft->dev = dev; | ||
373 | mutex_init(&ft->mutex); | ||
374 | |||
375 | for (i = 0; i < ft->num_groups; i++) { | ||
376 | memcpy(&ft->group[i].g, &group[i], sizeof(*group)); | ||
377 | ft->group[i].start_ix = start_ix; | ||
378 | start_ix += 1 << group[i].log_sz; | ||
379 | } | ||
380 | |||
381 | err = mlx5_create_flow_table_cmd(ft); | ||
382 | if (err) | ||
383 | goto err_free_ft; | ||
384 | |||
385 | err = mlx5_create_flow_table_groups(ft); | ||
386 | if (err) | ||
387 | goto err_destroy_flow_table_cmd; | ||
388 | |||
389 | return ft; | ||
390 | |||
391 | err_destroy_flow_table_cmd: | ||
392 | mlx5_destroy_flow_table_cmd(ft); | ||
393 | |||
394 | err_free_ft: | ||
395 | mlx5_core_warn(dev, "failed to alloc flow table\n"); | ||
396 | kfree(bm); | ||
397 | kfree(gr); | ||
398 | kfree(ft); | ||
399 | |||
400 | return NULL; | ||
401 | } | ||
402 | EXPORT_SYMBOL(mlx5_create_flow_table); | ||
403 | |||
404 | void mlx5_destroy_flow_table(void *flow_table) | ||
405 | { | ||
406 | struct mlx5_flow_table *ft = flow_table; | ||
407 | |||
408 | mlx5_destroy_flow_table_groups(ft); | ||
409 | mlx5_destroy_flow_table_cmd(ft); | ||
410 | kfree(ft->bitmap); | ||
411 | kfree(ft->group); | ||
412 | kfree(ft); | ||
413 | } | ||
414 | EXPORT_SYMBOL(mlx5_destroy_flow_table); | ||
415 | |||
416 | u32 mlx5_get_flow_table_id(void *flow_table) | ||
417 | { | ||
418 | struct mlx5_flow_table *ft = flow_table; | ||
419 | |||
420 | return ft->id; | ||
421 | } | ||
422 | EXPORT_SYMBOL(mlx5_get_flow_table_id); | ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c new file mode 100644 index 000000000000..3c555d708af1 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. 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 <linux/mlx5/driver.h> | ||
34 | #include "mlx5_core.h" | ||
35 | #include "transobj.h" | ||
36 | |||
37 | int mlx5_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn) | ||
38 | { | ||
39 | u32 out[MLX5_ST_SZ_DW(create_rq_out)]; | ||
40 | int err; | ||
41 | |||
42 | MLX5_SET(create_rq_in, in, opcode, MLX5_CMD_OP_CREATE_RQ); | ||
43 | |||
44 | memset(out, 0, sizeof(out)); | ||
45 | err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); | ||
46 | if (!err) | ||
47 | *rqn = MLX5_GET(create_rq_out, out, rqn); | ||
48 | |||
49 | return err; | ||
50 | } | ||
51 | |||
52 | int mlx5_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen) | ||
53 | { | ||
54 | u32 out[MLX5_ST_SZ_DW(modify_rq_out)]; | ||
55 | |||
56 | MLX5_SET(modify_rq_in, in, rqn, rqn); | ||
57 | MLX5_SET(modify_rq_in, in, opcode, MLX5_CMD_OP_MODIFY_RQ); | ||
58 | |||
59 | memset(out, 0, sizeof(out)); | ||
60 | return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); | ||
61 | } | ||
62 | |||
63 | void mlx5_destroy_rq(struct mlx5_core_dev *dev, u32 rqn) | ||
64 | { | ||
65 | u32 in[MLX5_ST_SZ_DW(destroy_rq_in)]; | ||
66 | u32 out[MLX5_ST_SZ_DW(destroy_rq_out)]; | ||
67 | |||
68 | memset(in, 0, sizeof(in)); | ||
69 | |||
70 | MLX5_SET(destroy_rq_in, in, opcode, MLX5_CMD_OP_DESTROY_RQ); | ||
71 | MLX5_SET(destroy_rq_in, in, rqn, rqn); | ||
72 | |||
73 | mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); | ||
74 | } | ||
75 | |||
76 | int mlx5_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *sqn) | ||
77 | { | ||
78 | u32 out[MLX5_ST_SZ_DW(create_sq_out)]; | ||
79 | int err; | ||
80 | |||
81 | MLX5_SET(create_sq_in, in, opcode, MLX5_CMD_OP_CREATE_SQ); | ||
82 | |||
83 | memset(out, 0, sizeof(out)); | ||
84 | err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); | ||
85 | if (!err) | ||
86 | *sqn = MLX5_GET(create_sq_out, out, sqn); | ||
87 | |||
88 | return err; | ||
89 | } | ||
90 | |||
91 | int mlx5_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen) | ||
92 | { | ||
93 | u32 out[MLX5_ST_SZ_DW(modify_sq_out)]; | ||
94 | |||
95 | MLX5_SET(modify_sq_in, in, sqn, sqn); | ||
96 | MLX5_SET(modify_sq_in, in, opcode, MLX5_CMD_OP_MODIFY_SQ); | ||
97 | |||
98 | memset(out, 0, sizeof(out)); | ||
99 | return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); | ||
100 | } | ||
101 | |||
102 | void mlx5_destroy_sq(struct mlx5_core_dev *dev, u32 sqn) | ||
103 | { | ||
104 | u32 in[MLX5_ST_SZ_DW(destroy_sq_in)]; | ||
105 | u32 out[MLX5_ST_SZ_DW(destroy_sq_out)]; | ||
106 | |||
107 | memset(in, 0, sizeof(in)); | ||
108 | |||
109 | MLX5_SET(destroy_sq_in, in, opcode, MLX5_CMD_OP_DESTROY_SQ); | ||
110 | MLX5_SET(destroy_sq_in, in, sqn, sqn); | ||
111 | |||
112 | mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); | ||
113 | } | ||
114 | |||
115 | int mlx5_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tirn) | ||
116 | { | ||
117 | u32 out[MLX5_ST_SZ_DW(create_tir_out)]; | ||
118 | int err; | ||
119 | |||
120 | MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR); | ||
121 | |||
122 | memset(out, 0, sizeof(out)); | ||
123 | err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); | ||
124 | if (!err) | ||
125 | *tirn = MLX5_GET(create_tir_out, out, tirn); | ||
126 | |||
127 | return err; | ||
128 | } | ||
129 | |||
130 | void mlx5_destroy_tir(struct mlx5_core_dev *dev, u32 tirn) | ||
131 | { | ||
132 | u32 in[MLX5_ST_SZ_DW(destroy_tir_out)]; | ||
133 | u32 out[MLX5_ST_SZ_DW(destroy_tir_out)]; | ||
134 | |||
135 | memset(in, 0, sizeof(in)); | ||
136 | |||
137 | MLX5_SET(destroy_tir_in, in, opcode, MLX5_CMD_OP_DESTROY_TIR); | ||
138 | MLX5_SET(destroy_tir_in, in, tirn, tirn); | ||
139 | |||
140 | mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); | ||
141 | } | ||
142 | |||
143 | int mlx5_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tisn) | ||
144 | { | ||
145 | u32 out[MLX5_ST_SZ_DW(create_tis_out)]; | ||
146 | int err; | ||
147 | |||
148 | MLX5_SET(create_tis_in, in, opcode, MLX5_CMD_OP_CREATE_TIS); | ||
149 | |||
150 | memset(out, 0, sizeof(out)); | ||
151 | err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); | ||
152 | if (!err) | ||
153 | *tisn = MLX5_GET(create_tis_out, out, tisn); | ||
154 | |||
155 | return err; | ||
156 | } | ||
157 | |||
158 | void mlx5_destroy_tis(struct mlx5_core_dev *dev, u32 tisn) | ||
159 | { | ||
160 | u32 in[MLX5_ST_SZ_DW(destroy_tis_out)]; | ||
161 | u32 out[MLX5_ST_SZ_DW(destroy_tis_out)]; | ||
162 | |||
163 | memset(in, 0, sizeof(in)); | ||
164 | |||
165 | MLX5_SET(destroy_tis_in, in, opcode, MLX5_CMD_OP_DESTROY_TIS); | ||
166 | MLX5_SET(destroy_tis_in, in, tisn, tisn); | ||
167 | |||
168 | mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); | ||
169 | } | ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h new file mode 100644 index 000000000000..1bc898cc4933 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. 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 | #ifndef __TRANSOBJ_H__ | ||
34 | #define __TRANSOBJ_H__ | ||
35 | |||
36 | int mlx5_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn); | ||
37 | int mlx5_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen); | ||
38 | void mlx5_destroy_rq(struct mlx5_core_dev *dev, u32 rqn); | ||
39 | int mlx5_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *sqn); | ||
40 | int mlx5_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen); | ||
41 | void mlx5_destroy_sq(struct mlx5_core_dev *dev, u32 sqn); | ||
42 | int mlx5_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tirn); | ||
43 | void mlx5_destroy_tir(struct mlx5_core_dev *dev, u32 tirn); | ||
44 | int mlx5_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tisn); | ||
45 | void mlx5_destroy_tis(struct mlx5_core_dev *dev, u32 tisn); | ||
46 | |||
47 | #endif /* __TRANSOBJ_H__ */ | ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c new file mode 100644 index 000000000000..ba374b9a6c87 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. 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 <linux/export.h> | ||
34 | #include <linux/etherdevice.h> | ||
35 | #include <linux/mlx5/driver.h> | ||
36 | #include "vport.h" | ||
37 | #include "mlx5_core.h" | ||
38 | |||
39 | u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod) | ||
40 | { | ||
41 | u32 in[MLX5_ST_SZ_DW(query_vport_state_in)]; | ||
42 | u32 out[MLX5_ST_SZ_DW(query_vport_state_out)]; | ||
43 | int err; | ||
44 | |||
45 | memset(in, 0, sizeof(in)); | ||
46 | |||
47 | MLX5_SET(query_vport_state_in, in, opcode, | ||
48 | MLX5_CMD_OP_QUERY_VPORT_STATE); | ||
49 | MLX5_SET(query_vport_state_in, in, op_mod, opmod); | ||
50 | |||
51 | err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, | ||
52 | sizeof(out)); | ||
53 | if (err) | ||
54 | mlx5_core_warn(mdev, "MLX5_CMD_OP_QUERY_VPORT_STATE failed\n"); | ||
55 | |||
56 | return MLX5_GET(query_vport_state_out, out, state); | ||
57 | } | ||
58 | |||
59 | void mlx5_query_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr) | ||
60 | { | ||
61 | u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)]; | ||
62 | u32 *out; | ||
63 | int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); | ||
64 | u8 *out_addr; | ||
65 | |||
66 | out = mlx5_vzalloc(outlen); | ||
67 | if (!out) | ||
68 | return; | ||
69 | |||
70 | out_addr = MLX5_ADDR_OF(query_nic_vport_context_out, out, | ||
71 | nic_vport_context.permanent_address); | ||
72 | |||
73 | memset(in, 0, sizeof(in)); | ||
74 | |||
75 | MLX5_SET(query_nic_vport_context_in, in, opcode, | ||
76 | MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT); | ||
77 | |||
78 | memset(out, 0, outlen); | ||
79 | mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen); | ||
80 | |||
81 | ether_addr_copy(addr, &out_addr[2]); | ||
82 | |||
83 | kvfree(out); | ||
84 | } | ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.h b/drivers/net/ethernet/mellanox/mlx5/core/vport.h new file mode 100644 index 000000000000..c05ca2c3419d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. 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 | #ifndef __MLX5_VPORT_H__ | ||
34 | #define __MLX5_VPORT_H__ | ||
35 | |||
36 | #include <linux/mlx5/driver.h> | ||
37 | |||
38 | u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod); | ||
39 | void mlx5_query_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr); | ||
40 | |||
41 | #endif /* __MLX5_VPORT_H__ */ | ||