diff options
author | Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> | 2018-03-20 10:58:12 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2018-03-26 14:00:08 -0400 |
commit | 9daf8208dd4dee4e13079bd0520a5fb8d20e8b06 (patch) | |
tree | a7560349d58b64af409dbc5d8d335d9ae0b8b2a5 | |
parent | 3a858ba392c3b19986c40a4c170ddc37b144115f (diff) |
ice: Add support for switch filter programming
A VSI needs traffic directed towards it. This is done by programming
filter rules on the switch (embedded vSwitch) element in the hardware,
which connects the VSI to the ingress/egress port.
This patch introduces data structures and functions necessary to add
remove or update switch rules on the switch element. This is a pretty low
level function that is generic enough to add a whole range of filters.
This patch also introduces two top level functions ice_add_mac and
ice_remove mac which through a series of intermediate helper functions
eventually call ice_aq_sw_rules to add/delete simple MAC based filters.
It's worth noting that one invocation of ice_add_mac/ice_remove_mac
is capable of adding/deleting multiple MAC filters.
Also worth noting is the fact that the driver maintains a list of currently
active filters, so every filter addition/removal causes an update to this
list. This is done for a couple of reasons:
1) If two VSIs try to add the same filters, we need to detect it and do
things a little differently (i.e. use VSI lists, described below) as
the same filter can't be added more than once.
2) In the event of a hardware reset we can simply walk through this list
and restore the filters.
VSI Lists:
In a multi-VSI situation, it's possible that multiple VSIs want to add the
same filter rule. For example, two VSIs that want to receive broadcast
traffic would both add a filter for destination MAC ff:ff:ff:ff:ff:ff.
This can become cumbersome to maintain and so this is handled using a
VSI list.
A VSI list is resource that can be allocated in the hardware using the
ice_aq_alloc_free_res admin queue command. Simply put, a VSI list can
be thought of as a subscription list containing a set of VSIs to which
the packet should be forwarded, should the filter match.
For example, if VSI-0 has already added a broadcast filter, and VSI-1
wants to do the same thing, the filter creation flow will detect this,
allocate a VSI list and update the switch rule so that broadcast traffic
will now be forwarded to the VSI list which contains VSI-0 and VSI-1.
Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>
Tested-by: Tony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 249 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_common.c | 74 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_main.c | 92 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_status.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_switch.c | 1378 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_switch.h | 120 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_type.h | 21 |
7 files changed, 1935 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 682e8dac72cc..9237841439da 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | |||
@@ -8,6 +8,7 @@ | |||
8 | * descriptor format. It is shared between Firmware and Software. | 8 | * descriptor format. It is shared between Firmware and Software. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #define ICE_MAX_VSI 768 | ||
11 | #define ICE_AQC_TOPO_MAX_LEVEL_NUM 0x9 | 12 | #define ICE_AQC_TOPO_MAX_LEVEL_NUM 0x9 |
12 | #define ICE_AQ_SET_MAC_FRAME_SIZE_MAX 9728 | 13 | #define ICE_AQ_SET_MAC_FRAME_SIZE_MAX 9728 |
13 | 14 | ||
@@ -191,6 +192,46 @@ struct ice_aqc_get_sw_cfg_resp { | |||
191 | struct ice_aqc_get_sw_cfg_resp_elem elements[1]; | 192 | struct ice_aqc_get_sw_cfg_resp_elem elements[1]; |
192 | }; | 193 | }; |
193 | 194 | ||
195 | /* These resource type defines are used for all switch resource | ||
196 | * commands where a resource type is required, such as: | ||
197 | * Get Resource Allocation command (indirect 0x0204) | ||
198 | * Allocate Resources command (indirect 0x0208) | ||
199 | * Free Resources command (indirect 0x0209) | ||
200 | * Get Allocated Resource Descriptors Command (indirect 0x020A) | ||
201 | */ | ||
202 | #define ICE_AQC_RES_TYPE_VSI_LIST_REP 0x03 | ||
203 | #define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE 0x04 | ||
204 | |||
205 | /* Allocate Resources command (indirect 0x0208) | ||
206 | * Free Resources command (indirect 0x0209) | ||
207 | */ | ||
208 | struct ice_aqc_alloc_free_res_cmd { | ||
209 | __le16 num_entries; /* Number of Resource entries */ | ||
210 | u8 reserved[6]; | ||
211 | __le32 addr_high; | ||
212 | __le32 addr_low; | ||
213 | }; | ||
214 | |||
215 | /* Resource descriptor */ | ||
216 | struct ice_aqc_res_elem { | ||
217 | union { | ||
218 | __le16 sw_resp; | ||
219 | __le16 flu_resp; | ||
220 | } e; | ||
221 | }; | ||
222 | |||
223 | /* Buffer for Allocate/Free Resources commands */ | ||
224 | struct ice_aqc_alloc_free_res_elem { | ||
225 | __le16 res_type; /* Types defined above cmd 0x0204 */ | ||
226 | #define ICE_AQC_RES_TYPE_SHARED_S 7 | ||
227 | #define ICE_AQC_RES_TYPE_SHARED_M (0x1 << ICE_AQC_RES_TYPE_SHARED_S) | ||
228 | #define ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_S 8 | ||
229 | #define ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_M \ | ||
230 | (0xF << ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_S) | ||
231 | __le16 num_elems; | ||
232 | struct ice_aqc_res_elem elem[1]; | ||
233 | }; | ||
234 | |||
194 | /* Add VSI (indirect 0x0210) | 235 | /* Add VSI (indirect 0x0210) |
195 | * Update VSI (indirect 0x0211) | 236 | * Update VSI (indirect 0x0211) |
196 | * Get VSI (indirect 0x0212) | 237 | * Get VSI (indirect 0x0212) |
@@ -384,6 +425,202 @@ struct ice_aqc_vsi_props { | |||
384 | u8 reserved[24]; | 425 | u8 reserved[24]; |
385 | }; | 426 | }; |
386 | 427 | ||
428 | /* Add/Update/Remove/Get switch rules (indirect 0x02A0, 0x02A1, 0x02A2, 0x02A3) | ||
429 | */ | ||
430 | struct ice_aqc_sw_rules { | ||
431 | /* ops: add switch rules, referring the number of rules. | ||
432 | * ops: update switch rules, referring the number of filters | ||
433 | * ops: remove switch rules, referring the entry index. | ||
434 | * ops: get switch rules, referring to the number of filters. | ||
435 | */ | ||
436 | __le16 num_rules_fltr_entry_index; | ||
437 | u8 reserved[6]; | ||
438 | __le32 addr_high; | ||
439 | __le32 addr_low; | ||
440 | }; | ||
441 | |||
442 | /* Add/Update/Get/Remove lookup Rx/Tx command/response entry | ||
443 | * This structures describes the lookup rules and associated actions. "index" | ||
444 | * is returned as part of a response to a successful Add command, and can be | ||
445 | * used to identify the rule for Update/Get/Remove commands. | ||
446 | */ | ||
447 | struct ice_sw_rule_lkup_rx_tx { | ||
448 | __le16 recipe_id; | ||
449 | #define ICE_SW_RECIPE_LOGICAL_PORT_FWD 10 | ||
450 | /* Source port for LOOKUP_RX and source VSI in case of LOOKUP_TX */ | ||
451 | __le16 src; | ||
452 | __le32 act; | ||
453 | |||
454 | /* Bit 0:1 - Action type */ | ||
455 | #define ICE_SINGLE_ACT_TYPE_S 0x00 | ||
456 | #define ICE_SINGLE_ACT_TYPE_M (0x3 << ICE_SINGLE_ACT_TYPE_S) | ||
457 | |||
458 | /* Bit 2 - Loop back enable | ||
459 | * Bit 3 - LAN enable | ||
460 | */ | ||
461 | #define ICE_SINGLE_ACT_LB_ENABLE BIT(2) | ||
462 | #define ICE_SINGLE_ACT_LAN_ENABLE BIT(3) | ||
463 | |||
464 | /* Action type = 0 - Forward to VSI or VSI list */ | ||
465 | #define ICE_SINGLE_ACT_VSI_FORWARDING 0x0 | ||
466 | |||
467 | #define ICE_SINGLE_ACT_VSI_ID_S 4 | ||
468 | #define ICE_SINGLE_ACT_VSI_ID_M (0x3FF << ICE_SINGLE_ACT_VSI_ID_S) | ||
469 | #define ICE_SINGLE_ACT_VSI_LIST_ID_S 4 | ||
470 | #define ICE_SINGLE_ACT_VSI_LIST_ID_M (0x3FF << ICE_SINGLE_ACT_VSI_LIST_ID_S) | ||
471 | /* This bit needs to be set if action is forward to VSI list */ | ||
472 | #define ICE_SINGLE_ACT_VSI_LIST BIT(14) | ||
473 | #define ICE_SINGLE_ACT_VALID_BIT BIT(17) | ||
474 | #define ICE_SINGLE_ACT_DROP BIT(18) | ||
475 | |||
476 | /* Action type = 1 - Forward to Queue of Queue group */ | ||
477 | #define ICE_SINGLE_ACT_TO_Q 0x1 | ||
478 | #define ICE_SINGLE_ACT_Q_INDEX_S 4 | ||
479 | #define ICE_SINGLE_ACT_Q_INDEX_M (0x7FF << ICE_SINGLE_ACT_Q_INDEX_S) | ||
480 | #define ICE_SINGLE_ACT_Q_REGION_S 15 | ||
481 | #define ICE_SINGLE_ACT_Q_REGION_M (0x7 << ICE_SINGLE_ACT_Q_REGION_S) | ||
482 | #define ICE_SINGLE_ACT_Q_PRIORITY BIT(18) | ||
483 | |||
484 | /* Action type = 2 - Prune */ | ||
485 | #define ICE_SINGLE_ACT_PRUNE 0x2 | ||
486 | #define ICE_SINGLE_ACT_EGRESS BIT(15) | ||
487 | #define ICE_SINGLE_ACT_INGRESS BIT(16) | ||
488 | #define ICE_SINGLE_ACT_PRUNET BIT(17) | ||
489 | /* Bit 18 should be set to 0 for this action */ | ||
490 | |||
491 | /* Action type = 2 - Pointer */ | ||
492 | #define ICE_SINGLE_ACT_PTR 0x2 | ||
493 | #define ICE_SINGLE_ACT_PTR_VAL_S 4 | ||
494 | #define ICE_SINGLE_ACT_PTR_VAL_M (0x1FFF << ICE_SINGLE_ACT_PTR_VAL_S) | ||
495 | /* Bit 18 should be set to 1 */ | ||
496 | #define ICE_SINGLE_ACT_PTR_BIT BIT(18) | ||
497 | |||
498 | /* Action type = 3 - Other actions. Last two bits | ||
499 | * are other action identifier | ||
500 | */ | ||
501 | #define ICE_SINGLE_ACT_OTHER_ACTS 0x3 | ||
502 | #define ICE_SINGLE_OTHER_ACT_IDENTIFIER_S 17 | ||
503 | #define ICE_SINGLE_OTHER_ACT_IDENTIFIER_M \ | ||
504 | (0x3 << \ ICE_SINGLE_OTHER_ACT_IDENTIFIER_S) | ||
505 | |||
506 | /* Bit 17:18 - Defines other actions */ | ||
507 | /* Other action = 0 - Mirror VSI */ | ||
508 | #define ICE_SINGLE_OTHER_ACT_MIRROR 0 | ||
509 | #define ICE_SINGLE_ACT_MIRROR_VSI_ID_S 4 | ||
510 | #define ICE_SINGLE_ACT_MIRROR_VSI_ID_M \ | ||
511 | (0x3FF << ICE_SINGLE_ACT_MIRROR_VSI_ID_S) | ||
512 | |||
513 | /* Other action = 3 - Set Stat count */ | ||
514 | #define ICE_SINGLE_OTHER_ACT_STAT_COUNT 3 | ||
515 | #define ICE_SINGLE_ACT_STAT_COUNT_INDEX_S 4 | ||
516 | #define ICE_SINGLE_ACT_STAT_COUNT_INDEX_M \ | ||
517 | (0x7F << ICE_SINGLE_ACT_STAT_COUNT_INDEX_S) | ||
518 | |||
519 | __le16 index; /* The index of the rule in the lookup table */ | ||
520 | /* Length and values of the header to be matched per recipe or | ||
521 | * lookup-type | ||
522 | */ | ||
523 | __le16 hdr_len; | ||
524 | u8 hdr[1]; | ||
525 | } __packed; | ||
526 | |||
527 | /* Add/Update/Remove large action command/response entry | ||
528 | * "index" is returned as part of a response to a successful Add command, and | ||
529 | * can be used to identify the action for Update/Get/Remove commands. | ||
530 | */ | ||
531 | struct ice_sw_rule_lg_act { | ||
532 | __le16 index; /* Index in large action table */ | ||
533 | __le16 size; | ||
534 | __le32 act[1]; /* array of size for actions */ | ||
535 | /* Max number of large actions */ | ||
536 | #define ICE_MAX_LG_ACT 4 | ||
537 | /* Bit 0:1 - Action type */ | ||
538 | #define ICE_LG_ACT_TYPE_S 0 | ||
539 | #define ICE_LG_ACT_TYPE_M (0x7 << ICE_LG_ACT_TYPE_S) | ||
540 | |||
541 | /* Action type = 0 - Forward to VSI or VSI list */ | ||
542 | #define ICE_LG_ACT_VSI_FORWARDING 0 | ||
543 | #define ICE_LG_ACT_VSI_ID_S 3 | ||
544 | #define ICE_LG_ACT_VSI_ID_M (0x3FF << ICE_LG_ACT_VSI_ID_S) | ||
545 | #define ICE_LG_ACT_VSI_LIST_ID_S 3 | ||
546 | #define ICE_LG_ACT_VSI_LIST_ID_M (0x3FF << ICE_LG_ACT_VSI_LIST_ID_S) | ||
547 | /* This bit needs to be set if action is forward to VSI list */ | ||
548 | #define ICE_LG_ACT_VSI_LIST BIT(13) | ||
549 | |||
550 | #define ICE_LG_ACT_VALID_BIT BIT(16) | ||
551 | |||
552 | /* Action type = 1 - Forward to Queue of Queue group */ | ||
553 | #define ICE_LG_ACT_TO_Q 0x1 | ||
554 | #define ICE_LG_ACT_Q_INDEX_S 3 | ||
555 | #define ICE_LG_ACT_Q_INDEX_M (0x7FF << ICE_LG_ACT_Q_INDEX_S) | ||
556 | #define ICE_LG_ACT_Q_REGION_S 14 | ||
557 | #define ICE_LG_ACT_Q_REGION_M (0x7 << ICE_LG_ACT_Q_REGION_S) | ||
558 | #define ICE_LG_ACT_Q_PRIORITY_SET BIT(17) | ||
559 | |||
560 | /* Action type = 2 - Prune */ | ||
561 | #define ICE_LG_ACT_PRUNE 0x2 | ||
562 | #define ICE_LG_ACT_EGRESS BIT(14) | ||
563 | #define ICE_LG_ACT_INGRESS BIT(15) | ||
564 | #define ICE_LG_ACT_PRUNET BIT(16) | ||
565 | |||
566 | /* Action type = 3 - Mirror VSI */ | ||
567 | #define ICE_LG_OTHER_ACT_MIRROR 0x3 | ||
568 | #define ICE_LG_ACT_MIRROR_VSI_ID_S 3 | ||
569 | #define ICE_LG_ACT_MIRROR_VSI_ID_M (0x3FF << ICE_LG_ACT_MIRROR_VSI_ID_S) | ||
570 | |||
571 | /* Action type = 5 - Large Action */ | ||
572 | #define ICE_LG_ACT_GENERIC 0x5 | ||
573 | #define ICE_LG_ACT_GENERIC_VALUE_S 3 | ||
574 | #define ICE_LG_ACT_GENERIC_VALUE_M (0xFFFF << ICE_LG_ACT_GENERIC_VALUE_S) | ||
575 | #define ICE_LG_ACT_GENERIC_OFFSET_S 19 | ||
576 | #define ICE_LG_ACT_GENERIC_OFFSET_M (0x7 << ICE_LG_ACT_GENERIC_OFFSET_S) | ||
577 | #define ICE_LG_ACT_GENERIC_PRIORITY_S 22 | ||
578 | #define ICE_LG_ACT_GENERIC_PRIORITY_M (0x7 << ICE_LG_ACT_GENERIC_PRIORITY_S) | ||
579 | |||
580 | /* Action = 7 - Set Stat count */ | ||
581 | #define ICE_LG_ACT_STAT_COUNT 0x7 | ||
582 | #define ICE_LG_ACT_STAT_COUNT_S 3 | ||
583 | #define ICE_LG_ACT_STAT_COUNT_M (0x7F << ICE_LG_ACT_STAT_COUNT_S) | ||
584 | }; | ||
585 | |||
586 | /* Add/Update/Remove VSI list command/response entry | ||
587 | * "index" is returned as part of a response to a successful Add command, and | ||
588 | * can be used to identify the VSI list for Update/Get/Remove commands. | ||
589 | */ | ||
590 | struct ice_sw_rule_vsi_list { | ||
591 | __le16 index; /* Index of VSI/Prune list */ | ||
592 | __le16 number_vsi; | ||
593 | __le16 vsi[1]; /* Array of number_vsi VSI numbers */ | ||
594 | }; | ||
595 | |||
596 | /* Query VSI list command/response entry */ | ||
597 | struct ice_sw_rule_vsi_list_query { | ||
598 | __le16 index; | ||
599 | DECLARE_BITMAP(vsi_list, ICE_MAX_VSI); | ||
600 | } __packed; | ||
601 | |||
602 | /* Add switch rule response: | ||
603 | * Content of return buffer is same as the input buffer. The status field and | ||
604 | * LUT index are updated as part of the response | ||
605 | */ | ||
606 | struct ice_aqc_sw_rules_elem { | ||
607 | __le16 type; /* Switch rule type, one of T_... */ | ||
608 | #define ICE_AQC_SW_RULES_T_LKUP_RX 0x0 | ||
609 | #define ICE_AQC_SW_RULES_T_LKUP_TX 0x1 | ||
610 | #define ICE_AQC_SW_RULES_T_LG_ACT 0x2 | ||
611 | #define ICE_AQC_SW_RULES_T_VSI_LIST_SET 0x3 | ||
612 | #define ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR 0x4 | ||
613 | #define ICE_AQC_SW_RULES_T_PRUNE_LIST_SET 0x5 | ||
614 | #define ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR 0x6 | ||
615 | __le16 status; | ||
616 | union { | ||
617 | struct ice_sw_rule_lkup_rx_tx lkup_tx_rx; | ||
618 | struct ice_sw_rule_lg_act lg_act; | ||
619 | struct ice_sw_rule_vsi_list vsi_list; | ||
620 | struct ice_sw_rule_vsi_list_query vsi_list_query; | ||
621 | } __packed pdata; | ||
622 | }; | ||
623 | |||
387 | /* Get Default Topology (indirect 0x0400) */ | 624 | /* Get Default Topology (indirect 0x0400) */ |
388 | struct ice_aqc_get_topo { | 625 | struct ice_aqc_get_topo { |
389 | u8 port_num; | 626 | u8 port_num; |
@@ -766,11 +1003,13 @@ struct ice_aq_desc { | |||
766 | struct ice_aqc_list_caps get_cap; | 1003 | struct ice_aqc_list_caps get_cap; |
767 | struct ice_aqc_get_phy_caps get_phy; | 1004 | struct ice_aqc_get_phy_caps get_phy; |
768 | struct ice_aqc_get_sw_cfg get_sw_conf; | 1005 | struct ice_aqc_get_sw_cfg get_sw_conf; |
1006 | struct ice_aqc_sw_rules sw_rules; | ||
769 | struct ice_aqc_get_topo get_topo; | 1007 | struct ice_aqc_get_topo get_topo; |
770 | struct ice_aqc_query_txsched_res query_sched_res; | 1008 | struct ice_aqc_query_txsched_res query_sched_res; |
771 | struct ice_aqc_add_move_delete_elem add_move_delete_elem; | 1009 | struct ice_aqc_add_move_delete_elem add_move_delete_elem; |
772 | struct ice_aqc_nvm nvm; | 1010 | struct ice_aqc_nvm nvm; |
773 | struct ice_aqc_add_get_update_free_vsi vsi_cmd; | 1011 | struct ice_aqc_add_get_update_free_vsi vsi_cmd; |
1012 | struct ice_aqc_alloc_free_res_cmd sw_res_ctrl; | ||
774 | struct ice_aqc_get_link_status get_link_status; | 1013 | struct ice_aqc_get_link_status get_link_status; |
775 | } params; | 1014 | } params; |
776 | }; | 1015 | }; |
@@ -821,10 +1060,20 @@ enum ice_adminq_opc { | |||
821 | /* internal switch commands */ | 1060 | /* internal switch commands */ |
822 | ice_aqc_opc_get_sw_cfg = 0x0200, | 1061 | ice_aqc_opc_get_sw_cfg = 0x0200, |
823 | 1062 | ||
1063 | /* Alloc/Free/Get Resources */ | ||
1064 | ice_aqc_opc_alloc_res = 0x0208, | ||
1065 | ice_aqc_opc_free_res = 0x0209, | ||
1066 | |||
824 | /* VSI commands */ | 1067 | /* VSI commands */ |
825 | ice_aqc_opc_add_vsi = 0x0210, | 1068 | ice_aqc_opc_add_vsi = 0x0210, |
826 | ice_aqc_opc_update_vsi = 0x0211, | 1069 | ice_aqc_opc_update_vsi = 0x0211, |
827 | ice_aqc_opc_free_vsi = 0x0213, | 1070 | ice_aqc_opc_free_vsi = 0x0213, |
1071 | |||
1072 | /* switch rules population commands */ | ||
1073 | ice_aqc_opc_add_sw_rules = 0x02A0, | ||
1074 | ice_aqc_opc_update_sw_rules = 0x02A1, | ||
1075 | ice_aqc_opc_remove_sw_rules = 0x02A2, | ||
1076 | |||
828 | ice_aqc_opc_clear_pf_cfg = 0x02A4, | 1077 | ice_aqc_opc_clear_pf_cfg = 0x02A4, |
829 | 1078 | ||
830 | /* transmit scheduler commands */ | 1079 | /* transmit scheduler commands */ |
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index a4ce8a87fb0d..67301fe75482 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c | |||
@@ -259,6 +259,66 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, | |||
259 | } | 259 | } |
260 | 260 | ||
261 | /** | 261 | /** |
262 | * ice_init_fltr_mgmt_struct - initializes filter management list and locks | ||
263 | * @hw: pointer to the hw struct | ||
264 | */ | ||
265 | static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw) | ||
266 | { | ||
267 | struct ice_switch_info *sw; | ||
268 | |||
269 | hw->switch_info = devm_kzalloc(ice_hw_to_dev(hw), | ||
270 | sizeof(*hw->switch_info), GFP_KERNEL); | ||
271 | sw = hw->switch_info; | ||
272 | |||
273 | if (!sw) | ||
274 | return ICE_ERR_NO_MEMORY; | ||
275 | |||
276 | INIT_LIST_HEAD(&sw->vsi_list_map_head); | ||
277 | |||
278 | mutex_init(&sw->mac_list_lock); | ||
279 | INIT_LIST_HEAD(&sw->mac_list_head); | ||
280 | |||
281 | mutex_init(&sw->vlan_list_lock); | ||
282 | INIT_LIST_HEAD(&sw->vlan_list_head); | ||
283 | |||
284 | mutex_init(&sw->eth_m_list_lock); | ||
285 | INIT_LIST_HEAD(&sw->eth_m_list_head); | ||
286 | |||
287 | mutex_init(&sw->promisc_list_lock); | ||
288 | INIT_LIST_HEAD(&sw->promisc_list_head); | ||
289 | |||
290 | mutex_init(&sw->mac_vlan_list_lock); | ||
291 | INIT_LIST_HEAD(&sw->mac_vlan_list_head); | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * ice_cleanup_fltr_mgmt_struct - cleanup filter management list and locks | ||
298 | * @hw: pointer to the hw struct | ||
299 | */ | ||
300 | static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw) | ||
301 | { | ||
302 | struct ice_switch_info *sw = hw->switch_info; | ||
303 | struct ice_vsi_list_map_info *v_pos_map; | ||
304 | struct ice_vsi_list_map_info *v_tmp_map; | ||
305 | |||
306 | list_for_each_entry_safe(v_pos_map, v_tmp_map, &sw->vsi_list_map_head, | ||
307 | list_entry) { | ||
308 | list_del(&v_pos_map->list_entry); | ||
309 | devm_kfree(ice_hw_to_dev(hw), v_pos_map); | ||
310 | } | ||
311 | |||
312 | mutex_destroy(&sw->mac_list_lock); | ||
313 | mutex_destroy(&sw->vlan_list_lock); | ||
314 | mutex_destroy(&sw->eth_m_list_lock); | ||
315 | mutex_destroy(&sw->promisc_list_lock); | ||
316 | mutex_destroy(&sw->mac_vlan_list_lock); | ||
317 | |||
318 | devm_kfree(ice_hw_to_dev(hw), sw); | ||
319 | } | ||
320 | |||
321 | /** | ||
262 | * ice_init_hw - main hardware initialization routine | 322 | * ice_init_hw - main hardware initialization routine |
263 | * @hw: pointer to the hardware structure | 323 | * @hw: pointer to the hardware structure |
264 | */ | 324 | */ |
@@ -321,6 +381,8 @@ enum ice_status ice_init_hw(struct ice_hw *hw) | |||
321 | if (status) | 381 | if (status) |
322 | goto err_unroll_alloc; | 382 | goto err_unroll_alloc; |
323 | 383 | ||
384 | hw->evb_veb = true; | ||
385 | |||
324 | /* Query the allocated resources for tx scheduler */ | 386 | /* Query the allocated resources for tx scheduler */ |
325 | status = ice_sched_query_res_alloc(hw); | 387 | status = ice_sched_query_res_alloc(hw); |
326 | if (status) { | 388 | if (status) { |
@@ -352,21 +414,27 @@ enum ice_status ice_init_hw(struct ice_hw *hw) | |||
352 | if (status) | 414 | if (status) |
353 | goto err_unroll_sched; | 415 | goto err_unroll_sched; |
354 | 416 | ||
417 | status = ice_init_fltr_mgmt_struct(hw); | ||
418 | if (status) | ||
419 | goto err_unroll_sched; | ||
420 | |||
355 | /* Get port MAC information */ | 421 | /* Get port MAC information */ |
356 | mac_buf_len = sizeof(struct ice_aqc_manage_mac_read_resp); | 422 | mac_buf_len = sizeof(struct ice_aqc_manage_mac_read_resp); |
357 | mac_buf = devm_kzalloc(ice_hw_to_dev(hw), mac_buf_len, GFP_KERNEL); | 423 | mac_buf = devm_kzalloc(ice_hw_to_dev(hw), mac_buf_len, GFP_KERNEL); |
358 | 424 | ||
359 | if (!mac_buf) | 425 | if (!mac_buf) |
360 | goto err_unroll_sched; | 426 | goto err_unroll_fltr_mgmt_struct; |
361 | 427 | ||
362 | status = ice_aq_manage_mac_read(hw, mac_buf, mac_buf_len, NULL); | 428 | status = ice_aq_manage_mac_read(hw, mac_buf, mac_buf_len, NULL); |
363 | devm_kfree(ice_hw_to_dev(hw), mac_buf); | 429 | devm_kfree(ice_hw_to_dev(hw), mac_buf); |
364 | 430 | ||
365 | if (status) | 431 | if (status) |
366 | goto err_unroll_sched; | 432 | goto err_unroll_fltr_mgmt_struct; |
367 | 433 | ||
368 | return 0; | 434 | return 0; |
369 | 435 | ||
436 | err_unroll_fltr_mgmt_struct: | ||
437 | ice_cleanup_fltr_mgmt_struct(hw); | ||
370 | err_unroll_sched: | 438 | err_unroll_sched: |
371 | ice_sched_cleanup_all(hw); | 439 | ice_sched_cleanup_all(hw); |
372 | err_unroll_alloc: | 440 | err_unroll_alloc: |
@@ -389,6 +457,8 @@ void ice_deinit_hw(struct ice_hw *hw) | |||
389 | devm_kfree(ice_hw_to_dev(hw), hw->port_info); | 457 | devm_kfree(ice_hw_to_dev(hw), hw->port_info); |
390 | hw->port_info = NULL; | 458 | hw->port_info = NULL; |
391 | } | 459 | } |
460 | |||
461 | ice_cleanup_fltr_mgmt_struct(hw); | ||
392 | } | 462 | } |
393 | 463 | ||
394 | /** | 464 | /** |
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 04e004ba2067..3b4a2691ddac 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c | |||
@@ -163,6 +163,57 @@ static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id) | |||
163 | } | 163 | } |
164 | 164 | ||
165 | /** | 165 | /** |
166 | * ice_add_mac_to_list - Add a mac address filter entry to the list | ||
167 | * @vsi: the VSI to be forwarded to | ||
168 | * @add_list: pointer to the list which contains MAC filter entries | ||
169 | * @macaddr: the MAC address to be added. | ||
170 | * | ||
171 | * Adds mac address filter entry to the temp list | ||
172 | * | ||
173 | * Returns 0 on success or ENOMEM on failure. | ||
174 | */ | ||
175 | static int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, | ||
176 | const u8 *macaddr) | ||
177 | { | ||
178 | struct ice_fltr_list_entry *tmp; | ||
179 | struct ice_pf *pf = vsi->back; | ||
180 | |||
181 | tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC); | ||
182 | if (!tmp) | ||
183 | return -ENOMEM; | ||
184 | |||
185 | tmp->fltr_info.flag = ICE_FLTR_TX; | ||
186 | tmp->fltr_info.src = vsi->vsi_num; | ||
187 | tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC; | ||
188 | tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; | ||
189 | tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; | ||
190 | ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr); | ||
191 | |||
192 | INIT_LIST_HEAD(&tmp->list_entry); | ||
193 | list_add(&tmp->list_entry, add_list); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * ice_free_fltr_list - free filter lists helper | ||
200 | * @dev: pointer to the device struct | ||
201 | * @h: pointer to the list head to be freed | ||
202 | * | ||
203 | * Helper function to free filter lists previously created using | ||
204 | * ice_add_mac_to_list | ||
205 | */ | ||
206 | static void ice_free_fltr_list(struct device *dev, struct list_head *h) | ||
207 | { | ||
208 | struct ice_fltr_list_entry *e, *tmp; | ||
209 | |||
210 | list_for_each_entry_safe(e, tmp, h, list_entry) { | ||
211 | list_del(&e->list_entry); | ||
212 | devm_kfree(dev, e); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | /** | ||
166 | * __ice_clean_ctrlq - helper function to clean controlq rings | 217 | * __ice_clean_ctrlq - helper function to clean controlq rings |
167 | * @pf: ptr to struct ice_pf | 218 | * @pf: ptr to struct ice_pf |
168 | * @q_type: specific Control queue type | 219 | * @q_type: specific Control queue type |
@@ -1519,6 +1570,8 @@ err_get_qs: | |||
1519 | */ | 1570 | */ |
1520 | static int ice_setup_pf_sw(struct ice_pf *pf) | 1571 | static int ice_setup_pf_sw(struct ice_pf *pf) |
1521 | { | 1572 | { |
1573 | LIST_HEAD(tmp_add_list); | ||
1574 | u8 broadcast[ETH_ALEN]; | ||
1522 | struct ice_vsi *vsi; | 1575 | struct ice_vsi *vsi; |
1523 | int status = 0; | 1576 | int status = 0; |
1524 | 1577 | ||
@@ -1528,7 +1581,37 @@ static int ice_setup_pf_sw(struct ice_pf *pf) | |||
1528 | goto error_exit; | 1581 | goto error_exit; |
1529 | } | 1582 | } |
1530 | 1583 | ||
1584 | /* tmp_add_list contains a list of MAC addresses for which MAC | ||
1585 | * filters need to be programmed. Add the VSI's unicast MAC to | ||
1586 | * this list | ||
1587 | */ | ||
1588 | status = ice_add_mac_to_list(vsi, &tmp_add_list, | ||
1589 | vsi->port_info->mac.perm_addr); | ||
1590 | if (status) | ||
1591 | goto error_exit; | ||
1592 | |||
1593 | /* VSI needs to receive broadcast traffic, so add the broadcast | ||
1594 | * MAC address to the list. | ||
1595 | */ | ||
1596 | eth_broadcast_addr(broadcast); | ||
1597 | status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast); | ||
1598 | if (status) | ||
1599 | goto error_exit; | ||
1600 | |||
1601 | /* program MAC filters for entries in tmp_add_list */ | ||
1602 | status = ice_add_mac(&pf->hw, &tmp_add_list); | ||
1603 | if (status) { | ||
1604 | dev_err(&pf->pdev->dev, "Could not add MAC filters\n"); | ||
1605 | status = -ENOMEM; | ||
1606 | goto error_exit; | ||
1607 | } | ||
1608 | |||
1609 | ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); | ||
1610 | return status; | ||
1611 | |||
1531 | error_exit: | 1612 | error_exit: |
1613 | ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); | ||
1614 | |||
1532 | if (vsi) { | 1615 | if (vsi) { |
1533 | ice_vsi_free_q_vectors(vsi); | 1616 | ice_vsi_free_q_vectors(vsi); |
1534 | if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED) | 1617 | if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED) |
@@ -1537,6 +1620,7 @@ error_exit: | |||
1537 | free_netdev(vsi->netdev); | 1620 | free_netdev(vsi->netdev); |
1538 | vsi->netdev = NULL; | 1621 | vsi->netdev = NULL; |
1539 | } | 1622 | } |
1623 | |||
1540 | ice_vsi_delete(vsi); | 1624 | ice_vsi_delete(vsi); |
1541 | ice_vsi_put_qs(vsi); | 1625 | ice_vsi_put_qs(vsi); |
1542 | pf->q_left_tx += vsi->alloc_txq; | 1626 | pf->q_left_tx += vsi->alloc_txq; |
@@ -1869,6 +1953,13 @@ static int ice_probe(struct pci_dev *pdev, | |||
1869 | "probe failed due to setup pf switch:%d\n", err); | 1953 | "probe failed due to setup pf switch:%d\n", err); |
1870 | goto err_alloc_sw_unroll; | 1954 | goto err_alloc_sw_unroll; |
1871 | } | 1955 | } |
1956 | |||
1957 | /* Driver is mostly up */ | ||
1958 | clear_bit(__ICE_DOWN, pf->state); | ||
1959 | |||
1960 | /* since everything is good, start the service timer */ | ||
1961 | mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period)); | ||
1962 | |||
1872 | return 0; | 1963 | return 0; |
1873 | 1964 | ||
1874 | err_alloc_sw_unroll: | 1965 | err_alloc_sw_unroll: |
@@ -2012,6 +2103,7 @@ static int ice_vsi_release(struct ice_vsi *vsi) | |||
2012 | ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); | 2103 | ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); |
2013 | pf->num_avail_msix += vsi->num_q_vectors; | 2104 | pf->num_avail_msix += vsi->num_q_vectors; |
2014 | 2105 | ||
2106 | ice_remove_vsi_fltr(&pf->hw, vsi->vsi_num); | ||
2015 | ice_vsi_delete(vsi); | 2107 | ice_vsi_delete(vsi); |
2016 | ice_vsi_free_q_vectors(vsi); | 2108 | ice_vsi_free_q_vectors(vsi); |
2017 | ice_vsi_clear_rings(vsi); | 2109 | ice_vsi_clear_rings(vsi); |
diff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h index 144712db1ad2..365dfb86dcb9 100644 --- a/drivers/net/ethernet/intel/ice/ice_status.h +++ b/drivers/net/ethernet/intel/ice/ice_status.h | |||
@@ -7,6 +7,7 @@ | |||
7 | /* Error Codes */ | 7 | /* Error Codes */ |
8 | enum ice_status { | 8 | enum ice_status { |
9 | ICE_ERR_PARAM = -1, | 9 | ICE_ERR_PARAM = -1, |
10 | ICE_ERR_NOT_IMPL = -2, | ||
10 | ICE_ERR_NOT_READY = -3, | 11 | ICE_ERR_NOT_READY = -3, |
11 | ICE_ERR_INVAL_SIZE = -6, | 12 | ICE_ERR_INVAL_SIZE = -6, |
12 | ICE_ERR_DEVICE_NOT_SUPPORTED = -8, | 13 | ICE_ERR_DEVICE_NOT_SUPPORTED = -8, |
@@ -15,6 +16,8 @@ enum ice_status { | |||
15 | ICE_ERR_NO_MEMORY = -11, | 16 | ICE_ERR_NO_MEMORY = -11, |
16 | ICE_ERR_CFG = -12, | 17 | ICE_ERR_CFG = -12, |
17 | ICE_ERR_OUT_OF_RANGE = -13, | 18 | ICE_ERR_OUT_OF_RANGE = -13, |
19 | ICE_ERR_ALREADY_EXISTS = -14, | ||
20 | ICE_ERR_DOES_NOT_EXIST = -15, | ||
18 | ICE_ERR_BUF_TOO_SHORT = -52, | 21 | ICE_ERR_BUF_TOO_SHORT = -52, |
19 | ICE_ERR_NVM_BLANK_MODE = -53, | 22 | ICE_ERR_NVM_BLANK_MODE = -53, |
20 | ICE_ERR_AQ_ERROR = -100, | 23 | ICE_ERR_AQ_ERROR = -100, |
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index b438cee9521e..3944dac6cfc6 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c | |||
@@ -3,6 +3,88 @@ | |||
3 | 3 | ||
4 | #include "ice_switch.h" | 4 | #include "ice_switch.h" |
5 | 5 | ||
6 | #define ICE_ETH_DA_OFFSET 0 | ||
7 | #define ICE_ETH_ETHTYPE_OFFSET 12 | ||
8 | #define ICE_ETH_VLAN_TCI_OFFSET 14 | ||
9 | #define ICE_MAX_VLAN_ID 0xFFF | ||
10 | |||
11 | /* Dummy ethernet header needed in the ice_aqc_sw_rules_elem | ||
12 | * struct to configure any switch filter rules. | ||
13 | * {DA (6 bytes), SA(6 bytes), | ||
14 | * Ether type (2 bytes for header without VLAN tag) OR | ||
15 | * VLAN tag (4 bytes for header with VLAN tag) } | ||
16 | * | ||
17 | * Word on Hardcoded values | ||
18 | * byte 0 = 0x2: to identify it as locally administered DA MAC | ||
19 | * byte 6 = 0x2: to identify it as locally administered SA MAC | ||
20 | * byte 12 = 0x81 & byte 13 = 0x00: | ||
21 | * In case of VLAN filter first two bytes defines ether type (0x8100) | ||
22 | * and remaining two bytes are placeholder for programming a given VLAN id | ||
23 | * In case of Ether type filter it is treated as header without VLAN tag | ||
24 | * and byte 12 and 13 is used to program a given Ether type instead | ||
25 | */ | ||
26 | #define DUMMY_ETH_HDR_LEN 16 | ||
27 | static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0, | ||
28 | 0x2, 0, 0, 0, 0, 0, | ||
29 | 0x81, 0, 0, 0}; | ||
30 | |||
31 | #define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE \ | ||
32 | (sizeof(struct ice_aqc_sw_rules_elem) - \ | ||
33 | sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \ | ||
34 | sizeof(struct ice_sw_rule_lkup_rx_tx) + DUMMY_ETH_HDR_LEN - 1) | ||
35 | #define ICE_SW_RULE_RX_TX_NO_HDR_SIZE \ | ||
36 | (sizeof(struct ice_aqc_sw_rules_elem) - \ | ||
37 | sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \ | ||
38 | sizeof(struct ice_sw_rule_lkup_rx_tx) - 1) | ||
39 | #define ICE_SW_RULE_LG_ACT_SIZE(n) \ | ||
40 | (sizeof(struct ice_aqc_sw_rules_elem) - \ | ||
41 | sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \ | ||
42 | sizeof(struct ice_sw_rule_lg_act) - \ | ||
43 | sizeof(((struct ice_sw_rule_lg_act *)0)->act) + \ | ||
44 | ((n) * sizeof(((struct ice_sw_rule_lg_act *)0)->act))) | ||
45 | #define ICE_SW_RULE_VSI_LIST_SIZE(n) \ | ||
46 | (sizeof(struct ice_aqc_sw_rules_elem) - \ | ||
47 | sizeof(((struct ice_aqc_sw_rules_elem *)0)->pdata) + \ | ||
48 | sizeof(struct ice_sw_rule_vsi_list) - \ | ||
49 | sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi) + \ | ||
50 | ((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi))) | ||
51 | |||
52 | /** | ||
53 | * ice_aq_alloc_free_res - command to allocate/free resources | ||
54 | * @hw: pointer to the hw struct | ||
55 | * @num_entries: number of resource entries in buffer | ||
56 | * @buf: Indirect buffer to hold data parameters and response | ||
57 | * @buf_size: size of buffer for indirect commands | ||
58 | * @opc: pass in the command opcode | ||
59 | * @cd: pointer to command details structure or NULL | ||
60 | * | ||
61 | * Helper function to allocate/free resources using the admin queue commands | ||
62 | */ | ||
63 | static enum ice_status | ||
64 | ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries, | ||
65 | struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size, | ||
66 | enum ice_adminq_opc opc, struct ice_sq_cd *cd) | ||
67 | { | ||
68 | struct ice_aqc_alloc_free_res_cmd *cmd; | ||
69 | struct ice_aq_desc desc; | ||
70 | |||
71 | cmd = &desc.params.sw_res_ctrl; | ||
72 | |||
73 | if (!buf) | ||
74 | return ICE_ERR_PARAM; | ||
75 | |||
76 | if (buf_size < (num_entries * sizeof(buf->elem[0]))) | ||
77 | return ICE_ERR_PARAM; | ||
78 | |||
79 | ice_fill_dflt_direct_cmd_desc(&desc, opc); | ||
80 | |||
81 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); | ||
82 | |||
83 | cmd->num_entries = cpu_to_le16(num_entries); | ||
84 | |||
85 | return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); | ||
86 | } | ||
87 | |||
6 | /** | 88 | /** |
7 | * ice_aq_get_sw_cfg - get switch configuration | 89 | * ice_aq_get_sw_cfg - get switch configuration |
8 | * @hw: pointer to the hardware structure | 90 | * @hw: pointer to the hardware structure |
@@ -165,6 +247,93 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, | |||
165 | return status; | 247 | return status; |
166 | } | 248 | } |
167 | 249 | ||
250 | /** | ||
251 | * ice_aq_alloc_free_vsi_list | ||
252 | * @hw: pointer to the hw struct | ||
253 | * @vsi_list_id: VSI list id returned or used for lookup | ||
254 | * @lkup_type: switch rule filter lookup type | ||
255 | * @opc: switch rules population command type - pass in the command opcode | ||
256 | * | ||
257 | * allocates or free a VSI list resource | ||
258 | */ | ||
259 | static enum ice_status | ||
260 | ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id, | ||
261 | enum ice_sw_lkup_type lkup_type, | ||
262 | enum ice_adminq_opc opc) | ||
263 | { | ||
264 | struct ice_aqc_alloc_free_res_elem *sw_buf; | ||
265 | struct ice_aqc_res_elem *vsi_ele; | ||
266 | enum ice_status status; | ||
267 | u16 buf_len; | ||
268 | |||
269 | buf_len = sizeof(*sw_buf); | ||
270 | sw_buf = devm_kzalloc(ice_hw_to_dev(hw), buf_len, GFP_KERNEL); | ||
271 | if (!sw_buf) | ||
272 | return ICE_ERR_NO_MEMORY; | ||
273 | sw_buf->num_elems = cpu_to_le16(1); | ||
274 | |||
275 | if (lkup_type == ICE_SW_LKUP_MAC || | ||
276 | lkup_type == ICE_SW_LKUP_MAC_VLAN || | ||
277 | lkup_type == ICE_SW_LKUP_ETHERTYPE || | ||
278 | lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || | ||
279 | lkup_type == ICE_SW_LKUP_PROMISC || | ||
280 | lkup_type == ICE_SW_LKUP_PROMISC_VLAN) { | ||
281 | sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP); | ||
282 | } else if (lkup_type == ICE_SW_LKUP_VLAN) { | ||
283 | sw_buf->res_type = | ||
284 | cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE); | ||
285 | } else { | ||
286 | status = ICE_ERR_PARAM; | ||
287 | goto ice_aq_alloc_free_vsi_list_exit; | ||
288 | } | ||
289 | |||
290 | if (opc == ice_aqc_opc_free_res) | ||
291 | sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id); | ||
292 | |||
293 | status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL); | ||
294 | if (status) | ||
295 | goto ice_aq_alloc_free_vsi_list_exit; | ||
296 | |||
297 | if (opc == ice_aqc_opc_alloc_res) { | ||
298 | vsi_ele = &sw_buf->elem[0]; | ||
299 | *vsi_list_id = le16_to_cpu(vsi_ele->e.sw_resp); | ||
300 | } | ||
301 | |||
302 | ice_aq_alloc_free_vsi_list_exit: | ||
303 | devm_kfree(ice_hw_to_dev(hw), sw_buf); | ||
304 | return status; | ||
305 | } | ||
306 | |||
307 | /** | ||
308 | * ice_aq_sw_rules - add/update/remove switch rules | ||
309 | * @hw: pointer to the hw struct | ||
310 | * @rule_list: pointer to switch rule population list | ||
311 | * @rule_list_sz: total size of the rule list in bytes | ||
312 | * @num_rules: number of switch rules in the rule_list | ||
313 | * @opc: switch rules population command type - pass in the command opcode | ||
314 | * @cd: pointer to command details structure or NULL | ||
315 | * | ||
316 | * Add(0x02a0)/Update(0x02a1)/Remove(0x02a2) switch rules commands to firmware | ||
317 | */ | ||
318 | static enum ice_status | ||
319 | ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz, | ||
320 | u8 num_rules, enum ice_adminq_opc opc, struct ice_sq_cd *cd) | ||
321 | { | ||
322 | struct ice_aq_desc desc; | ||
323 | |||
324 | if (opc != ice_aqc_opc_add_sw_rules && | ||
325 | opc != ice_aqc_opc_update_sw_rules && | ||
326 | opc != ice_aqc_opc_remove_sw_rules) | ||
327 | return ICE_ERR_PARAM; | ||
328 | |||
329 | ice_fill_dflt_direct_cmd_desc(&desc, opc); | ||
330 | |||
331 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); | ||
332 | desc.params.sw_rules.num_rules_fltr_entry_index = | ||
333 | cpu_to_le16(num_rules); | ||
334 | return ice_aq_send_cmd(hw, &desc, rule_list, rule_list_sz, cd); | ||
335 | } | ||
336 | |||
168 | /* ice_init_port_info - Initialize port_info with switch configuration data | 337 | /* ice_init_port_info - Initialize port_info with switch configuration data |
169 | * @pi: pointer to port_info | 338 | * @pi: pointer to port_info |
170 | * @vsi_port_num: VSI number or port number | 339 | * @vsi_port_num: VSI number or port number |
@@ -257,3 +426,1212 @@ enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw) | |||
257 | devm_kfree(ice_hw_to_dev(hw), (void *)rbuf); | 426 | devm_kfree(ice_hw_to_dev(hw), (void *)rbuf); |
258 | return status; | 427 | return status; |
259 | } | 428 | } |
429 | |||
430 | /** | ||
431 | * ice_fill_sw_info - Helper function to populate lb_en and lan_en | ||
432 | * @hw: pointer to the hardware structure | ||
433 | * @f_info: filter info structure to fill/update | ||
434 | * | ||
435 | * This helper function populates the lb_en and lan_en elements of the provided | ||
436 | * ice_fltr_info struct using the switch's type and characteristics of the | ||
437 | * switch rule being configured. | ||
438 | */ | ||
439 | static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *f_info) | ||
440 | { | ||
441 | f_info->lb_en = false; | ||
442 | f_info->lan_en = false; | ||
443 | if ((f_info->flag & ICE_FLTR_TX) && | ||
444 | (f_info->fltr_act == ICE_FWD_TO_VSI || | ||
445 | f_info->fltr_act == ICE_FWD_TO_VSI_LIST || | ||
446 | f_info->fltr_act == ICE_FWD_TO_Q || | ||
447 | f_info->fltr_act == ICE_FWD_TO_QGRP)) { | ||
448 | f_info->lb_en = true; | ||
449 | if (!(hw->evb_veb && f_info->lkup_type == ICE_SW_LKUP_MAC && | ||
450 | is_unicast_ether_addr(f_info->l_data.mac.mac_addr))) | ||
451 | f_info->lan_en = true; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | /** | ||
456 | * ice_fill_sw_rule - Helper function to fill switch rule structure | ||
457 | * @hw: pointer to the hardware structure | ||
458 | * @f_info: entry containing packet forwarding information | ||
459 | * @s_rule: switch rule structure to be filled in based on mac_entry | ||
460 | * @opc: switch rules population command type - pass in the command opcode | ||
461 | */ | ||
462 | static void | ||
463 | ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, | ||
464 | struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc) | ||
465 | { | ||
466 | u16 vlan_id = ICE_MAX_VLAN_ID + 1; | ||
467 | u8 eth_hdr[DUMMY_ETH_HDR_LEN]; | ||
468 | void *daddr = NULL; | ||
469 | u32 act = 0; | ||
470 | __be16 *off; | ||
471 | |||
472 | if (opc == ice_aqc_opc_remove_sw_rules) { | ||
473 | s_rule->pdata.lkup_tx_rx.act = 0; | ||
474 | s_rule->pdata.lkup_tx_rx.index = | ||
475 | cpu_to_le16(f_info->fltr_rule_id); | ||
476 | s_rule->pdata.lkup_tx_rx.hdr_len = 0; | ||
477 | return; | ||
478 | } | ||
479 | |||
480 | /* initialize the ether header with a dummy header */ | ||
481 | memcpy(eth_hdr, dummy_eth_header, sizeof(dummy_eth_header)); | ||
482 | ice_fill_sw_info(hw, f_info); | ||
483 | |||
484 | switch (f_info->fltr_act) { | ||
485 | case ICE_FWD_TO_VSI: | ||
486 | act |= (f_info->fwd_id.vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & | ||
487 | ICE_SINGLE_ACT_VSI_ID_M; | ||
488 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) | ||
489 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | | ||
490 | ICE_SINGLE_ACT_VALID_BIT; | ||
491 | break; | ||
492 | case ICE_FWD_TO_VSI_LIST: | ||
493 | act |= ICE_SINGLE_ACT_VSI_LIST; | ||
494 | act |= (f_info->fwd_id.vsi_list_id << | ||
495 | ICE_SINGLE_ACT_VSI_LIST_ID_S) & | ||
496 | ICE_SINGLE_ACT_VSI_LIST_ID_M; | ||
497 | if (f_info->lkup_type != ICE_SW_LKUP_VLAN) | ||
498 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | | ||
499 | ICE_SINGLE_ACT_VALID_BIT; | ||
500 | break; | ||
501 | case ICE_FWD_TO_Q: | ||
502 | act |= ICE_SINGLE_ACT_TO_Q; | ||
503 | act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & | ||
504 | ICE_SINGLE_ACT_Q_INDEX_M; | ||
505 | break; | ||
506 | case ICE_FWD_TO_QGRP: | ||
507 | act |= ICE_SINGLE_ACT_TO_Q; | ||
508 | act |= (f_info->qgrp_size << ICE_SINGLE_ACT_Q_REGION_S) & | ||
509 | ICE_SINGLE_ACT_Q_REGION_M; | ||
510 | break; | ||
511 | case ICE_DROP_PACKET: | ||
512 | act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP; | ||
513 | break; | ||
514 | default: | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | if (f_info->lb_en) | ||
519 | act |= ICE_SINGLE_ACT_LB_ENABLE; | ||
520 | if (f_info->lan_en) | ||
521 | act |= ICE_SINGLE_ACT_LAN_ENABLE; | ||
522 | |||
523 | switch (f_info->lkup_type) { | ||
524 | case ICE_SW_LKUP_MAC: | ||
525 | daddr = f_info->l_data.mac.mac_addr; | ||
526 | break; | ||
527 | case ICE_SW_LKUP_VLAN: | ||
528 | vlan_id = f_info->l_data.vlan.vlan_id; | ||
529 | if (f_info->fltr_act == ICE_FWD_TO_VSI || | ||
530 | f_info->fltr_act == ICE_FWD_TO_VSI_LIST) { | ||
531 | act |= ICE_SINGLE_ACT_PRUNE; | ||
532 | act |= ICE_SINGLE_ACT_EGRESS | ICE_SINGLE_ACT_INGRESS; | ||
533 | } | ||
534 | break; | ||
535 | case ICE_SW_LKUP_ETHERTYPE_MAC: | ||
536 | daddr = f_info->l_data.ethertype_mac.mac_addr; | ||
537 | /* fall-through */ | ||
538 | case ICE_SW_LKUP_ETHERTYPE: | ||
539 | off = (__be16 *)ð_hdr[ICE_ETH_ETHTYPE_OFFSET]; | ||
540 | *off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype); | ||
541 | break; | ||
542 | case ICE_SW_LKUP_MAC_VLAN: | ||
543 | daddr = f_info->l_data.mac_vlan.mac_addr; | ||
544 | vlan_id = f_info->l_data.mac_vlan.vlan_id; | ||
545 | break; | ||
546 | case ICE_SW_LKUP_PROMISC_VLAN: | ||
547 | vlan_id = f_info->l_data.mac_vlan.vlan_id; | ||
548 | /* fall-through */ | ||
549 | case ICE_SW_LKUP_PROMISC: | ||
550 | daddr = f_info->l_data.mac_vlan.mac_addr; | ||
551 | break; | ||
552 | default: | ||
553 | break; | ||
554 | } | ||
555 | |||
556 | s_rule->type = (f_info->flag & ICE_FLTR_RX) ? | ||
557 | cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX) : | ||
558 | cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); | ||
559 | |||
560 | /* Recipe set depending on lookup type */ | ||
561 | s_rule->pdata.lkup_tx_rx.recipe_id = cpu_to_le16(f_info->lkup_type); | ||
562 | s_rule->pdata.lkup_tx_rx.src = cpu_to_le16(f_info->src); | ||
563 | s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act); | ||
564 | |||
565 | if (daddr) | ||
566 | ether_addr_copy(ð_hdr[ICE_ETH_DA_OFFSET], daddr); | ||
567 | |||
568 | if (!(vlan_id > ICE_MAX_VLAN_ID)) { | ||
569 | off = (__be16 *)ð_hdr[ICE_ETH_VLAN_TCI_OFFSET]; | ||
570 | *off = cpu_to_be16(vlan_id); | ||
571 | } | ||
572 | |||
573 | /* Create the switch rule with the final dummy Ethernet header */ | ||
574 | if (opc != ice_aqc_opc_update_sw_rules) | ||
575 | s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(sizeof(eth_hdr)); | ||
576 | |||
577 | memcpy(s_rule->pdata.lkup_tx_rx.hdr, eth_hdr, sizeof(eth_hdr)); | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * ice_add_marker_act | ||
582 | * @hw: pointer to the hardware structure | ||
583 | * @m_ent: the management entry for which sw marker needs to be added | ||
584 | * @sw_marker: sw marker to tag the Rx descriptor with | ||
585 | * @l_id: large action resource id | ||
586 | * | ||
587 | * Create a large action to hold software marker and update the switch rule | ||
588 | * entry pointed by m_ent with newly created large action | ||
589 | */ | ||
590 | static enum ice_status | ||
591 | ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, | ||
592 | u16 sw_marker, u16 l_id) | ||
593 | { | ||
594 | struct ice_aqc_sw_rules_elem *lg_act, *rx_tx; | ||
595 | /* For software marker we need 3 large actions | ||
596 | * 1. FWD action: FWD TO VSI or VSI LIST | ||
597 | * 2. GENERIC VALUE action to hold the profile id | ||
598 | * 3. GENERIC VALUE action to hold the software marker id | ||
599 | */ | ||
600 | const u16 num_lg_acts = 3; | ||
601 | enum ice_status status; | ||
602 | u16 lg_act_size; | ||
603 | u16 rules_size; | ||
604 | u16 vsi_info; | ||
605 | u32 act; | ||
606 | |||
607 | if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC) | ||
608 | return ICE_ERR_PARAM; | ||
609 | |||
610 | /* Create two back-to-back switch rules and submit them to the HW using | ||
611 | * one memory buffer: | ||
612 | * 1. Large Action | ||
613 | * 2. Look up tx rx | ||
614 | */ | ||
615 | lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(num_lg_acts); | ||
616 | rules_size = lg_act_size + ICE_SW_RULE_RX_TX_ETH_HDR_SIZE; | ||
617 | lg_act = devm_kzalloc(ice_hw_to_dev(hw), rules_size, GFP_KERNEL); | ||
618 | if (!lg_act) | ||
619 | return ICE_ERR_NO_MEMORY; | ||
620 | |||
621 | rx_tx = (struct ice_aqc_sw_rules_elem *)((u8 *)lg_act + lg_act_size); | ||
622 | |||
623 | /* Fill in the first switch rule i.e. large action */ | ||
624 | lg_act->type = cpu_to_le16(ICE_AQC_SW_RULES_T_LG_ACT); | ||
625 | lg_act->pdata.lg_act.index = cpu_to_le16(l_id); | ||
626 | lg_act->pdata.lg_act.size = cpu_to_le16(num_lg_acts); | ||
627 | |||
628 | /* First action VSI forwarding or VSI list forwarding depending on how | ||
629 | * many VSIs | ||
630 | */ | ||
631 | vsi_info = (m_ent->vsi_count > 1) ? | ||
632 | m_ent->fltr_info.fwd_id.vsi_list_id : | ||
633 | m_ent->fltr_info.fwd_id.vsi_id; | ||
634 | |||
635 | act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT; | ||
636 | act |= (vsi_info << ICE_LG_ACT_VSI_LIST_ID_S) & | ||
637 | ICE_LG_ACT_VSI_LIST_ID_M; | ||
638 | if (m_ent->vsi_count > 1) | ||
639 | act |= ICE_LG_ACT_VSI_LIST; | ||
640 | lg_act->pdata.lg_act.act[0] = cpu_to_le32(act); | ||
641 | |||
642 | /* Second action descriptor type */ | ||
643 | act = ICE_LG_ACT_GENERIC; | ||
644 | |||
645 | act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M; | ||
646 | lg_act->pdata.lg_act.act[1] = cpu_to_le32(act); | ||
647 | |||
648 | act = (7 << ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_VALUE_M; | ||
649 | |||
650 | /* Third action Marker value */ | ||
651 | act |= ICE_LG_ACT_GENERIC; | ||
652 | act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) & | ||
653 | ICE_LG_ACT_GENERIC_VALUE_M; | ||
654 | |||
655 | act |= (0 << ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_VALUE_M; | ||
656 | lg_act->pdata.lg_act.act[2] = cpu_to_le32(act); | ||
657 | |||
658 | /* call the fill switch rule to fill the lookup tx rx structure */ | ||
659 | ice_fill_sw_rule(hw, &m_ent->fltr_info, rx_tx, | ||
660 | ice_aqc_opc_update_sw_rules); | ||
661 | |||
662 | /* Update the action to point to the large action id */ | ||
663 | rx_tx->pdata.lkup_tx_rx.act = | ||
664 | cpu_to_le32(ICE_SINGLE_ACT_PTR | | ||
665 | ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) & | ||
666 | ICE_SINGLE_ACT_PTR_VAL_M)); | ||
667 | |||
668 | /* Use the filter rule id of the previously created rule with single | ||
669 | * act. Once the update happens, hardware will treat this as large | ||
670 | * action | ||
671 | */ | ||
672 | rx_tx->pdata.lkup_tx_rx.index = | ||
673 | cpu_to_le16(m_ent->fltr_info.fltr_rule_id); | ||
674 | |||
675 | status = ice_aq_sw_rules(hw, lg_act, rules_size, 2, | ||
676 | ice_aqc_opc_update_sw_rules, NULL); | ||
677 | if (!status) { | ||
678 | m_ent->lg_act_idx = l_id; | ||
679 | m_ent->sw_marker_id = sw_marker; | ||
680 | } | ||
681 | |||
682 | devm_kfree(ice_hw_to_dev(hw), lg_act); | ||
683 | return status; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * ice_create_vsi_list_map | ||
688 | * @hw: pointer to the hardware structure | ||
689 | * @vsi_array: array of VSIs to form a VSI list | ||
690 | * @num_vsi: num VSI in the array | ||
691 | * @vsi_list_id: VSI list id generated as part of allocate resource | ||
692 | * | ||
693 | * Helper function to create a new entry of VSI list id to VSI mapping | ||
694 | * using the given VSI list id | ||
695 | */ | ||
696 | static struct ice_vsi_list_map_info * | ||
697 | ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, | ||
698 | u16 vsi_list_id) | ||
699 | { | ||
700 | struct ice_switch_info *sw = hw->switch_info; | ||
701 | struct ice_vsi_list_map_info *v_map; | ||
702 | int i; | ||
703 | |||
704 | v_map = devm_kcalloc(ice_hw_to_dev(hw), 1, sizeof(*v_map), GFP_KERNEL); | ||
705 | if (!v_map) | ||
706 | return NULL; | ||
707 | |||
708 | v_map->vsi_list_id = vsi_list_id; | ||
709 | |||
710 | for (i = 0; i < num_vsi; i++) | ||
711 | set_bit(vsi_array[i], v_map->vsi_map); | ||
712 | |||
713 | list_add(&v_map->list_entry, &sw->vsi_list_map_head); | ||
714 | return v_map; | ||
715 | } | ||
716 | |||
717 | /** | ||
718 | * ice_update_vsi_list_rule | ||
719 | * @hw: pointer to the hardware structure | ||
720 | * @vsi_array: array of VSIs to form a VSI list | ||
721 | * @num_vsi: num VSI in the array | ||
722 | * @vsi_list_id: VSI list id generated as part of allocate resource | ||
723 | * @remove: Boolean value to indicate if this is a remove action | ||
724 | * @opc: switch rules population command type - pass in the command opcode | ||
725 | * @lkup_type: lookup type of the filter | ||
726 | * | ||
727 | * Call AQ command to add a new switch rule or update existing switch rule | ||
728 | * using the given VSI list id | ||
729 | */ | ||
730 | static enum ice_status | ||
731 | ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, | ||
732 | u16 vsi_list_id, bool remove, enum ice_adminq_opc opc, | ||
733 | enum ice_sw_lkup_type lkup_type) | ||
734 | { | ||
735 | struct ice_aqc_sw_rules_elem *s_rule; | ||
736 | enum ice_status status; | ||
737 | u16 s_rule_size; | ||
738 | u16 type; | ||
739 | int i; | ||
740 | |||
741 | if (!num_vsi) | ||
742 | return ICE_ERR_PARAM; | ||
743 | |||
744 | if (lkup_type == ICE_SW_LKUP_MAC || | ||
745 | lkup_type == ICE_SW_LKUP_MAC_VLAN || | ||
746 | lkup_type == ICE_SW_LKUP_ETHERTYPE || | ||
747 | lkup_type == ICE_SW_LKUP_ETHERTYPE_MAC || | ||
748 | lkup_type == ICE_SW_LKUP_PROMISC || | ||
749 | lkup_type == ICE_SW_LKUP_PROMISC_VLAN) | ||
750 | type = remove ? ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR : | ||
751 | ICE_AQC_SW_RULES_T_VSI_LIST_SET; | ||
752 | else if (lkup_type == ICE_SW_LKUP_VLAN) | ||
753 | type = remove ? ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR : | ||
754 | ICE_AQC_SW_RULES_T_PRUNE_LIST_SET; | ||
755 | else | ||
756 | return ICE_ERR_PARAM; | ||
757 | |||
758 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(num_vsi); | ||
759 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); | ||
760 | if (!s_rule) | ||
761 | return ICE_ERR_NO_MEMORY; | ||
762 | |||
763 | for (i = 0; i < num_vsi; i++) | ||
764 | s_rule->pdata.vsi_list.vsi[i] = cpu_to_le16(vsi_array[i]); | ||
765 | |||
766 | s_rule->type = cpu_to_le16(type); | ||
767 | s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi); | ||
768 | s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id); | ||
769 | |||
770 | status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL); | ||
771 | |||
772 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
773 | return status; | ||
774 | } | ||
775 | |||
776 | /** | ||
777 | * ice_create_vsi_list_rule - Creates and populates a VSI list rule | ||
778 | * @hw: pointer to the hw struct | ||
779 | * @vsi_array: array of VSIs to form a VSI list | ||
780 | * @num_vsi: number of VSIs in the array | ||
781 | * @vsi_list_id: stores the ID of the VSI list to be created | ||
782 | * @lkup_type: switch rule filter's lookup type | ||
783 | */ | ||
784 | static enum ice_status | ||
785 | ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, | ||
786 | u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type) | ||
787 | { | ||
788 | enum ice_status status; | ||
789 | int i; | ||
790 | |||
791 | for (i = 0; i < num_vsi; i++) | ||
792 | if (vsi_array[i] >= ICE_MAX_VSI) | ||
793 | return ICE_ERR_OUT_OF_RANGE; | ||
794 | |||
795 | status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type, | ||
796 | ice_aqc_opc_alloc_res); | ||
797 | if (status) | ||
798 | return status; | ||
799 | |||
800 | /* Update the newly created VSI list to include the specified VSIs */ | ||
801 | return ice_update_vsi_list_rule(hw, vsi_array, num_vsi, *vsi_list_id, | ||
802 | false, ice_aqc_opc_add_sw_rules, | ||
803 | lkup_type); | ||
804 | } | ||
805 | |||
806 | /** | ||
807 | * ice_create_pkt_fwd_rule | ||
808 | * @hw: pointer to the hardware structure | ||
809 | * @f_entry: entry containing packet forwarding information | ||
810 | * | ||
811 | * Create switch rule with given filter information and add an entry | ||
812 | * to the corresponding filter management list to track this switch rule | ||
813 | * and VSI mapping | ||
814 | */ | ||
815 | static enum ice_status | ||
816 | ice_create_pkt_fwd_rule(struct ice_hw *hw, | ||
817 | struct ice_fltr_list_entry *f_entry) | ||
818 | { | ||
819 | struct ice_switch_info *sw = hw->switch_info; | ||
820 | struct ice_fltr_mgmt_list_entry *fm_entry; | ||
821 | struct ice_aqc_sw_rules_elem *s_rule; | ||
822 | enum ice_sw_lkup_type l_type; | ||
823 | enum ice_status status; | ||
824 | |||
825 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), | ||
826 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL); | ||
827 | if (!s_rule) | ||
828 | return ICE_ERR_NO_MEMORY; | ||
829 | fm_entry = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*fm_entry), | ||
830 | GFP_KERNEL); | ||
831 | if (!fm_entry) { | ||
832 | status = ICE_ERR_NO_MEMORY; | ||
833 | goto ice_create_pkt_fwd_rule_exit; | ||
834 | } | ||
835 | |||
836 | fm_entry->fltr_info = f_entry->fltr_info; | ||
837 | |||
838 | /* Initialize all the fields for the management entry */ | ||
839 | fm_entry->vsi_count = 1; | ||
840 | fm_entry->lg_act_idx = ICE_INVAL_LG_ACT_INDEX; | ||
841 | fm_entry->sw_marker_id = ICE_INVAL_SW_MARKER_ID; | ||
842 | fm_entry->counter_index = ICE_INVAL_COUNTER_ID; | ||
843 | |||
844 | ice_fill_sw_rule(hw, &fm_entry->fltr_info, s_rule, | ||
845 | ice_aqc_opc_add_sw_rules); | ||
846 | |||
847 | status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1, | ||
848 | ice_aqc_opc_add_sw_rules, NULL); | ||
849 | if (status) { | ||
850 | devm_kfree(ice_hw_to_dev(hw), fm_entry); | ||
851 | goto ice_create_pkt_fwd_rule_exit; | ||
852 | } | ||
853 | |||
854 | f_entry->fltr_info.fltr_rule_id = | ||
855 | le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); | ||
856 | fm_entry->fltr_info.fltr_rule_id = | ||
857 | le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); | ||
858 | |||
859 | /* The book keeping entries will get removed when base driver | ||
860 | * calls remove filter AQ command | ||
861 | */ | ||
862 | l_type = fm_entry->fltr_info.lkup_type; | ||
863 | if (l_type == ICE_SW_LKUP_MAC) { | ||
864 | mutex_lock(&sw->mac_list_lock); | ||
865 | list_add(&fm_entry->list_entry, &sw->mac_list_head); | ||
866 | mutex_unlock(&sw->mac_list_lock); | ||
867 | } else if (l_type == ICE_SW_LKUP_VLAN) { | ||
868 | mutex_lock(&sw->vlan_list_lock); | ||
869 | list_add(&fm_entry->list_entry, &sw->vlan_list_head); | ||
870 | mutex_unlock(&sw->vlan_list_lock); | ||
871 | } else if (l_type == ICE_SW_LKUP_ETHERTYPE || | ||
872 | l_type == ICE_SW_LKUP_ETHERTYPE_MAC) { | ||
873 | mutex_lock(&sw->eth_m_list_lock); | ||
874 | list_add(&fm_entry->list_entry, &sw->eth_m_list_head); | ||
875 | mutex_unlock(&sw->eth_m_list_lock); | ||
876 | } else if (l_type == ICE_SW_LKUP_PROMISC || | ||
877 | l_type == ICE_SW_LKUP_PROMISC_VLAN) { | ||
878 | mutex_lock(&sw->promisc_list_lock); | ||
879 | list_add(&fm_entry->list_entry, &sw->promisc_list_head); | ||
880 | mutex_unlock(&sw->promisc_list_lock); | ||
881 | } else if (fm_entry->fltr_info.lkup_type == ICE_SW_LKUP_MAC_VLAN) { | ||
882 | mutex_lock(&sw->mac_vlan_list_lock); | ||
883 | list_add(&fm_entry->list_entry, &sw->mac_vlan_list_head); | ||
884 | mutex_unlock(&sw->mac_vlan_list_lock); | ||
885 | } else { | ||
886 | status = ICE_ERR_NOT_IMPL; | ||
887 | } | ||
888 | ice_create_pkt_fwd_rule_exit: | ||
889 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
890 | return status; | ||
891 | } | ||
892 | |||
893 | /** | ||
894 | * ice_update_pkt_fwd_rule | ||
895 | * @hw: pointer to the hardware structure | ||
896 | * @rule_id: rule of previously created switch rule to update | ||
897 | * @vsi_list_id: VSI list id to be updated with | ||
898 | * @f_info: ice_fltr_info to pull other information for switch rule | ||
899 | * | ||
900 | * Call AQ command to update a previously created switch rule with a | ||
901 | * VSI list id | ||
902 | */ | ||
903 | static enum ice_status | ||
904 | ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id, | ||
905 | struct ice_fltr_info f_info) | ||
906 | { | ||
907 | struct ice_aqc_sw_rules_elem *s_rule; | ||
908 | struct ice_fltr_info tmp_fltr; | ||
909 | enum ice_status status; | ||
910 | |||
911 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), | ||
912 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, GFP_KERNEL); | ||
913 | if (!s_rule) | ||
914 | return ICE_ERR_NO_MEMORY; | ||
915 | |||
916 | tmp_fltr = f_info; | ||
917 | tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; | ||
918 | tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; | ||
919 | |||
920 | ice_fill_sw_rule(hw, &tmp_fltr, s_rule, | ||
921 | ice_aqc_opc_update_sw_rules); | ||
922 | |||
923 | s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(rule_id); | ||
924 | |||
925 | /* Update switch rule with new rule set to forward VSI list */ | ||
926 | status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1, | ||
927 | ice_aqc_opc_update_sw_rules, NULL); | ||
928 | |||
929 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
930 | return status; | ||
931 | } | ||
932 | |||
933 | /** | ||
934 | * ice_handle_vsi_list_mgmt | ||
935 | * @hw: pointer to the hardware structure | ||
936 | * @m_entry: pointer to current filter management list entry | ||
937 | * @cur_fltr: filter information from the book keeping entry | ||
938 | * @new_fltr: filter information with the new VSI to be added | ||
939 | * | ||
940 | * Call AQ command to add or update previously created VSI list with new VSI. | ||
941 | * | ||
942 | * Helper function to do book keeping associated with adding filter information | ||
943 | * The algorithm to do the booking keeping is described below : | ||
944 | * When a VSI needs to subscribe to a given filter( MAC/VLAN/Ethtype etc.) | ||
945 | * if only one VSI has been added till now | ||
946 | * Allocate a new VSI list and add two VSIs | ||
947 | * to this list using switch rule command | ||
948 | * Update the previously created switch rule with the | ||
949 | * newly created VSI list id | ||
950 | * if a VSI list was previously created | ||
951 | * Add the new VSI to the previously created VSI list set | ||
952 | * using the update switch rule command | ||
953 | */ | ||
954 | static enum ice_status | ||
955 | ice_handle_vsi_list_mgmt(struct ice_hw *hw, | ||
956 | struct ice_fltr_mgmt_list_entry *m_entry, | ||
957 | struct ice_fltr_info *cur_fltr, | ||
958 | struct ice_fltr_info *new_fltr) | ||
959 | { | ||
960 | enum ice_status status = 0; | ||
961 | u16 vsi_list_id = 0; | ||
962 | |||
963 | if ((cur_fltr->fltr_act == ICE_FWD_TO_Q || | ||
964 | cur_fltr->fltr_act == ICE_FWD_TO_QGRP)) | ||
965 | return ICE_ERR_NOT_IMPL; | ||
966 | |||
967 | if ((new_fltr->fltr_act == ICE_FWD_TO_Q || | ||
968 | new_fltr->fltr_act == ICE_FWD_TO_QGRP) && | ||
969 | (cur_fltr->fltr_act == ICE_FWD_TO_VSI || | ||
970 | cur_fltr->fltr_act == ICE_FWD_TO_VSI_LIST)) | ||
971 | return ICE_ERR_NOT_IMPL; | ||
972 | |||
973 | if (m_entry->vsi_count < 2 && !m_entry->vsi_list_info) { | ||
974 | /* Only one entry existed in the mapping and it was not already | ||
975 | * a part of a VSI list. So, create a VSI list with the old and | ||
976 | * new VSIs. | ||
977 | */ | ||
978 | u16 vsi_id_arr[2]; | ||
979 | u16 fltr_rule; | ||
980 | |||
981 | /* A rule already exists with the new VSI being added */ | ||
982 | if (cur_fltr->fwd_id.vsi_id == new_fltr->fwd_id.vsi_id) | ||
983 | return ICE_ERR_ALREADY_EXISTS; | ||
984 | |||
985 | vsi_id_arr[0] = cur_fltr->fwd_id.vsi_id; | ||
986 | vsi_id_arr[1] = new_fltr->fwd_id.vsi_id; | ||
987 | status = ice_create_vsi_list_rule(hw, &vsi_id_arr[0], 2, | ||
988 | &vsi_list_id, | ||
989 | new_fltr->lkup_type); | ||
990 | if (status) | ||
991 | return status; | ||
992 | |||
993 | fltr_rule = cur_fltr->fltr_rule_id; | ||
994 | /* Update the previous switch rule of "MAC forward to VSI" to | ||
995 | * "MAC fwd to VSI list" | ||
996 | */ | ||
997 | status = ice_update_pkt_fwd_rule(hw, fltr_rule, vsi_list_id, | ||
998 | *new_fltr); | ||
999 | if (status) | ||
1000 | return status; | ||
1001 | |||
1002 | cur_fltr->fwd_id.vsi_list_id = vsi_list_id; | ||
1003 | cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; | ||
1004 | m_entry->vsi_list_info = | ||
1005 | ice_create_vsi_list_map(hw, &vsi_id_arr[0], 2, | ||
1006 | vsi_list_id); | ||
1007 | |||
1008 | /* If this entry was large action then the large action needs | ||
1009 | * to be updated to point to FWD to VSI list | ||
1010 | */ | ||
1011 | if (m_entry->sw_marker_id != ICE_INVAL_SW_MARKER_ID) | ||
1012 | status = | ||
1013 | ice_add_marker_act(hw, m_entry, | ||
1014 | m_entry->sw_marker_id, | ||
1015 | m_entry->lg_act_idx); | ||
1016 | } else { | ||
1017 | u16 vsi_id = new_fltr->fwd_id.vsi_id; | ||
1018 | enum ice_adminq_opc opcode; | ||
1019 | |||
1020 | /* A rule already exists with the new VSI being added */ | ||
1021 | if (test_bit(vsi_id, m_entry->vsi_list_info->vsi_map)) | ||
1022 | return 0; | ||
1023 | |||
1024 | /* Update the previously created VSI list set with | ||
1025 | * the new VSI id passed in | ||
1026 | */ | ||
1027 | vsi_list_id = cur_fltr->fwd_id.vsi_list_id; | ||
1028 | opcode = ice_aqc_opc_update_sw_rules; | ||
1029 | |||
1030 | status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, | ||
1031 | false, opcode, | ||
1032 | new_fltr->lkup_type); | ||
1033 | /* update VSI list mapping info with new VSI id */ | ||
1034 | if (!status) | ||
1035 | set_bit(vsi_id, m_entry->vsi_list_info->vsi_map); | ||
1036 | } | ||
1037 | if (!status) | ||
1038 | m_entry->vsi_count++; | ||
1039 | return status; | ||
1040 | } | ||
1041 | |||
1042 | /** | ||
1043 | * ice_find_mac_entry | ||
1044 | * @hw: pointer to the hardware structure | ||
1045 | * @mac_addr: MAC address to search for | ||
1046 | * | ||
1047 | * Helper function to search for a MAC entry using a given MAC address | ||
1048 | * Returns pointer to the entry if found. | ||
1049 | */ | ||
1050 | static struct ice_fltr_mgmt_list_entry * | ||
1051 | ice_find_mac_entry(struct ice_hw *hw, u8 *mac_addr) | ||
1052 | { | ||
1053 | struct ice_fltr_mgmt_list_entry *m_list_itr, *mac_ret = NULL; | ||
1054 | struct ice_switch_info *sw = hw->switch_info; | ||
1055 | |||
1056 | mutex_lock(&sw->mac_list_lock); | ||
1057 | list_for_each_entry(m_list_itr, &sw->mac_list_head, list_entry) { | ||
1058 | u8 *buf = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; | ||
1059 | |||
1060 | if (ether_addr_equal(buf, mac_addr)) { | ||
1061 | mac_ret = m_list_itr; | ||
1062 | break; | ||
1063 | } | ||
1064 | } | ||
1065 | mutex_unlock(&sw->mac_list_lock); | ||
1066 | return mac_ret; | ||
1067 | } | ||
1068 | |||
1069 | /** | ||
1070 | * ice_add_shared_mac - Add one MAC shared filter rule | ||
1071 | * @hw: pointer to the hardware structure | ||
1072 | * @f_entry: structure containing MAC forwarding information | ||
1073 | * | ||
1074 | * Adds or updates the book keeping list for the MAC addresses | ||
1075 | */ | ||
1076 | static enum ice_status | ||
1077 | ice_add_shared_mac(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) | ||
1078 | { | ||
1079 | struct ice_fltr_info *new_fltr, *cur_fltr; | ||
1080 | struct ice_fltr_mgmt_list_entry *m_entry; | ||
1081 | |||
1082 | new_fltr = &f_entry->fltr_info; | ||
1083 | |||
1084 | m_entry = ice_find_mac_entry(hw, &new_fltr->l_data.mac.mac_addr[0]); | ||
1085 | if (!m_entry) | ||
1086 | return ice_create_pkt_fwd_rule(hw, f_entry); | ||
1087 | |||
1088 | cur_fltr = &m_entry->fltr_info; | ||
1089 | |||
1090 | return ice_handle_vsi_list_mgmt(hw, m_entry, cur_fltr, new_fltr); | ||
1091 | } | ||
1092 | |||
1093 | /** | ||
1094 | * ice_add_mac - Add a MAC address based filter rule | ||
1095 | * @hw: pointer to the hardware structure | ||
1096 | * @m_list: list of MAC addresses and forwarding information | ||
1097 | * | ||
1098 | * IMPORTANT: When the ucast_shared flag is set to false and m_list has | ||
1099 | * multiple unicast addresses, the function assumes that all the | ||
1100 | * addresses are unique in a given add_mac call. It doesn't | ||
1101 | * check for duplicates in this case, removing duplicates from a given | ||
1102 | * list should be taken care of in the caller of this function. | ||
1103 | */ | ||
1104 | enum ice_status | ||
1105 | ice_add_mac(struct ice_hw *hw, struct list_head *m_list) | ||
1106 | { | ||
1107 | struct ice_aqc_sw_rules_elem *s_rule, *r_iter; | ||
1108 | struct ice_fltr_list_entry *m_list_itr; | ||
1109 | u16 elem_sent, total_elem_left; | ||
1110 | enum ice_status status = 0; | ||
1111 | u16 num_unicast = 0; | ||
1112 | u16 s_rule_size; | ||
1113 | |||
1114 | if (!m_list || !hw) | ||
1115 | return ICE_ERR_PARAM; | ||
1116 | |||
1117 | list_for_each_entry(m_list_itr, m_list, list_entry) { | ||
1118 | u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; | ||
1119 | |||
1120 | if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC) | ||
1121 | return ICE_ERR_PARAM; | ||
1122 | if (is_zero_ether_addr(add)) | ||
1123 | return ICE_ERR_PARAM; | ||
1124 | if (is_unicast_ether_addr(add) && !hw->ucast_shared) { | ||
1125 | /* Don't overwrite the unicast address */ | ||
1126 | if (ice_find_mac_entry(hw, add)) | ||
1127 | return ICE_ERR_ALREADY_EXISTS; | ||
1128 | num_unicast++; | ||
1129 | } else if (is_multicast_ether_addr(add) || | ||
1130 | (is_unicast_ether_addr(add) && hw->ucast_shared)) { | ||
1131 | status = ice_add_shared_mac(hw, m_list_itr); | ||
1132 | if (status) { | ||
1133 | m_list_itr->status = ICE_FLTR_STATUS_FW_FAIL; | ||
1134 | return status; | ||
1135 | } | ||
1136 | m_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS; | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1140 | /* Exit if no suitable entries were found for adding bulk switch rule */ | ||
1141 | if (!num_unicast) | ||
1142 | return 0; | ||
1143 | |||
1144 | /* Allocate switch rule buffer for the bulk update for unicast */ | ||
1145 | s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE; | ||
1146 | s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size, | ||
1147 | GFP_KERNEL); | ||
1148 | if (!s_rule) | ||
1149 | return ICE_ERR_NO_MEMORY; | ||
1150 | |||
1151 | r_iter = s_rule; | ||
1152 | list_for_each_entry(m_list_itr, m_list, list_entry) { | ||
1153 | struct ice_fltr_info *f_info = &m_list_itr->fltr_info; | ||
1154 | u8 *addr = &f_info->l_data.mac.mac_addr[0]; | ||
1155 | |||
1156 | if (is_unicast_ether_addr(addr)) { | ||
1157 | ice_fill_sw_rule(hw, &m_list_itr->fltr_info, | ||
1158 | r_iter, ice_aqc_opc_add_sw_rules); | ||
1159 | r_iter = (struct ice_aqc_sw_rules_elem *) | ||
1160 | ((u8 *)r_iter + s_rule_size); | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | /* Call AQ bulk switch rule update for all unicast addresses */ | ||
1165 | r_iter = s_rule; | ||
1166 | /* Call AQ switch rule in AQ_MAX chunk */ | ||
1167 | for (total_elem_left = num_unicast; total_elem_left > 0; | ||
1168 | total_elem_left -= elem_sent) { | ||
1169 | struct ice_aqc_sw_rules_elem *entry = r_iter; | ||
1170 | |||
1171 | elem_sent = min(total_elem_left, | ||
1172 | (u16)(ICE_AQ_MAX_BUF_LEN / s_rule_size)); | ||
1173 | status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size, | ||
1174 | elem_sent, ice_aqc_opc_add_sw_rules, | ||
1175 | NULL); | ||
1176 | if (status) | ||
1177 | goto ice_add_mac_exit; | ||
1178 | r_iter = (struct ice_aqc_sw_rules_elem *) | ||
1179 | ((u8 *)r_iter + (elem_sent * s_rule_size)); | ||
1180 | } | ||
1181 | |||
1182 | /* Fill up rule id based on the value returned from FW */ | ||
1183 | r_iter = s_rule; | ||
1184 | list_for_each_entry(m_list_itr, m_list, list_entry) { | ||
1185 | struct ice_fltr_info *f_info = &m_list_itr->fltr_info; | ||
1186 | u8 *addr = &f_info->l_data.mac.mac_addr[0]; | ||
1187 | struct ice_switch_info *sw = hw->switch_info; | ||
1188 | struct ice_fltr_mgmt_list_entry *fm_entry; | ||
1189 | |||
1190 | if (is_unicast_ether_addr(addr)) { | ||
1191 | f_info->fltr_rule_id = | ||
1192 | le16_to_cpu(r_iter->pdata.lkup_tx_rx.index); | ||
1193 | f_info->fltr_act = ICE_FWD_TO_VSI; | ||
1194 | /* Create an entry to track this MAC address */ | ||
1195 | fm_entry = devm_kzalloc(ice_hw_to_dev(hw), | ||
1196 | sizeof(*fm_entry), GFP_KERNEL); | ||
1197 | if (!fm_entry) { | ||
1198 | status = ICE_ERR_NO_MEMORY; | ||
1199 | goto ice_add_mac_exit; | ||
1200 | } | ||
1201 | fm_entry->fltr_info = *f_info; | ||
1202 | fm_entry->vsi_count = 1; | ||
1203 | /* The book keeping entries will get removed when | ||
1204 | * base driver calls remove filter AQ command | ||
1205 | */ | ||
1206 | mutex_lock(&sw->mac_list_lock); | ||
1207 | list_add(&fm_entry->list_entry, &sw->mac_list_head); | ||
1208 | mutex_unlock(&sw->mac_list_lock); | ||
1209 | |||
1210 | r_iter = (struct ice_aqc_sw_rules_elem *) | ||
1211 | ((u8 *)r_iter + s_rule_size); | ||
1212 | } | ||
1213 | } | ||
1214 | |||
1215 | ice_add_mac_exit: | ||
1216 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
1217 | return status; | ||
1218 | } | ||
1219 | |||
1220 | /** | ||
1221 | * ice_remove_vsi_list_rule | ||
1222 | * @hw: pointer to the hardware structure | ||
1223 | * @vsi_list_id: VSI list id generated as part of allocate resource | ||
1224 | * @lkup_type: switch rule filter lookup type | ||
1225 | */ | ||
1226 | static enum ice_status | ||
1227 | ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, | ||
1228 | enum ice_sw_lkup_type lkup_type) | ||
1229 | { | ||
1230 | struct ice_aqc_sw_rules_elem *s_rule; | ||
1231 | enum ice_status status; | ||
1232 | u16 s_rule_size; | ||
1233 | |||
1234 | s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0); | ||
1235 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); | ||
1236 | if (!s_rule) | ||
1237 | return ICE_ERR_NO_MEMORY; | ||
1238 | |||
1239 | s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR); | ||
1240 | s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id); | ||
1241 | /* FW expects number of VSIs in vsi_list resource to be 0 for clear | ||
1242 | * command. Since memory is zero'ed out during initialization, it's not | ||
1243 | * necessary to explicitly initialize the variable to 0. | ||
1244 | */ | ||
1245 | |||
1246 | status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, | ||
1247 | ice_aqc_opc_remove_sw_rules, NULL); | ||
1248 | if (!status) | ||
1249 | /* Free the vsi_list resource that we allocated */ | ||
1250 | status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type, | ||
1251 | ice_aqc_opc_free_res); | ||
1252 | |||
1253 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
1254 | return status; | ||
1255 | } | ||
1256 | |||
1257 | /** | ||
1258 | * ice_handle_rem_vsi_list_mgmt | ||
1259 | * @hw: pointer to the hardware structure | ||
1260 | * @vsi_id: ID of the VSI to remove | ||
1261 | * @fm_list_itr: filter management entry for which the VSI list management | ||
1262 | * needs to be done | ||
1263 | */ | ||
1264 | static enum ice_status | ||
1265 | ice_handle_rem_vsi_list_mgmt(struct ice_hw *hw, u16 vsi_id, | ||
1266 | struct ice_fltr_mgmt_list_entry *fm_list_itr) | ||
1267 | { | ||
1268 | struct ice_switch_info *sw = hw->switch_info; | ||
1269 | enum ice_status status = 0; | ||
1270 | enum ice_sw_lkup_type lkup_type; | ||
1271 | bool is_last_elem = true; | ||
1272 | bool conv_list = false; | ||
1273 | bool del_list = false; | ||
1274 | u16 vsi_list_id; | ||
1275 | |||
1276 | lkup_type = fm_list_itr->fltr_info.lkup_type; | ||
1277 | vsi_list_id = fm_list_itr->fltr_info.fwd_id.vsi_list_id; | ||
1278 | |||
1279 | if (fm_list_itr->vsi_count > 1) { | ||
1280 | status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, | ||
1281 | true, | ||
1282 | ice_aqc_opc_update_sw_rules, | ||
1283 | lkup_type); | ||
1284 | if (status) | ||
1285 | return status; | ||
1286 | fm_list_itr->vsi_count--; | ||
1287 | is_last_elem = false; | ||
1288 | clear_bit(vsi_id, fm_list_itr->vsi_list_info->vsi_map); | ||
1289 | } | ||
1290 | |||
1291 | /* For non-VLAN rules that forward packets to a VSI list, convert them | ||
1292 | * to forwarding packets to a VSI if there is only one VSI left in the | ||
1293 | * list. Unused lists are then removed. | ||
1294 | * VLAN rules need to use VSI lists even with only one VSI. | ||
1295 | */ | ||
1296 | if (fm_list_itr->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST) { | ||
1297 | if (lkup_type == ICE_SW_LKUP_VLAN) { | ||
1298 | del_list = is_last_elem; | ||
1299 | } else if (fm_list_itr->vsi_count == 1) { | ||
1300 | conv_list = true; | ||
1301 | del_list = true; | ||
1302 | } | ||
1303 | } | ||
1304 | |||
1305 | if (del_list) { | ||
1306 | /* Remove the VSI list since it is no longer used */ | ||
1307 | struct ice_vsi_list_map_info *vsi_list_info = | ||
1308 | fm_list_itr->vsi_list_info; | ||
1309 | |||
1310 | status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); | ||
1311 | if (status) | ||
1312 | return status; | ||
1313 | |||
1314 | if (conv_list) { | ||
1315 | u16 rem_vsi_id; | ||
1316 | |||
1317 | rem_vsi_id = find_first_bit(vsi_list_info->vsi_map, | ||
1318 | ICE_MAX_VSI); | ||
1319 | |||
1320 | /* Error out when the expected last element is not in | ||
1321 | * the VSI list map | ||
1322 | */ | ||
1323 | if (rem_vsi_id == ICE_MAX_VSI) | ||
1324 | return ICE_ERR_OUT_OF_RANGE; | ||
1325 | |||
1326 | /* Change the list entry action from VSI_LIST to VSI */ | ||
1327 | fm_list_itr->fltr_info.fltr_act = ICE_FWD_TO_VSI; | ||
1328 | fm_list_itr->fltr_info.fwd_id.vsi_id = rem_vsi_id; | ||
1329 | } | ||
1330 | |||
1331 | list_del(&vsi_list_info->list_entry); | ||
1332 | devm_kfree(ice_hw_to_dev(hw), vsi_list_info); | ||
1333 | fm_list_itr->vsi_list_info = NULL; | ||
1334 | } | ||
1335 | |||
1336 | if (conv_list) { | ||
1337 | /* Convert the rule's forward action to forwarding packets to | ||
1338 | * a VSI | ||
1339 | */ | ||
1340 | struct ice_aqc_sw_rules_elem *s_rule; | ||
1341 | |||
1342 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), | ||
1343 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, | ||
1344 | GFP_KERNEL); | ||
1345 | if (!s_rule) | ||
1346 | return ICE_ERR_NO_MEMORY; | ||
1347 | |||
1348 | ice_fill_sw_rule(hw, &fm_list_itr->fltr_info, s_rule, | ||
1349 | ice_aqc_opc_update_sw_rules); | ||
1350 | |||
1351 | s_rule->pdata.lkup_tx_rx.index = | ||
1352 | cpu_to_le16(fm_list_itr->fltr_info.fltr_rule_id); | ||
1353 | |||
1354 | status = ice_aq_sw_rules(hw, s_rule, | ||
1355 | ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1, | ||
1356 | ice_aqc_opc_update_sw_rules, NULL); | ||
1357 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
1358 | if (status) | ||
1359 | return status; | ||
1360 | } | ||
1361 | |||
1362 | if (is_last_elem) { | ||
1363 | /* Remove the lookup rule */ | ||
1364 | struct ice_aqc_sw_rules_elem *s_rule; | ||
1365 | |||
1366 | s_rule = devm_kzalloc(ice_hw_to_dev(hw), | ||
1367 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE, | ||
1368 | GFP_KERNEL); | ||
1369 | if (!s_rule) | ||
1370 | return ICE_ERR_NO_MEMORY; | ||
1371 | |||
1372 | ice_fill_sw_rule(hw, &fm_list_itr->fltr_info, s_rule, | ||
1373 | ice_aqc_opc_remove_sw_rules); | ||
1374 | |||
1375 | status = ice_aq_sw_rules(hw, s_rule, | ||
1376 | ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1, | ||
1377 | ice_aqc_opc_remove_sw_rules, NULL); | ||
1378 | if (status) | ||
1379 | return status; | ||
1380 | |||
1381 | /* Remove a book keeping entry from the MAC address list */ | ||
1382 | mutex_lock(&sw->mac_list_lock); | ||
1383 | list_del(&fm_list_itr->list_entry); | ||
1384 | mutex_unlock(&sw->mac_list_lock); | ||
1385 | devm_kfree(ice_hw_to_dev(hw), fm_list_itr); | ||
1386 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
1387 | } | ||
1388 | return status; | ||
1389 | } | ||
1390 | |||
1391 | /** | ||
1392 | * ice_remove_mac_entry | ||
1393 | * @hw: pointer to the hardware structure | ||
1394 | * @f_entry: structure containing MAC forwarding information | ||
1395 | */ | ||
1396 | static enum ice_status | ||
1397 | ice_remove_mac_entry(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) | ||
1398 | { | ||
1399 | struct ice_fltr_mgmt_list_entry *m_entry; | ||
1400 | u16 vsi_id; | ||
1401 | u8 *add; | ||
1402 | |||
1403 | add = &f_entry->fltr_info.l_data.mac.mac_addr[0]; | ||
1404 | |||
1405 | m_entry = ice_find_mac_entry(hw, add); | ||
1406 | if (!m_entry) | ||
1407 | return ICE_ERR_PARAM; | ||
1408 | |||
1409 | vsi_id = f_entry->fltr_info.fwd_id.vsi_id; | ||
1410 | return ice_handle_rem_vsi_list_mgmt(hw, vsi_id, m_entry); | ||
1411 | } | ||
1412 | |||
1413 | /** | ||
1414 | * ice_remove_mac - remove a MAC address based filter rule | ||
1415 | * @hw: pointer to the hardware structure | ||
1416 | * @m_list: list of MAC addresses and forwarding information | ||
1417 | * | ||
1418 | * This function removes either a MAC filter rule or a specific VSI from a | ||
1419 | * VSI list for a multicast MAC address. | ||
1420 | * | ||
1421 | * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by | ||
1422 | * ice_add_mac. Caller should be aware that this call will only work if all | ||
1423 | * the entries passed into m_list were added previously. It will not attempt to | ||
1424 | * do a partial remove of entries that were found. | ||
1425 | */ | ||
1426 | enum ice_status | ||
1427 | ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) | ||
1428 | { | ||
1429 | struct ice_aqc_sw_rules_elem *s_rule, *r_iter; | ||
1430 | u8 s_rule_size = ICE_SW_RULE_RX_TX_NO_HDR_SIZE; | ||
1431 | struct ice_switch_info *sw = hw->switch_info; | ||
1432 | struct ice_fltr_mgmt_list_entry *m_entry; | ||
1433 | struct ice_fltr_list_entry *m_list_itr; | ||
1434 | u16 elem_sent, total_elem_left; | ||
1435 | enum ice_status status = 0; | ||
1436 | u16 num_unicast = 0; | ||
1437 | |||
1438 | if (!m_list) | ||
1439 | return ICE_ERR_PARAM; | ||
1440 | |||
1441 | list_for_each_entry(m_list_itr, m_list, list_entry) { | ||
1442 | u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr; | ||
1443 | |||
1444 | if (is_unicast_ether_addr(addr) && !hw->ucast_shared) | ||
1445 | num_unicast++; | ||
1446 | else if (is_multicast_ether_addr(addr) || | ||
1447 | (is_unicast_ether_addr(addr) && hw->ucast_shared)) | ||
1448 | ice_remove_mac_entry(hw, m_list_itr); | ||
1449 | } | ||
1450 | |||
1451 | /* Exit if no unicast addresses found. Multicast switch rules | ||
1452 | * were added individually | ||
1453 | */ | ||
1454 | if (!num_unicast) | ||
1455 | return 0; | ||
1456 | |||
1457 | /* Allocate switch rule buffer for the bulk update for unicast */ | ||
1458 | s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size, | ||
1459 | GFP_KERNEL); | ||
1460 | if (!s_rule) | ||
1461 | return ICE_ERR_NO_MEMORY; | ||
1462 | |||
1463 | r_iter = s_rule; | ||
1464 | list_for_each_entry(m_list_itr, m_list, list_entry) { | ||
1465 | u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr; | ||
1466 | |||
1467 | if (is_unicast_ether_addr(addr)) { | ||
1468 | m_entry = ice_find_mac_entry(hw, addr); | ||
1469 | if (!m_entry) { | ||
1470 | status = ICE_ERR_DOES_NOT_EXIST; | ||
1471 | goto ice_remove_mac_exit; | ||
1472 | } | ||
1473 | |||
1474 | ice_fill_sw_rule(hw, &m_entry->fltr_info, | ||
1475 | r_iter, ice_aqc_opc_remove_sw_rules); | ||
1476 | r_iter = (struct ice_aqc_sw_rules_elem *) | ||
1477 | ((u8 *)r_iter + s_rule_size); | ||
1478 | } | ||
1479 | } | ||
1480 | |||
1481 | /* Call AQ bulk switch rule update for all unicast addresses */ | ||
1482 | r_iter = s_rule; | ||
1483 | /* Call AQ switch rule in AQ_MAX chunk */ | ||
1484 | for (total_elem_left = num_unicast; total_elem_left > 0; | ||
1485 | total_elem_left -= elem_sent) { | ||
1486 | struct ice_aqc_sw_rules_elem *entry = r_iter; | ||
1487 | |||
1488 | elem_sent = min(total_elem_left, | ||
1489 | (u16)(ICE_AQ_MAX_BUF_LEN / s_rule_size)); | ||
1490 | status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size, | ||
1491 | elem_sent, ice_aqc_opc_remove_sw_rules, | ||
1492 | NULL); | ||
1493 | if (status) | ||
1494 | break; | ||
1495 | r_iter = (struct ice_aqc_sw_rules_elem *) | ||
1496 | ((u8 *)r_iter + s_rule_size); | ||
1497 | } | ||
1498 | |||
1499 | list_for_each_entry(m_list_itr, m_list, list_entry) { | ||
1500 | u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr; | ||
1501 | |||
1502 | if (is_unicast_ether_addr(addr)) { | ||
1503 | m_entry = ice_find_mac_entry(hw, addr); | ||
1504 | if (!m_entry) | ||
1505 | return ICE_ERR_OUT_OF_RANGE; | ||
1506 | mutex_lock(&sw->mac_list_lock); | ||
1507 | list_del(&m_entry->list_entry); | ||
1508 | mutex_unlock(&sw->mac_list_lock); | ||
1509 | devm_kfree(ice_hw_to_dev(hw), m_entry); | ||
1510 | } | ||
1511 | } | ||
1512 | |||
1513 | ice_remove_mac_exit: | ||
1514 | devm_kfree(ice_hw_to_dev(hw), s_rule); | ||
1515 | return status; | ||
1516 | } | ||
1517 | |||
1518 | /** | ||
1519 | * ice_add_to_vsi_fltr_list - Add VSI filters to the list | ||
1520 | * @hw: pointer to the hardware structure | ||
1521 | * @vsi_id: ID of VSI to remove filters from | ||
1522 | * @lkup_list_head: pointer to the list that has certain lookup type filters | ||
1523 | * @vsi_list_head: pointer to the list pertaining to VSI with vsi_id | ||
1524 | */ | ||
1525 | static enum ice_status | ||
1526 | ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, | ||
1527 | struct list_head *lkup_list_head, | ||
1528 | struct list_head *vsi_list_head) | ||
1529 | { | ||
1530 | struct ice_fltr_mgmt_list_entry *fm_entry; | ||
1531 | |||
1532 | /* check to make sure VSI id is valid and within boundary */ | ||
1533 | if (vsi_id >= | ||
1534 | (sizeof(fm_entry->vsi_list_info->vsi_map) * BITS_PER_BYTE - 1)) | ||
1535 | return ICE_ERR_PARAM; | ||
1536 | |||
1537 | list_for_each_entry(fm_entry, lkup_list_head, list_entry) { | ||
1538 | struct ice_fltr_info *fi; | ||
1539 | |||
1540 | fi = &fm_entry->fltr_info; | ||
1541 | if ((fi->fltr_act == ICE_FWD_TO_VSI && | ||
1542 | fi->fwd_id.vsi_id == vsi_id) || | ||
1543 | (fi->fltr_act == ICE_FWD_TO_VSI_LIST && | ||
1544 | (test_bit(vsi_id, fm_entry->vsi_list_info->vsi_map)))) { | ||
1545 | struct ice_fltr_list_entry *tmp; | ||
1546 | |||
1547 | /* this memory is freed up in the caller function | ||
1548 | * ice_remove_vsi_lkup_fltr() once filters for | ||
1549 | * this VSI are removed | ||
1550 | */ | ||
1551 | tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), | ||
1552 | GFP_KERNEL); | ||
1553 | if (!tmp) | ||
1554 | return ICE_ERR_NO_MEMORY; | ||
1555 | |||
1556 | memcpy(&tmp->fltr_info, fi, sizeof(*fi)); | ||
1557 | |||
1558 | /* Expected below fields to be set to ICE_FWD_TO_VSI and | ||
1559 | * the particular VSI id since we are only removing this | ||
1560 | * one VSI | ||
1561 | */ | ||
1562 | if (fi->fltr_act == ICE_FWD_TO_VSI_LIST) { | ||
1563 | tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; | ||
1564 | tmp->fltr_info.fwd_id.vsi_id = vsi_id; | ||
1565 | } | ||
1566 | |||
1567 | list_add(&tmp->list_entry, vsi_list_head); | ||
1568 | } | ||
1569 | } | ||
1570 | return 0; | ||
1571 | } | ||
1572 | |||
1573 | /** | ||
1574 | * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI | ||
1575 | * @hw: pointer to the hardware structure | ||
1576 | * @vsi_id: ID of VSI to remove filters from | ||
1577 | * @lkup: switch rule filter lookup type | ||
1578 | */ | ||
1579 | static void | ||
1580 | ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, | ||
1581 | enum ice_sw_lkup_type lkup) | ||
1582 | { | ||
1583 | struct ice_switch_info *sw = hw->switch_info; | ||
1584 | struct ice_fltr_list_entry *fm_entry; | ||
1585 | struct list_head remove_list_head; | ||
1586 | struct ice_fltr_list_entry *tmp; | ||
1587 | enum ice_status status; | ||
1588 | |||
1589 | INIT_LIST_HEAD(&remove_list_head); | ||
1590 | switch (lkup) { | ||
1591 | case ICE_SW_LKUP_MAC: | ||
1592 | mutex_lock(&sw->mac_list_lock); | ||
1593 | status = ice_add_to_vsi_fltr_list(hw, vsi_id, | ||
1594 | &sw->mac_list_head, | ||
1595 | &remove_list_head); | ||
1596 | mutex_unlock(&sw->mac_list_lock); | ||
1597 | if (!status) { | ||
1598 | ice_remove_mac(hw, &remove_list_head); | ||
1599 | goto free_fltr_list; | ||
1600 | } | ||
1601 | break; | ||
1602 | case ICE_SW_LKUP_VLAN: | ||
1603 | case ICE_SW_LKUP_MAC_VLAN: | ||
1604 | case ICE_SW_LKUP_ETHERTYPE: | ||
1605 | case ICE_SW_LKUP_ETHERTYPE_MAC: | ||
1606 | case ICE_SW_LKUP_PROMISC: | ||
1607 | case ICE_SW_LKUP_PROMISC_VLAN: | ||
1608 | case ICE_SW_LKUP_DFLT: | ||
1609 | ice_debug(hw, ICE_DBG_SW, | ||
1610 | "Remove filters for this lookup type hasn't been implemented yet\n"); | ||
1611 | break; | ||
1612 | } | ||
1613 | |||
1614 | return; | ||
1615 | free_fltr_list: | ||
1616 | list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { | ||
1617 | list_del(&fm_entry->list_entry); | ||
1618 | devm_kfree(ice_hw_to_dev(hw), fm_entry); | ||
1619 | } | ||
1620 | } | ||
1621 | |||
1622 | /** | ||
1623 | * ice_remove_vsi_fltr - Remove all filters for a VSI | ||
1624 | * @hw: pointer to the hardware structure | ||
1625 | * @vsi_id: ID of VSI to remove filters from | ||
1626 | */ | ||
1627 | void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id) | ||
1628 | { | ||
1629 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC); | ||
1630 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC_VLAN); | ||
1631 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC); | ||
1632 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_VLAN); | ||
1633 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_DFLT); | ||
1634 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE); | ||
1635 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE_MAC); | ||
1636 | ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC_VLAN); | ||
1637 | } | ||
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index bb8612d8e07b..1b312e7ab2b5 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h | |||
@@ -19,6 +19,122 @@ struct ice_vsi_ctx { | |||
19 | bool alloc_from_pool; | 19 | bool alloc_from_pool; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | enum ice_sw_fwd_act_type { | ||
23 | ICE_FWD_TO_VSI = 0, | ||
24 | ICE_FWD_TO_VSI_LIST, /* Do not use this when adding filter */ | ||
25 | ICE_FWD_TO_Q, | ||
26 | ICE_FWD_TO_QGRP, | ||
27 | ICE_DROP_PACKET, | ||
28 | ICE_INVAL_ACT | ||
29 | }; | ||
30 | |||
31 | /* Switch recipe ID enum values are specific to hardware */ | ||
32 | enum ice_sw_lkup_type { | ||
33 | ICE_SW_LKUP_ETHERTYPE = 0, | ||
34 | ICE_SW_LKUP_MAC = 1, | ||
35 | ICE_SW_LKUP_MAC_VLAN = 2, | ||
36 | ICE_SW_LKUP_PROMISC = 3, | ||
37 | ICE_SW_LKUP_VLAN = 4, | ||
38 | ICE_SW_LKUP_DFLT = 5, | ||
39 | ICE_SW_LKUP_ETHERTYPE_MAC = 8, | ||
40 | ICE_SW_LKUP_PROMISC_VLAN = 9, | ||
41 | }; | ||
42 | |||
43 | struct ice_fltr_info { | ||
44 | /* Look up information: how to look up packet */ | ||
45 | enum ice_sw_lkup_type lkup_type; | ||
46 | /* Forward action: filter action to do after lookup */ | ||
47 | enum ice_sw_fwd_act_type fltr_act; | ||
48 | /* rule ID returned by firmware once filter rule is created */ | ||
49 | u16 fltr_rule_id; | ||
50 | u16 flag; | ||
51 | #define ICE_FLTR_RX BIT(0) | ||
52 | #define ICE_FLTR_TX BIT(1) | ||
53 | #define ICE_FLTR_TX_RX (ICE_FLTR_RX | ICE_FLTR_TX) | ||
54 | |||
55 | /* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */ | ||
56 | u16 src; | ||
57 | |||
58 | union { | ||
59 | struct { | ||
60 | u8 mac_addr[ETH_ALEN]; | ||
61 | } mac; | ||
62 | struct { | ||
63 | u8 mac_addr[ETH_ALEN]; | ||
64 | u16 vlan_id; | ||
65 | } mac_vlan; | ||
66 | struct { | ||
67 | u16 vlan_id; | ||
68 | } vlan; | ||
69 | /* Set lkup_type as ICE_SW_LKUP_ETHERTYPE | ||
70 | * if just using ethertype as filter. Set lkup_type as | ||
71 | * ICE_SW_LKUP_ETHERTYPE_MAC if MAC also needs to be | ||
72 | * passed in as filter. | ||
73 | */ | ||
74 | struct { | ||
75 | u16 ethertype; | ||
76 | u8 mac_addr[ETH_ALEN]; /* optional */ | ||
77 | } ethertype_mac; | ||
78 | } l_data; | ||
79 | |||
80 | /* Depending on filter action */ | ||
81 | union { | ||
82 | /* queue id in case of ICE_FWD_TO_Q and starting | ||
83 | * queue id in case of ICE_FWD_TO_QGRP. | ||
84 | */ | ||
85 | u16 q_id:11; | ||
86 | u16 vsi_id:10; | ||
87 | u16 vsi_list_id:10; | ||
88 | } fwd_id; | ||
89 | |||
90 | /* Set to num_queues if action is ICE_FWD_TO_QGRP. This field | ||
91 | * determines the range of queues the packet needs to be forwarded to | ||
92 | */ | ||
93 | u8 qgrp_size; | ||
94 | |||
95 | /* Rule creations populate these indicators basing on the switch type */ | ||
96 | bool lb_en; /* Indicate if packet can be looped back */ | ||
97 | bool lan_en; /* Indicate if packet can be forwarded to the uplink */ | ||
98 | }; | ||
99 | |||
100 | /* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list id */ | ||
101 | struct ice_vsi_list_map_info { | ||
102 | struct list_head list_entry; | ||
103 | DECLARE_BITMAP(vsi_map, ICE_MAX_VSI); | ||
104 | u16 vsi_list_id; | ||
105 | }; | ||
106 | |||
107 | enum ice_sw_fltr_status { | ||
108 | ICE_FLTR_STATUS_NEW = 0, | ||
109 | ICE_FLTR_STATUS_FW_SUCCESS, | ||
110 | ICE_FLTR_STATUS_FW_FAIL, | ||
111 | }; | ||
112 | |||
113 | struct ice_fltr_list_entry { | ||
114 | struct list_head list_entry; | ||
115 | enum ice_sw_fltr_status status; | ||
116 | struct ice_fltr_info fltr_info; | ||
117 | }; | ||
118 | |||
119 | /* This defines an entry in the list that maintains MAC or VLAN membership | ||
120 | * to HW list mapping, since multiple VSIs can subscribe to the same MAC or | ||
121 | * VLAN. As an optimization the VSI list should be created only when a | ||
122 | * second VSI becomes a subscriber to the VLAN address. | ||
123 | */ | ||
124 | struct ice_fltr_mgmt_list_entry { | ||
125 | /* back pointer to VSI list id to VSI list mapping */ | ||
126 | struct ice_vsi_list_map_info *vsi_list_info; | ||
127 | u16 vsi_count; | ||
128 | #define ICE_INVAL_LG_ACT_INDEX 0xffff | ||
129 | u16 lg_act_idx; | ||
130 | #define ICE_INVAL_SW_MARKER_ID 0xffff | ||
131 | u16 sw_marker_id; | ||
132 | struct list_head list_entry; | ||
133 | struct ice_fltr_info fltr_info; | ||
134 | #define ICE_INVAL_COUNTER_ID 0xff | ||
135 | u8 counter_index; | ||
136 | }; | ||
137 | |||
22 | /* VSI related commands */ | 138 | /* VSI related commands */ |
23 | enum ice_status | 139 | enum ice_status |
24 | ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, | 140 | ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, |
@@ -32,4 +148,8 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, | |||
32 | 148 | ||
33 | enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); | 149 | enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); |
34 | 150 | ||
151 | /* Switch/bridge related commands */ | ||
152 | enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst); | ||
153 | enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst); | ||
154 | void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id); | ||
35 | #endif /* _ICE_SWITCH_H_ */ | 155 | #endif /* _ICE_SWITCH_H_ */ |
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 5f58fd84d558..8926715b76ee 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h | |||
@@ -223,6 +223,22 @@ struct ice_port_info { | |||
223 | bool is_vf; | 223 | bool is_vf; |
224 | }; | 224 | }; |
225 | 225 | ||
226 | struct ice_switch_info { | ||
227 | /* Switch VSI lists to MAC/VLAN translation */ | ||
228 | struct mutex mac_list_lock; /* protect MAC list */ | ||
229 | struct list_head mac_list_head; | ||
230 | struct mutex vlan_list_lock; /* protect VLAN list */ | ||
231 | struct list_head vlan_list_head; | ||
232 | struct mutex eth_m_list_lock; /* protect ethtype list */ | ||
233 | struct list_head eth_m_list_head; | ||
234 | struct mutex promisc_list_lock; /* protect promisc mode list */ | ||
235 | struct list_head promisc_list_head; | ||
236 | struct mutex mac_vlan_list_lock; /* protect MAC-VLAN list */ | ||
237 | struct list_head mac_vlan_list_head; | ||
238 | |||
239 | struct list_head vsi_list_map_head; | ||
240 | }; | ||
241 | |||
226 | /* Port hardware description */ | 242 | /* Port hardware description */ |
227 | struct ice_hw { | 243 | struct ice_hw { |
228 | u8 __iomem *hw_addr; | 244 | u8 __iomem *hw_addr; |
@@ -248,11 +264,14 @@ struct ice_hw { | |||
248 | u8 max_cgds; | 264 | u8 max_cgds; |
249 | u8 sw_entry_point_layer; | 265 | u8 sw_entry_point_layer; |
250 | 266 | ||
267 | bool evb_veb; /* true for VEB, false for VEPA */ | ||
251 | struct ice_bus_info bus; | 268 | struct ice_bus_info bus; |
252 | struct ice_nvm_info nvm; | 269 | struct ice_nvm_info nvm; |
253 | struct ice_hw_dev_caps dev_caps; /* device capabilities */ | 270 | struct ice_hw_dev_caps dev_caps; /* device capabilities */ |
254 | struct ice_hw_func_caps func_caps; /* function capabilities */ | 271 | struct ice_hw_func_caps func_caps; /* function capabilities */ |
255 | 272 | ||
273 | struct ice_switch_info *switch_info; /* switch filter lists */ | ||
274 | |||
256 | /* Control Queue info */ | 275 | /* Control Queue info */ |
257 | struct ice_ctl_q_info adminq; | 276 | struct ice_ctl_q_info adminq; |
258 | 277 | ||
@@ -276,6 +295,8 @@ struct ice_hw { | |||
276 | u8 itr_gran_100; | 295 | u8 itr_gran_100; |
277 | u8 itr_gran_50; | 296 | u8 itr_gran_50; |
278 | u8 itr_gran_25; | 297 | u8 itr_gran_25; |
298 | bool ucast_shared; /* true if VSIs can share unicast addr */ | ||
299 | |||
279 | }; | 300 | }; |
280 | 301 | ||
281 | /* Checksum and Shadow RAM pointers */ | 302 | /* Checksum and Shadow RAM pointers */ |