// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2018-2021, Intel Corporation. */ /* Link Aggregation code */ #include "ice.h" #include "ice_lib.h" #include "ice_lag.h" #define ICE_LAG_RES_SHARED … #define ICE_LAG_RES_VALID … #define LACP_TRAIN_PKT_LEN … static const u8 lacp_train_pkt[LACP_TRAIN_PKT_LEN] = …; #define ICE_RECIPE_LEN … static const u8 ice_dflt_vsi_rcp[ICE_RECIPE_LEN] = …; static const u8 ice_lport_rcp[ICE_RECIPE_LEN] = …; /** * ice_lag_set_primary - set PF LAG state as Primary * @lag: LAG info struct */ static void ice_lag_set_primary(struct ice_lag *lag) { … } /** * ice_lag_set_backup - set PF LAG state to Backup * @lag: LAG info struct */ static void ice_lag_set_backup(struct ice_lag *lag) { … } /** * netif_is_same_ice - determine if netdev is on the same ice NIC as local PF * @pf: local PF struct * @netdev: netdev we are evaluating */ static bool netif_is_same_ice(struct ice_pf *pf, struct net_device *netdev) { … } /** * ice_netdev_to_lag - return pointer to associated lag struct from netdev * @netdev: pointer to net_device struct to query */ static struct ice_lag *ice_netdev_to_lag(struct net_device *netdev) { … } /** * ice_lag_find_hw_by_lport - return an hw struct from bond members lport * @lag: lag struct * @lport: lport value to search for */ static struct ice_hw * ice_lag_find_hw_by_lport(struct ice_lag *lag, u8 lport) { … } /** * ice_pkg_has_lport_extract - check if lport extraction supported * @hw: HW struct */ static bool ice_pkg_has_lport_extract(struct ice_hw *hw) { … } /** * ice_lag_find_primary - returns pointer to primary interfaces lag struct * @lag: local interfaces lag struct */ static struct ice_lag *ice_lag_find_primary(struct ice_lag *lag) { … } /** * ice_lag_cfg_fltr - Add/Remove rule for LAG * @lag: lag struct for local interface * @act: rule action * @recipe_id: recipe id for the new rule * @rule_idx: pointer to rule index * @direction: ICE_FLTR_RX or ICE_FLTR_TX * @add: boolean on whether we are adding filters */ static int ice_lag_cfg_fltr(struct ice_lag *lag, u32 act, u16 recipe_id, u16 *rule_idx, u8 direction, bool add) { … } /** * ice_lag_cfg_dflt_fltr - Add/Remove default VSI rule for LAG * @lag: lag struct for local interface * @add: boolean on whether to add filter */ static int ice_lag_cfg_dflt_fltr(struct ice_lag *lag, bool add) { … } /** * ice_lag_cfg_drop_fltr - Add/Remove lport drop rule * @lag: lag struct for local interface * @add: boolean on whether to add filter */ static int ice_lag_cfg_drop_fltr(struct ice_lag *lag, bool add) { … } /** * ice_lag_cfg_pf_fltrs - set filters up for new active port * @lag: local interfaces lag struct * @ptr: opaque data containing notifier event */ static void ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr) { … } /** * ice_display_lag_info - print LAG info * @lag: LAG info struct */ static void ice_display_lag_info(struct ice_lag *lag) { … } /** * ice_lag_qbuf_recfg - generate a buffer of queues for a reconfigure command * @hw: HW struct that contains the queue contexts * @qbuf: pointer to buffer to populate * @vsi_num: index of the VSI in PF space * @numq: number of queues to search for * @tc: traffic class that contains the queues * * function returns the number of valid queues in buffer */ static u16 ice_lag_qbuf_recfg(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *qbuf, u16 vsi_num, u16 numq, u8 tc) { … } /** * ice_lag_get_sched_parent - locate or create a sched node parent * @hw: HW struct for getting parent in * @tc: traffic class on parent/node */ static struct ice_sched_node * ice_lag_get_sched_parent(struct ice_hw *hw, u8 tc) { … } /** * ice_lag_move_vf_node_tc - move scheduling nodes for one VF on one TC * @lag: lag info struct * @oldport: lport of previous nodes location * @newport: lport of destination nodes location * @vsi_num: array index of VSI in PF space * @tc: traffic class to move */ static void ice_lag_move_vf_node_tc(struct ice_lag *lag, u8 oldport, u8 newport, u16 vsi_num, u8 tc) { … } /** * ice_lag_build_netdev_list - populate the lag struct's netdev list * @lag: local lag struct * @ndlist: pointer to netdev list to populate */ static void ice_lag_build_netdev_list(struct ice_lag *lag, struct ice_lag_netdev_list *ndlist) { … } /** * ice_lag_destroy_netdev_list - free lag struct's netdev list * @lag: pointer to local lag struct * @ndlist: pointer to lag struct netdev list */ static void ice_lag_destroy_netdev_list(struct ice_lag *lag, struct ice_lag_netdev_list *ndlist) { … } /** * ice_lag_move_single_vf_nodes - Move Tx scheduling nodes for single VF * @lag: primary interface LAG struct * @oldport: lport of previous interface * @newport: lport of destination interface * @vsi_num: SW index of VF's VSI */ static void ice_lag_move_single_vf_nodes(struct ice_lag *lag, u8 oldport, u8 newport, u16 vsi_num) { … } /** * ice_lag_move_new_vf_nodes - Move Tx scheduling nodes for a VF if required * @vf: the VF to move Tx nodes for * * Called just after configuring new VF queues. Check whether the VF Tx * scheduling nodes need to be updated to fail over to the active port. If so, * move them now. */ void ice_lag_move_new_vf_nodes(struct ice_vf *vf) { … } /** * ice_lag_move_vf_nodes - move Tx scheduling nodes for all VFs to new port * @lag: lag info struct * @oldport: lport of previous interface * @newport: lport of destination interface */ static void ice_lag_move_vf_nodes(struct ice_lag *lag, u8 oldport, u8 newport) { … } /** * ice_lag_move_vf_nodes_cfg - move vf nodes outside LAG netdev event context * @lag: local lag struct * @src_prt: lport value for source port * @dst_prt: lport value for destination port * * This function is used to move nodes during an out-of-netdev-event situation, * primarily when the driver needs to reconfigure or recreate resources. * * Must be called while holding the lag_mutex to avoid lag events from * processing while out-of-sync moves are happening. Also, paired moves, * such as used in a reset flow, should both be called under the same mutex * lock to avoid changes between start of reset and end of reset. */ void ice_lag_move_vf_nodes_cfg(struct ice_lag *lag, u8 src_prt, u8 dst_prt) { … } #define ICE_LAG_SRIOV_CP_RECIPE … #define ICE_LAG_SRIOV_TRAIN_PKT_LEN … /** * ice_lag_cfg_cp_fltr - configure filter for control packets * @lag: local interface's lag struct * @add: add or remove rule */ static void ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add) { … } /** * ice_lag_info_event - handle NETDEV_BONDING_INFO event * @lag: LAG info struct * @ptr: opaque data pointer * * ptr is to be cast to (netdev_notifier_bonding_info *) */ static void ice_lag_info_event(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_reclaim_vf_tc - move scheduling nodes back to primary interface * @lag: primary interface lag struct * @src_hw: HW struct current node location * @vsi_num: VSI index in PF space * @tc: traffic class to move */ static void ice_lag_reclaim_vf_tc(struct ice_lag *lag, struct ice_hw *src_hw, u16 vsi_num, u8 tc) { … } /** * ice_lag_reclaim_vf_nodes - When interface leaving bond primary reclaims nodes * @lag: primary interface lag struct * @src_hw: HW struct for current node location */ static void ice_lag_reclaim_vf_nodes(struct ice_lag *lag, struct ice_hw *src_hw) { … } /** * ice_lag_link - handle LAG link event * @lag: LAG info struct */ static void ice_lag_link(struct ice_lag *lag) { … } /** * ice_lag_unlink - handle unlink event * @lag: LAG info struct */ static void ice_lag_unlink(struct ice_lag *lag) { … } /** * ice_lag_link_unlink - helper function to call lag_link/unlink * @lag: lag info struct * @ptr: opaque pointer data */ static void ice_lag_link_unlink(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_set_swid - set the SWID on secondary interface * @primary_swid: primary interface's SWID * @local_lag: local interfaces LAG struct * @link: Is this a linking activity * * If link is false, then primary_swid should be expected to not be valid * This function should never be called in interrupt context. */ static void ice_lag_set_swid(u16 primary_swid, struct ice_lag *local_lag, bool link) { … } /** * ice_lag_primary_swid - set/clear the SHARED attrib of primary's SWID * @lag: primary interface's lag struct * @link: is this a linking activity * * Implement setting primary SWID as shared using 0x020B */ static void ice_lag_primary_swid(struct ice_lag *lag, bool link) { … } /** * ice_lag_add_prune_list - Adds event_pf's VSI to primary's prune list * @lag: lag info struct * @event_pf: PF struct for VSI we are adding to primary's prune list */ static void ice_lag_add_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) { … } /** * ice_lag_del_prune_list - Remove secondary's vsi from primary's prune list * @lag: primary interface's ice_lag struct * @event_pf: PF struct for unlinking interface */ static void ice_lag_del_prune_list(struct ice_lag *lag, struct ice_pf *event_pf) { … } /** * ice_lag_init_feature_support_flag - Check for package and NVM support for LAG * @pf: PF struct */ static void ice_lag_init_feature_support_flag(struct ice_pf *pf) { … } /** * ice_lag_changeupper_event - handle LAG changeupper event * @lag: LAG info struct * @ptr: opaque pointer data */ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_monitor_link - monitor interfaces entering/leaving the aggregate * @lag: lag info struct * @ptr: opaque data containing notifier event * * This function only operates after a primary has been set. */ static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_monitor_active - main PF keep track of which port is active * @lag: lag info struct * @ptr: opaque data containing notifier event * * This function is for the primary PF to monitor changes in which port is * active and handle changes for SRIOV VF functionality */ static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_chk_comp - evaluate bonded interface for feature support * @lag: lag info struct * @ptr: opaque data for netdev event info */ static bool ice_lag_chk_comp(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_unregister - handle netdev unregister events * @lag: LAG info struct * @event_netdev: netdev struct for target of notifier event */ static void ice_lag_unregister(struct ice_lag *lag, struct net_device *event_netdev) { … } /** * ice_lag_monitor_rdma - set and clear rdma functionality * @lag: pointer to lag struct * @ptr: opaque data for netdev event info */ static void ice_lag_monitor_rdma(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_chk_disabled_bond - monitor interfaces entering/leaving disabled bond * @lag: lag info struct * @ptr: opaque data containing event * * as interfaces enter a bond - determine if the bond is currently * SRIOV LAG compliant and flag if not. As interfaces leave the * bond, reset their compliant status. */ static void ice_lag_chk_disabled_bond(struct ice_lag *lag, void *ptr) { … } /** * ice_lag_disable_sriov_bond - set members of bond as not supporting SRIOV LAG * @lag: primary interfaces lag struct */ static void ice_lag_disable_sriov_bond(struct ice_lag *lag) { … } /** * ice_lag_process_event - process a task assigned to the lag_wq * @work: pointer to work_struct */ static void ice_lag_process_event(struct work_struct *work) { … } /** * ice_lag_event_handler - handle LAG events from netdev * @notif_blk: notifier block registered by this netdev * @event: event type * @ptr: opaque data containing notifier event */ static int ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event, void *ptr) { … } /** * ice_register_lag_handler - register LAG handler on netdev * @lag: LAG struct */ static int ice_register_lag_handler(struct ice_lag *lag) { … } /** * ice_unregister_lag_handler - unregister LAG handler on netdev * @lag: LAG struct */ static void ice_unregister_lag_handler(struct ice_lag *lag) { … } /** * ice_create_lag_recipe * @hw: pointer to HW struct * @rid: pointer to u16 to pass back recipe index * @base_recipe: recipe to base the new recipe on * @prio: priority for new recipe * * function returns 0 on error */ static int ice_create_lag_recipe(struct ice_hw *hw, u16 *rid, const u8 *base_recipe, u8 prio) { … } /** * ice_lag_move_vf_nodes_tc_sync - move a VF's nodes for a tc during reset * @lag: primary interfaces lag struct * @dest_hw: HW struct for destination's interface * @vsi_num: VSI index in PF space * @tc: traffic class to move */ static void ice_lag_move_vf_nodes_tc_sync(struct ice_lag *lag, struct ice_hw *dest_hw, u16 vsi_num, u8 tc) { … } /** * ice_lag_move_vf_nodes_sync - move vf nodes to active interface * @lag: primary interfaces lag struct * @dest_hw: lport value for currently active port * * This function is used in a reset context, outside of event handling, * to move the VF nodes to the secondary interface when that interface * is the active interface during a reset rebuild */ static void ice_lag_move_vf_nodes_sync(struct ice_lag *lag, struct ice_hw *dest_hw) { … } /** * ice_init_lag - initialize support for LAG * @pf: PF struct * * Alloc memory for LAG structs and initialize the elements. * Memory will be freed in ice_deinit_lag */ int ice_init_lag(struct ice_pf *pf) { … } /** * ice_deinit_lag - Clean up LAG * @pf: PF struct * * Clean up kernel LAG info and free memory * This function is meant to only be called on driver remove/shutdown */ void ice_deinit_lag(struct ice_pf *pf) { … } /** * ice_lag_rebuild - rebuild lag resources after reset * @pf: pointer to local pf struct * * PF resets are promoted to CORER resets when interface in an aggregate. This * means that we need to rebuild the PF resources for the interface. Since * this will happen outside the normal event processing, need to acquire the lag * lock. * * This function will also evaluate the VF resources if this is the primary * interface. */ void ice_lag_rebuild(struct ice_pf *pf) { … } /** * ice_lag_is_switchdev_running * @pf: pointer to PF structure * * Check if switchdev is running on any of the interfaces connected to lag. */ bool ice_lag_is_switchdev_running(struct ice_pf *pf) { … }