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 /drivers/net/ethernet/intel | |
| 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>
Diffstat (limited to 'drivers/net/ethernet/intel')
| -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 */ |
