net/mlx5: Introducing E-Switch and l2 table
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch.c
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/etherdevice.h>
34 #include <linux/mlx5/driver.h>
35 #include <linux/mlx5/mlx5_ifc.h>
36 #include <linux/mlx5/vport.h>
37 #include "mlx5_core.h"
38 #include "eswitch.h"
39
40 #define MLX5_DEBUG_ESWITCH_MASK BIT(3)
41
42 #define esw_info(dev, format, ...)                              \
43         pr_info("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
44
45 #define esw_warn(dev, format, ...)                              \
46         pr_warn("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
47
48 #define esw_debug(dev, format, ...)                             \
49         mlx5_core_dbg_mask(dev, MLX5_DEBUG_ESWITCH_MASK, format, ##__VA_ARGS__)
50
51 enum {
52         MLX5_ACTION_NONE = 0,
53         MLX5_ACTION_ADD  = 1,
54         MLX5_ACTION_DEL  = 2,
55 };
56
57 /* HW UC L2 table hash node */
58 struct mlx5_uc_l2addr {
59         struct l2addr_node node;
60         u8                 action;
61         u32                table_index;
62         u32                vport;
63 };
64
65 /* Vport UC L2 table hash node */
66 struct mlx5_vport_addr {
67         struct l2addr_node node;
68         u8                 action;
69 };
70
71 enum {
72         UC_ADDR_CHANGE = BIT(0),
73         MC_ADDR_CHANGE = BIT(1),
74 };
75
76 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, int vport,
77                                         u32 events_mask)
78 {
79         int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)];
80         int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)];
81         void *nic_vport_ctx;
82         int err;
83
84         memset(out, 0, sizeof(out));
85         memset(in, 0, sizeof(in));
86
87         MLX5_SET(modify_nic_vport_context_in, in,
88                  opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
89         MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);
90         MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
91         if (vport)
92                 MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
93         nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
94                                      in, nic_vport_context);
95
96         MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);
97
98         if (events_mask & UC_ADDR_CHANGE)
99                 MLX5_SET(nic_vport_context, nic_vport_ctx,
100                          event_on_uc_address_change, 1);
101         if (events_mask & MC_ADDR_CHANGE)
102                 MLX5_SET(nic_vport_context, nic_vport_ctx,
103                          event_on_mc_address_change, 1);
104
105         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
106         if (err)
107                 goto ex;
108         err = mlx5_cmd_status_to_err_v2(out);
109         if (err)
110                 goto ex;
111         return 0;
112 ex:
113         return err;
114 }
115
116 /* HW L2 Table (MPFS) management */
117 static int set_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index,
118                                   u8 *mac, u8 vlan_valid, u16 vlan)
119 {
120         u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)];
121         u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)];
122         u8 *in_mac_addr;
123
124         memset(in, 0, sizeof(in));
125         memset(out, 0, sizeof(out));
126
127         MLX5_SET(set_l2_table_entry_in, in, opcode,
128                  MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
129         MLX5_SET(set_l2_table_entry_in, in, table_index, index);
130         MLX5_SET(set_l2_table_entry_in, in, vlan_valid, vlan_valid);
131         MLX5_SET(set_l2_table_entry_in, in, vlan, vlan);
132
133         in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address);
134         ether_addr_copy(&in_mac_addr[2], mac);
135
136         return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
137                                           out, sizeof(out));
138 }
139
140 static int del_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
141 {
142         u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)];
143         u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)];
144
145         memset(in, 0, sizeof(in));
146         memset(out, 0, sizeof(out));
147
148         MLX5_SET(delete_l2_table_entry_in, in, opcode,
149                  MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY);
150         MLX5_SET(delete_l2_table_entry_in, in, table_index, index);
151         return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
152                                           out, sizeof(out));
153 }
154
155 static int alloc_l2_table_index(struct mlx5_l2_table *l2_table, u32 *ix)
156 {
157         int err = 0;
158
159         *ix = find_first_zero_bit(l2_table->bitmap, l2_table->size);
160         if (*ix >= l2_table->size)
161                 err = -ENOSPC;
162         else
163                 __set_bit(*ix, l2_table->bitmap);
164
165         return err;
166 }
167
168 static void free_l2_table_index(struct mlx5_l2_table *l2_table, u32 ix)
169 {
170         __clear_bit(ix, l2_table->bitmap);
171 }
172
173 static int set_l2_table_entry(struct mlx5_core_dev *dev, u8 *mac,
174                               u8 vlan_valid, u16 vlan,
175                               u32 *index)
176 {
177         struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
178         int err;
179
180         err = alloc_l2_table_index(l2_table, index);
181         if (err)
182                 return err;
183
184         err = set_l2_table_entry_cmd(dev, *index, mac, vlan_valid, vlan);
185         if (err)
186                 free_l2_table_index(l2_table, *index);
187
188         return err;
189 }
190
191 static void del_l2_table_entry(struct mlx5_core_dev *dev, u32 index)
192 {
193         struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
194
195         del_l2_table_entry_cmd(dev, index);
196         free_l2_table_index(l2_table, index);
197 }
198
199 /* SW E-Switch L2 Table management */
200 static int l2_table_addr_add(struct mlx5_eswitch *esw,
201                              u8 mac[ETH_ALEN], u32 vport)
202 {
203         struct hlist_head *hash;
204         struct mlx5_uc_l2addr *addr;
205         int err;
206
207         hash = esw->l2_table.l2_hash;
208         addr = l2addr_hash_find(hash, mac, struct mlx5_uc_l2addr);
209         if (addr) {
210                 esw_warn(esw->dev,
211                          "Failed to set L2 mac(%pM) for vport(%d), mac is already in use by vport(%d)\n",
212                          mac, vport, addr->vport);
213                 return -EEXIST;
214         }
215
216         addr = l2addr_hash_add(hash, mac, struct mlx5_uc_l2addr,
217                                GFP_KERNEL);
218         if (!addr)
219                 return -ENOMEM;
220
221         addr->vport = vport;
222         addr->action = MLX5_ACTION_NONE;
223         err = set_l2_table_entry(esw->dev, mac, 0, 0, &addr->table_index);
224         if (err)
225                 l2addr_hash_del(addr);
226         else
227                 esw_debug(esw->dev, "\tADDED L2 MAC: vport[%d] %pM index:%d\n",
228                           vport, addr->node.addr, addr->table_index);
229         return err;
230 }
231
232 static int l2_table_addr_del(struct mlx5_eswitch *esw,
233                              u8 mac[ETH_ALEN], u32 vport)
234 {
235         struct hlist_head *hash;
236         struct mlx5_uc_l2addr *addr;
237
238         hash = esw->l2_table.l2_hash;
239         addr = l2addr_hash_find(hash, mac, struct mlx5_uc_l2addr);
240         if (!addr || addr->vport != vport) {
241                 esw_warn(esw->dev, "MAC(%pM) doesn't belong to vport (%d)\n",
242                          mac, vport);
243                 return -EINVAL;
244         }
245
246         esw_debug(esw->dev, "\tDELETE L2 MAC: vport[%d] %pM index:%d\n",
247                   vport, addr->node.addr, addr->table_index);
248         del_l2_table_entry(esw->dev, addr->table_index);
249         l2addr_hash_del(addr);
250         return 0;
251 }
252
253 /* E-Switch vport uc list management */
254
255 /* Apply vport uc list to HW l2 table */
256 static void esw_apply_vport_uc_list(struct mlx5_eswitch *esw,
257                                     u32 vport_num)
258 {
259         struct mlx5_vport *vport = &esw->vports[vport_num];
260         struct mlx5_vport_addr *addr;
261         struct l2addr_node *node;
262         struct hlist_head *hash;
263         struct hlist_node *tmp;
264         int hi;
265
266         hash = vport->uc_list;
267         for_each_l2hash_node(node, tmp, hash, hi) {
268                 addr = container_of(node, struct mlx5_vport_addr, node);
269                 switch (addr->action) {
270                 case MLX5_ACTION_ADD:
271                         l2_table_addr_add(esw, addr->node.addr, vport_num);
272                         addr->action = MLX5_ACTION_NONE;
273                         break;
274                 case MLX5_ACTION_DEL:
275                         l2_table_addr_del(esw, addr->node.addr, vport_num);
276                         l2addr_hash_del(addr);
277                         break;
278                 }
279         }
280 }
281
282 /* Sync vport uc list from vport context */
283 static void esw_update_vport_uc_list(struct mlx5_eswitch *esw,
284                                      u32 vport_num)
285 {
286         struct mlx5_vport *vport = &esw->vports[vport_num];
287         struct mlx5_vport_addr *addr;
288         struct l2addr_node *node;
289         u8 (*mac_list)[ETH_ALEN];
290         struct hlist_head *hash;
291         struct hlist_node *tmp;
292         int size;
293         int err;
294         int hi;
295         int i;
296
297         size = MLX5_MAX_UC_PER_VPORT(esw->dev);
298
299         mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
300         if (!mac_list)
301                 return;
302
303         hash = vport->uc_list;
304
305         for_each_l2hash_node(node, tmp, hash, hi) {
306                 addr = container_of(node, struct mlx5_vport_addr, node);
307                 addr->action = MLX5_ACTION_DEL;
308         }
309
310         err = mlx5_query_nic_vport_mac_list(esw->dev, vport_num,
311                                             MLX5_NVPRT_LIST_TYPE_UC,
312                                             mac_list, &size);
313         if (err)
314                 return;
315         esw_debug(esw->dev, "vport[%d] context update UC list size (%d)\n",
316                   vport_num, size);
317
318         for (i = 0; i < size; i++) {
319                 if (!is_valid_ether_addr(mac_list[i]))
320                         continue;
321
322                 addr = l2addr_hash_find(hash, mac_list[i],
323                                         struct mlx5_vport_addr);
324                 if (addr) {
325                         addr->action = MLX5_ACTION_NONE;
326                         continue;
327                 }
328
329                 addr = l2addr_hash_add(hash, mac_list[i],
330                                        struct mlx5_vport_addr,
331                                        GFP_KERNEL);
332                 if (!addr) {
333                         esw_warn(esw->dev,
334                                  "Failed to add MAC(%pM) to vport[%d] DB\n",
335                                  mac_list[i], vport_num);
336                         continue;
337                 }
338                 addr->action = MLX5_ACTION_ADD;
339         }
340         kfree(mac_list);
341 }
342
343 static void esw_vport_change_handler(struct work_struct *work)
344 {
345         struct mlx5_vport *vport =
346                 container_of(work, struct mlx5_vport, vport_change_handler);
347         struct mlx5_core_dev *dev = vport->dev;
348         u8 mac[ETH_ALEN];
349
350         mlx5_query_nic_vport_mac_address(dev, vport->vport, mac);
351
352         if (!is_valid_ether_addr(mac))
353                 goto out;
354
355         esw_update_vport_uc_list(dev->priv.eswitch, vport->vport);
356         esw_apply_vport_uc_list(dev->priv.eswitch, vport->vport);
357
358 out:
359         if (vport->enabled)
360                 arm_vport_context_events_cmd(dev, vport->vport,
361                                              UC_ADDR_CHANGE);
362 }
363
364 static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num)
365 {
366         struct mlx5_vport *vport = &esw->vports[vport_num];
367         unsigned long flags;
368
369         spin_lock_irqsave(&vport->lock, flags);
370         vport->enabled = true;
371         spin_unlock_irqrestore(&vport->lock, flags);
372
373         arm_vport_context_events_cmd(esw->dev, vport_num, UC_ADDR_CHANGE);
374 }
375
376 static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
377 {
378         struct mlx5_vport *vport = &esw->vports[vport_num];
379         unsigned long flags;
380
381         if (!vport->enabled)
382                 return;
383
384         /* Mark this vport as disabled to discard new events */
385         spin_lock_irqsave(&vport->lock, flags);
386         vport->enabled = false;
387         spin_unlock_irqrestore(&vport->lock, flags);
388
389         /* Wait for current already scheduled events to complete */
390         flush_workqueue(esw->work_queue);
391
392         /* Disable events from this vport */
393         arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
394 }
395
396 /* Public E-Switch API */
397 int mlx5_eswitch_init(struct mlx5_core_dev *dev)
398 {
399         int l2_table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
400         int total_vports = 1 + pci_sriov_get_totalvfs(dev->pdev);
401         struct mlx5_eswitch *esw;
402         int vport_num;
403         int err;
404
405         if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
406             MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
407                 return 0;
408
409         esw_info(dev,
410                  "Total vports %d, l2 table size(%d), per vport: max uc(%d) max mc(%d)\n",
411                  total_vports, l2_table_size,
412                  MLX5_MAX_UC_PER_VPORT(dev),
413                  MLX5_MAX_MC_PER_VPORT(dev));
414
415         esw = kzalloc(sizeof(*esw), GFP_KERNEL);
416         if (!esw)
417                 return -ENOMEM;
418
419         esw->dev = dev;
420
421         esw->l2_table.bitmap = kcalloc(BITS_TO_LONGS(l2_table_size),
422                                    sizeof(uintptr_t), GFP_KERNEL);
423         if (!esw->l2_table.bitmap) {
424                 err = -ENOMEM;
425                 goto abort;
426         }
427         esw->l2_table.size = l2_table_size;
428
429         esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
430         if (!esw->work_queue) {
431                 err = -ENOMEM;
432                 goto abort;
433         }
434
435         esw->vports = kcalloc(total_vports, sizeof(struct mlx5_vport),
436                               GFP_KERNEL);
437         if (!esw->vports) {
438                 err = -ENOMEM;
439                 goto abort;
440         }
441
442         esw->total_vports = total_vports;
443         for (vport_num = 0; vport_num < total_vports; vport_num++) {
444                 struct mlx5_vport *vport = &esw->vports[vport_num];
445
446                 vport->vport = vport_num;
447                 vport->dev = dev;
448                 INIT_WORK(&vport->vport_change_handler,
449                           esw_vport_change_handler);
450                 spin_lock_init(&vport->lock);
451         }
452
453         dev->priv.eswitch = esw;
454
455         esw_enable_vport(esw, 0);
456         /* VF Vports will be enabled when SRIOV is enabled */
457         return 0;
458 abort:
459         if (esw->work_queue)
460                 destroy_workqueue(esw->work_queue);
461         kfree(esw->l2_table.bitmap);
462         kfree(esw->vports);
463         kfree(esw);
464         return err;
465 }
466
467 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
468 {
469         if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
470             MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
471                 return;
472
473         esw_info(esw->dev, "cleanup\n");
474         esw_disable_vport(esw, 0);
475
476         esw->dev->priv.eswitch = NULL;
477         destroy_workqueue(esw->work_queue);
478         kfree(esw->l2_table.bitmap);
479         kfree(esw->vports);
480         kfree(esw);
481 }
482
483 void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe)
484 {
485         struct mlx5_eqe_vport_change *vc_eqe = &eqe->data.vport_change;
486         u16 vport_num = be16_to_cpu(vc_eqe->vport_num);
487         struct mlx5_vport *vport;
488
489         if (!esw) {
490                 pr_warn("MLX5 E-Switch: vport %d got an event while eswitch is not initialized\n",
491                         vport_num);
492                 return;
493         }
494
495         vport = &esw->vports[vport_num];
496         spin_lock(&vport->lock);
497         if (vport->enabled)
498                 queue_work(esw->work_queue, &vport->vport_change_handler);
499         spin_unlock(&vport->lock);
500 }