Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
[linux-2.6-microblaze.git] / drivers / net / ethernet / intel / ice / ice_fltr.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2018-2020, Intel Corporation. */
3
4 #include "ice.h"
5 #include "ice_fltr.h"
6
7 /**
8  * ice_fltr_free_list - free filter lists helper
9  * @dev: pointer to the device struct
10  * @h: pointer to the list head to be freed
11  *
12  * Helper function to free filter lists previously created using
13  * ice_fltr_add_mac_to_list
14  */
15 void ice_fltr_free_list(struct device *dev, struct list_head *h)
16 {
17         struct ice_fltr_list_entry *e, *tmp;
18
19         list_for_each_entry_safe(e, tmp, h, list_entry) {
20                 list_del(&e->list_entry);
21                 devm_kfree(dev, e);
22         }
23 }
24
25 /**
26  * ice_fltr_add_entry_to_list - allocate and add filter entry to list
27  * @dev: pointer to device needed by alloc function
28  * @info: filter info struct that gets added to the passed in list
29  * @list: pointer to the list which contains MAC filters entry
30  */
31 static int
32 ice_fltr_add_entry_to_list(struct device *dev, struct ice_fltr_info *info,
33                            struct list_head *list)
34 {
35         struct ice_fltr_list_entry *entry;
36
37         entry = devm_kzalloc(dev, sizeof(*entry), GFP_ATOMIC);
38         if (!entry)
39                 return -ENOMEM;
40
41         entry->fltr_info = *info;
42
43         INIT_LIST_HEAD(&entry->list_entry);
44         list_add(&entry->list_entry, list);
45
46         return 0;
47 }
48
49 /**
50  * ice_fltr_set_vlan_vsi_promisc
51  * @hw: pointer to the hardware structure
52  * @vsi: the VSI being configured
53  * @promisc_mask: mask of promiscuous config bits
54  *
55  * Set VSI with all associated VLANs to given promiscuous mode(s)
56  */
57 int
58 ice_fltr_set_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi,
59                               u8 promisc_mask)
60 {
61         return ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, false);
62 }
63
64 /**
65  * ice_fltr_clear_vlan_vsi_promisc
66  * @hw: pointer to the hardware structure
67  * @vsi: the VSI being configured
68  * @promisc_mask: mask of promiscuous config bits
69  *
70  * Clear VSI with all associated VLANs to given promiscuous mode(s)
71  */
72 int
73 ice_fltr_clear_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi,
74                                 u8 promisc_mask)
75 {
76         return ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, true);
77 }
78
79 /**
80  * ice_fltr_clear_vsi_promisc - clear specified promiscuous mode(s)
81  * @hw: pointer to the hardware structure
82  * @vsi_handle: VSI handle to clear mode
83  * @promisc_mask: mask of promiscuous config bits to clear
84  * @vid: VLAN ID to clear VLAN promiscuous
85  */
86 int
87 ice_fltr_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
88                            u16 vid)
89 {
90         return ice_clear_vsi_promisc(hw, vsi_handle, promisc_mask, vid);
91 }
92
93 /**
94  * ice_fltr_set_vsi_promisc - set given VSI to given promiscuous mode(s)
95  * @hw: pointer to the hardware structure
96  * @vsi_handle: VSI handle to configure
97  * @promisc_mask: mask of promiscuous config bits
98  * @vid: VLAN ID to set VLAN promiscuous
99  */
100 int
101 ice_fltr_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
102                          u16 vid)
103 {
104         return ice_set_vsi_promisc(hw, vsi_handle, promisc_mask, vid);
105 }
106
107 /**
108  * ice_fltr_add_mac_list - add list of MAC filters
109  * @vsi: pointer to VSI struct
110  * @list: list of filters
111  */
112 int ice_fltr_add_mac_list(struct ice_vsi *vsi, struct list_head *list)
113 {
114         return ice_add_mac(&vsi->back->hw, list);
115 }
116
117 /**
118  * ice_fltr_remove_mac_list - remove list of MAC filters
119  * @vsi: pointer to VSI struct
120  * @list: list of filters
121  */
122 int ice_fltr_remove_mac_list(struct ice_vsi *vsi, struct list_head *list)
123 {
124         return ice_remove_mac(&vsi->back->hw, list);
125 }
126
127 /**
128  * ice_fltr_add_vlan_list - add list of VLAN filters
129  * @vsi: pointer to VSI struct
130  * @list: list of filters
131  */
132 static int ice_fltr_add_vlan_list(struct ice_vsi *vsi, struct list_head *list)
133 {
134         return ice_add_vlan(&vsi->back->hw, list);
135 }
136
137 /**
138  * ice_fltr_remove_vlan_list - remove list of VLAN filters
139  * @vsi: pointer to VSI struct
140  * @list: list of filters
141  */
142 static int
143 ice_fltr_remove_vlan_list(struct ice_vsi *vsi, struct list_head *list)
144 {
145         return ice_remove_vlan(&vsi->back->hw, list);
146 }
147
148 /**
149  * ice_fltr_add_eth_list - add list of ethertype filters
150  * @vsi: pointer to VSI struct
151  * @list: list of filters
152  */
153 static int ice_fltr_add_eth_list(struct ice_vsi *vsi, struct list_head *list)
154 {
155         return ice_add_eth_mac(&vsi->back->hw, list);
156 }
157
158 /**
159  * ice_fltr_remove_eth_list - remove list of ethertype filters
160  * @vsi: pointer to VSI struct
161  * @list: list of filters
162  */
163 static int ice_fltr_remove_eth_list(struct ice_vsi *vsi, struct list_head *list)
164 {
165         return ice_remove_eth_mac(&vsi->back->hw, list);
166 }
167
168 /**
169  * ice_fltr_remove_all - remove all filters associated with VSI
170  * @vsi: pointer to VSI struct
171  */
172 void ice_fltr_remove_all(struct ice_vsi *vsi)
173 {
174         ice_remove_vsi_fltr(&vsi->back->hw, vsi->idx);
175 }
176
177 /**
178  * ice_fltr_add_mac_to_list - add MAC filter info to exsisting list
179  * @vsi: pointer to VSI struct
180  * @list: list to add filter info to
181  * @mac: MAC address to add
182  * @action: filter action
183  */
184 int
185 ice_fltr_add_mac_to_list(struct ice_vsi *vsi, struct list_head *list,
186                          const u8 *mac, enum ice_sw_fwd_act_type action)
187 {
188         struct ice_fltr_info info = { 0 };
189
190         info.flag = ICE_FLTR_TX;
191         info.src_id = ICE_SRC_ID_VSI;
192         info.lkup_type = ICE_SW_LKUP_MAC;
193         info.fltr_act = action;
194         info.vsi_handle = vsi->idx;
195
196         ether_addr_copy(info.l_data.mac.mac_addr, mac);
197
198         return ice_fltr_add_entry_to_list(ice_pf_to_dev(vsi->back), &info,
199                                           list);
200 }
201
202 /**
203  * ice_fltr_add_vlan_to_list - add VLAN filter info to exsisting list
204  * @vsi: pointer to VSI struct
205  * @list: list to add filter info to
206  * @vlan: VLAN filter details
207  */
208 static int
209 ice_fltr_add_vlan_to_list(struct ice_vsi *vsi, struct list_head *list,
210                           struct ice_vlan *vlan)
211 {
212         struct ice_fltr_info info = { 0 };
213
214         info.flag = ICE_FLTR_TX;
215         info.src_id = ICE_SRC_ID_VSI;
216         info.lkup_type = ICE_SW_LKUP_VLAN;
217         info.fltr_act = ICE_FWD_TO_VSI;
218         info.vsi_handle = vsi->idx;
219         info.l_data.vlan.vlan_id = vlan->vid;
220         info.l_data.vlan.tpid = vlan->tpid;
221         info.l_data.vlan.tpid_valid = true;
222
223         return ice_fltr_add_entry_to_list(ice_pf_to_dev(vsi->back), &info,
224                                           list);
225 }
226
227 /**
228  * ice_fltr_add_eth_to_list - add ethertype filter info to exsisting list
229  * @vsi: pointer to VSI struct
230  * @list: list to add filter info to
231  * @ethertype: ethertype of packet that matches filter
232  * @flag: filter direction, Tx or Rx
233  * @action: filter action
234  */
235 static int
236 ice_fltr_add_eth_to_list(struct ice_vsi *vsi, struct list_head *list,
237                          u16 ethertype, u16 flag,
238                          enum ice_sw_fwd_act_type action)
239 {
240         struct ice_fltr_info info = { 0 };
241
242         info.flag = flag;
243         info.lkup_type = ICE_SW_LKUP_ETHERTYPE;
244         info.fltr_act = action;
245         info.vsi_handle = vsi->idx;
246         info.l_data.ethertype_mac.ethertype = ethertype;
247
248         if (flag == ICE_FLTR_TX)
249                 info.src_id = ICE_SRC_ID_VSI;
250         else
251                 info.src_id = ICE_SRC_ID_LPORT;
252
253         return ice_fltr_add_entry_to_list(ice_pf_to_dev(vsi->back), &info,
254                                           list);
255 }
256
257 /**
258  * ice_fltr_prepare_mac - add or remove MAC rule
259  * @vsi: pointer to VSI struct
260  * @mac: MAC address to add
261  * @action: action to be performed on filter match
262  * @mac_action: pointer to add or remove MAC function
263  */
264 static int
265 ice_fltr_prepare_mac(struct ice_vsi *vsi, const u8 *mac,
266                      enum ice_sw_fwd_act_type action,
267                      int (*mac_action)(struct ice_vsi *, struct list_head *))
268 {
269         LIST_HEAD(tmp_list);
270         int result;
271
272         if (ice_fltr_add_mac_to_list(vsi, &tmp_list, mac, action)) {
273                 ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
274                 return -ENOMEM;
275         }
276
277         result = mac_action(vsi, &tmp_list);
278         ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
279         return result;
280 }
281
282 /**
283  * ice_fltr_prepare_mac_and_broadcast - add or remove MAC and broadcast filter
284  * @vsi: pointer to VSI struct
285  * @mac: MAC address to add
286  * @action: action to be performed on filter match
287  * @mac_action: pointer to add or remove MAC function
288  */
289 static int
290 ice_fltr_prepare_mac_and_broadcast(struct ice_vsi *vsi, const u8 *mac,
291                                    enum ice_sw_fwd_act_type action,
292                                    int(*mac_action)
293                                    (struct ice_vsi *, struct list_head *))
294 {
295         u8 broadcast[ETH_ALEN];
296         LIST_HEAD(tmp_list);
297         int result;
298
299         eth_broadcast_addr(broadcast);
300         if (ice_fltr_add_mac_to_list(vsi, &tmp_list, mac, action) ||
301             ice_fltr_add_mac_to_list(vsi, &tmp_list, broadcast, action)) {
302                 ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
303                 return -ENOMEM;
304         }
305
306         result = mac_action(vsi, &tmp_list);
307         ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
308         return result;
309 }
310
311 /**
312  * ice_fltr_prepare_vlan - add or remove VLAN filter
313  * @vsi: pointer to VSI struct
314  * @vlan: VLAN filter details
315  * @vlan_action: pointer to add or remove VLAN function
316  */
317 static int
318 ice_fltr_prepare_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan,
319                       int (*vlan_action)(struct ice_vsi *, struct list_head *))
320 {
321         LIST_HEAD(tmp_list);
322         int result;
323
324         if (ice_fltr_add_vlan_to_list(vsi, &tmp_list, vlan))
325                 return -ENOMEM;
326
327         result = vlan_action(vsi, &tmp_list);
328         ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
329         return result;
330 }
331
332 /**
333  * ice_fltr_prepare_eth - add or remove ethertype filter
334  * @vsi: pointer to VSI struct
335  * @ethertype: ethertype of packet to be filtered
336  * @flag: direction of packet, Tx or Rx
337  * @action: action to be performed on filter match
338  * @eth_action: pointer to add or remove ethertype function
339  */
340 static int
341 ice_fltr_prepare_eth(struct ice_vsi *vsi, u16 ethertype, u16 flag,
342                      enum ice_sw_fwd_act_type action,
343                      int (*eth_action)(struct ice_vsi *, struct list_head *))
344 {
345         LIST_HEAD(tmp_list);
346         int result;
347
348         if (ice_fltr_add_eth_to_list(vsi, &tmp_list, ethertype, flag, action))
349                 return -ENOMEM;
350
351         result = eth_action(vsi, &tmp_list);
352         ice_fltr_free_list(ice_pf_to_dev(vsi->back), &tmp_list);
353         return result;
354 }
355
356 /**
357  * ice_fltr_add_mac - add single MAC filter
358  * @vsi: pointer to VSI struct
359  * @mac: MAC to add
360  * @action: action to be performed on filter match
361  */
362 int ice_fltr_add_mac(struct ice_vsi *vsi, const u8 *mac,
363                      enum ice_sw_fwd_act_type action)
364 {
365         return ice_fltr_prepare_mac(vsi, mac, action, ice_fltr_add_mac_list);
366 }
367
368 /**
369  * ice_fltr_add_mac_and_broadcast - add single MAC and broadcast
370  * @vsi: pointer to VSI struct
371  * @mac: MAC to add
372  * @action: action to be performed on filter match
373  */
374 int
375 ice_fltr_add_mac_and_broadcast(struct ice_vsi *vsi, const u8 *mac,
376                                enum ice_sw_fwd_act_type action)
377 {
378         return ice_fltr_prepare_mac_and_broadcast(vsi, mac, action,
379                                                   ice_fltr_add_mac_list);
380 }
381
382 /**
383  * ice_fltr_remove_mac - remove MAC filter
384  * @vsi: pointer to VSI struct
385  * @mac: filter MAC to remove
386  * @action: action to remove
387  */
388 int ice_fltr_remove_mac(struct ice_vsi *vsi, const u8 *mac,
389                         enum ice_sw_fwd_act_type action)
390 {
391         return ice_fltr_prepare_mac(vsi, mac, action, ice_fltr_remove_mac_list);
392 }
393
394 /**
395  * ice_fltr_add_vlan - add single VLAN filter
396  * @vsi: pointer to VSI struct
397  * @vlan: VLAN filter details
398  */
399 int ice_fltr_add_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
400 {
401         return ice_fltr_prepare_vlan(vsi, vlan, ice_fltr_add_vlan_list);
402 }
403
404 /**
405  * ice_fltr_remove_vlan - remove VLAN filter
406  * @vsi: pointer to VSI struct
407  * @vlan: VLAN filter details
408  */
409 int ice_fltr_remove_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
410 {
411         return ice_fltr_prepare_vlan(vsi, vlan, ice_fltr_remove_vlan_list);
412 }
413
414 /**
415  * ice_fltr_add_eth - add specyfic ethertype filter
416  * @vsi: pointer to VSI struct
417  * @ethertype: ethertype of filter
418  * @flag: direction of packet to be filtered, Tx or Rx
419  * @action: action to be performed on filter match
420  */
421 int ice_fltr_add_eth(struct ice_vsi *vsi, u16 ethertype, u16 flag,
422                      enum ice_sw_fwd_act_type action)
423 {
424         return ice_fltr_prepare_eth(vsi, ethertype, flag, action,
425                                     ice_fltr_add_eth_list);
426 }
427
428 /**
429  * ice_fltr_remove_eth - remove ethertype filter
430  * @vsi: pointer to VSI struct
431  * @ethertype: ethertype of filter
432  * @flag: direction of filter
433  * @action: action to remove
434  */
435 int ice_fltr_remove_eth(struct ice_vsi *vsi, u16 ethertype, u16 flag,
436                         enum ice_sw_fwd_act_type action)
437 {
438         return ice_fltr_prepare_eth(vsi, ethertype, flag, action,
439                                     ice_fltr_remove_eth_list);
440 }