162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "fm10k_pf.h" 562306a36Sopenharmony_ci#include "fm10k_vf.h" 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/** 862306a36Sopenharmony_ci * fm10k_reset_hw_pf - PF hardware reset 962306a36Sopenharmony_ci * @hw: pointer to hardware structure 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * This function should return the hardware to a state similar to the 1262306a36Sopenharmony_ci * one it is in after being powered on. 1362306a36Sopenharmony_ci **/ 1462306a36Sopenharmony_cistatic s32 fm10k_reset_hw_pf(struct fm10k_hw *hw) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci s32 err; 1762306a36Sopenharmony_ci u32 reg; 1862306a36Sopenharmony_ci u16 i; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci /* Disable interrupts */ 2162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_EIMR, FM10K_EIMR_DISABLE(ALL)); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci /* Lock ITR2 reg 0 into itself and disable interrupt moderation */ 2462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(0), 0); 2562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_INT_CTRL, 0); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci /* We assume here Tx and Rx queue 0 are owned by the PF */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* Shut off VF access to their queues forcing them to queue 0 */ 3062306a36Sopenharmony_ci for (i = 0; i < FM10K_TQMAP_TABLE_SIZE; i++) { 3162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(i), 0); 3262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RQMAP(i), 0); 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* shut down all rings */ 3662306a36Sopenharmony_ci err = fm10k_disable_queues_generic(hw, FM10K_MAX_QUEUES); 3762306a36Sopenharmony_ci if (err == FM10K_ERR_REQUESTS_PENDING) { 3862306a36Sopenharmony_ci hw->mac.reset_while_pending++; 3962306a36Sopenharmony_ci goto force_reset; 4062306a36Sopenharmony_ci } else if (err) { 4162306a36Sopenharmony_ci return err; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* Verify that DMA is no longer active */ 4562306a36Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_DMA_CTRL); 4662306a36Sopenharmony_ci if (reg & (FM10K_DMA_CTRL_TX_ACTIVE | FM10K_DMA_CTRL_RX_ACTIVE)) 4762306a36Sopenharmony_ci return FM10K_ERR_DMA_PENDING; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciforce_reset: 5062306a36Sopenharmony_ci /* Inititate data path reset */ 5162306a36Sopenharmony_ci reg = FM10K_DMA_CTRL_DATAPATH_RESET; 5262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DMA_CTRL, reg); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* Flush write and allow 100us for reset to complete */ 5562306a36Sopenharmony_ci fm10k_write_flush(hw); 5662306a36Sopenharmony_ci udelay(FM10K_RESET_TIMEOUT); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Verify we made it out of reset */ 5962306a36Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_IP); 6062306a36Sopenharmony_ci if (!(reg & FM10K_IP_NOTINRESET)) 6162306a36Sopenharmony_ci return FM10K_ERR_RESET_FAILED; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/** 6762306a36Sopenharmony_ci * fm10k_is_ari_hierarchy_pf - Indicate ARI hierarchy support 6862306a36Sopenharmony_ci * @hw: pointer to hardware structure 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Looks at the ARI hierarchy bit to determine whether ARI is supported or not. 7162306a36Sopenharmony_ci **/ 7262306a36Sopenharmony_cistatic bool fm10k_is_ari_hierarchy_pf(struct fm10k_hw *hw) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci u16 sriov_ctrl = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_SRIOV_CTRL); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return !!(sriov_ctrl & FM10K_PCIE_SRIOV_CTRL_VFARI); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/** 8062306a36Sopenharmony_ci * fm10k_init_hw_pf - PF hardware initialization 8162306a36Sopenharmony_ci * @hw: pointer to hardware structure 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci **/ 8462306a36Sopenharmony_cistatic s32 fm10k_init_hw_pf(struct fm10k_hw *hw) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci u32 dma_ctrl, txqctl; 8762306a36Sopenharmony_ci u16 i; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Establish default VSI as valid */ 9062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DGLORTDEC(fm10k_dglort_default), 0); 9162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_default), 9262306a36Sopenharmony_ci FM10K_DGLORTMAP_ANY); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Invalidate all other GLORT entries */ 9562306a36Sopenharmony_ci for (i = 1; i < FM10K_DGLORT_COUNT; i++) 9662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DGLORTMAP(i), FM10K_DGLORTMAP_NONE); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* reset ITR2(0) to point to itself */ 9962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(0), 0); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* reset VF ITR2(0) to point to 0 avoid PF registers */ 10262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), 0); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* loop through all PF ITR2 registers pointing them to the previous */ 10562306a36Sopenharmony_ci for (i = 1; i < FM10K_ITR_REG_COUNT_PF; i++) 10662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(i), i - 1); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Enable interrupt moderator if not already enabled */ 10962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* compute the default txqctl configuration */ 11262306a36Sopenharmony_ci txqctl = FM10K_TXQCTL_PF | FM10K_TXQCTL_UNLIMITED_BW | 11362306a36Sopenharmony_ci (hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci for (i = 0; i < FM10K_MAX_QUEUES; i++) { 11662306a36Sopenharmony_ci /* configure rings for 256 Queue / 32 Descriptor cache mode */ 11762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQDLOC(i), 11862306a36Sopenharmony_ci (i * FM10K_TQDLOC_BASE_32_DESC) | 11962306a36Sopenharmony_ci FM10K_TQDLOC_SIZE_32_DESC); 12062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXQCTL(i), txqctl); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* configure rings to provide TPH processing hints */ 12362306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TPH_TXCTRL(i), 12462306a36Sopenharmony_ci FM10K_TPH_TXCTRL_DESC_TPHEN | 12562306a36Sopenharmony_ci FM10K_TPH_TXCTRL_DESC_RROEN | 12662306a36Sopenharmony_ci FM10K_TPH_TXCTRL_DESC_WROEN | 12762306a36Sopenharmony_ci FM10K_TPH_TXCTRL_DATA_RROEN); 12862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TPH_RXCTRL(i), 12962306a36Sopenharmony_ci FM10K_TPH_RXCTRL_DESC_TPHEN | 13062306a36Sopenharmony_ci FM10K_TPH_RXCTRL_DESC_RROEN | 13162306a36Sopenharmony_ci FM10K_TPH_RXCTRL_DATA_WROEN | 13262306a36Sopenharmony_ci FM10K_TPH_RXCTRL_HDR_WROEN); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* set max hold interval to align with 1.024 usec in all modes and 13662306a36Sopenharmony_ci * store ITR scale 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci switch (hw->bus.speed) { 13962306a36Sopenharmony_ci case fm10k_bus_speed_2500: 14062306a36Sopenharmony_ci dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1; 14162306a36Sopenharmony_ci hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN1; 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case fm10k_bus_speed_5000: 14462306a36Sopenharmony_ci dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2; 14562306a36Sopenharmony_ci hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN2; 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci case fm10k_bus_speed_8000: 14862306a36Sopenharmony_ci dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3; 14962306a36Sopenharmony_ci hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3; 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci default: 15262306a36Sopenharmony_ci dma_ctrl = 0; 15362306a36Sopenharmony_ci /* just in case, assume Gen3 ITR scale */ 15462306a36Sopenharmony_ci hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3; 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Configure TSO flags */ 15962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DTXTCPFLGL, FM10K_TSO_FLAGS_LOW); 16062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DTXTCPFLGH, FM10K_TSO_FLAGS_HI); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Enable DMA engine 16362306a36Sopenharmony_ci * Set Rx Descriptor size to 32 16462306a36Sopenharmony_ci * Set Minimum MSS to 64 16562306a36Sopenharmony_ci * Set Maximum number of Rx queues to 256 / 32 Descriptor 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci dma_ctrl |= FM10K_DMA_CTRL_TX_ENABLE | FM10K_DMA_CTRL_RX_ENABLE | 16862306a36Sopenharmony_ci FM10K_DMA_CTRL_RX_DESC_SIZE | FM10K_DMA_CTRL_MINMSS_64 | 16962306a36Sopenharmony_ci FM10K_DMA_CTRL_32_DESC; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DMA_CTRL, dma_ctrl); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* record maximum queue count, we limit ourselves to 128 */ 17462306a36Sopenharmony_ci hw->mac.max_queues = FM10K_MAX_QUEUES_PF; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* We support either 64 VFs or 7 VFs depending on if we have ARI */ 17762306a36Sopenharmony_ci hw->iov.total_vfs = fm10k_is_ari_hierarchy_pf(hw) ? 64 : 7; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/** 18362306a36Sopenharmony_ci * fm10k_update_vlan_pf - Update status of VLAN ID in VLAN filter table 18462306a36Sopenharmony_ci * @hw: pointer to hardware structure 18562306a36Sopenharmony_ci * @vid: VLAN ID to add to table 18662306a36Sopenharmony_ci * @vsi: Index indicating VF ID or PF ID in table 18762306a36Sopenharmony_ci * @set: Indicates if this is a set or clear operation 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * This function adds or removes the corresponding VLAN ID from the VLAN 19062306a36Sopenharmony_ci * filter table for the corresponding function. In addition to the 19162306a36Sopenharmony_ci * standard set/clear that supports one bit a multi-bit write is 19262306a36Sopenharmony_ci * supported to set 64 bits at a time. 19362306a36Sopenharmony_ci **/ 19462306a36Sopenharmony_cistatic s32 fm10k_update_vlan_pf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci u32 vlan_table, reg, mask, bit, len; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* verify the VSI index is valid */ 19962306a36Sopenharmony_ci if (vsi > FM10K_VLAN_TABLE_VSI_MAX) 20062306a36Sopenharmony_ci return FM10K_ERR_PARAM; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* VLAN multi-bit write: 20362306a36Sopenharmony_ci * The multi-bit write has several parts to it. 20462306a36Sopenharmony_ci * 24 16 8 0 20562306a36Sopenharmony_ci * 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 20662306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 20762306a36Sopenharmony_ci * | RSVD0 | Length |C|RSVD0| VLAN ID | 20862306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * VLAN ID: Vlan Starting value 21162306a36Sopenharmony_ci * RSVD0: Reserved section, must be 0 21262306a36Sopenharmony_ci * C: Flag field, 0 is set, 1 is clear (Used in VF VLAN message) 21362306a36Sopenharmony_ci * Length: Number of times to repeat the bit being set 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci len = vid >> 16; 21662306a36Sopenharmony_ci vid = (vid << 17) >> 17; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* verify the reserved 0 fields are 0 */ 21962306a36Sopenharmony_ci if (len >= FM10K_VLAN_TABLE_VID_MAX || vid >= FM10K_VLAN_TABLE_VID_MAX) 22062306a36Sopenharmony_ci return FM10K_ERR_PARAM; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Loop through the table updating all required VLANs */ 22362306a36Sopenharmony_ci for (reg = FM10K_VLAN_TABLE(vsi, vid / 32), bit = vid % 32; 22462306a36Sopenharmony_ci len < FM10K_VLAN_TABLE_VID_MAX; 22562306a36Sopenharmony_ci len -= 32 - bit, reg++, bit = 0) { 22662306a36Sopenharmony_ci /* record the initial state of the register */ 22762306a36Sopenharmony_ci vlan_table = fm10k_read_reg(hw, reg); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* truncate mask if we are at the start or end of the run */ 23062306a36Sopenharmony_ci mask = (~(u32)0 >> ((len < 31) ? 31 - len : 0)) << bit; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* make necessary modifications to the register */ 23362306a36Sopenharmony_ci mask &= set ? ~vlan_table : vlan_table; 23462306a36Sopenharmony_ci if (mask) 23562306a36Sopenharmony_ci fm10k_write_reg(hw, reg, vlan_table ^ mask); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * fm10k_read_mac_addr_pf - Read device MAC address 24362306a36Sopenharmony_ci * @hw: pointer to the HW structure 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * Reads the device MAC address from the SM_AREA and stores the value. 24662306a36Sopenharmony_ci **/ 24762306a36Sopenharmony_cistatic s32 fm10k_read_mac_addr_pf(struct fm10k_hw *hw) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci u8 perm_addr[ETH_ALEN]; 25062306a36Sopenharmony_ci u32 serial_num; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci serial_num = fm10k_read_reg(hw, FM10K_SM_AREA(1)); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* last byte should be all 1's */ 25562306a36Sopenharmony_ci if ((~serial_num) << 24) 25662306a36Sopenharmony_ci return FM10K_ERR_INVALID_MAC_ADDR; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci perm_addr[0] = (u8)(serial_num >> 24); 25962306a36Sopenharmony_ci perm_addr[1] = (u8)(serial_num >> 16); 26062306a36Sopenharmony_ci perm_addr[2] = (u8)(serial_num >> 8); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci serial_num = fm10k_read_reg(hw, FM10K_SM_AREA(0)); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* first byte should be all 1's */ 26562306a36Sopenharmony_ci if ((~serial_num) >> 24) 26662306a36Sopenharmony_ci return FM10K_ERR_INVALID_MAC_ADDR; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci perm_addr[3] = (u8)(serial_num >> 16); 26962306a36Sopenharmony_ci perm_addr[4] = (u8)(serial_num >> 8); 27062306a36Sopenharmony_ci perm_addr[5] = (u8)(serial_num); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ether_addr_copy(hw->mac.perm_addr, perm_addr); 27362306a36Sopenharmony_ci ether_addr_copy(hw->mac.addr, perm_addr); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/** 27962306a36Sopenharmony_ci * fm10k_glort_valid_pf - Validate that the provided glort is valid 28062306a36Sopenharmony_ci * @hw: pointer to the HW structure 28162306a36Sopenharmony_ci * @glort: base glort to be validated 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * This function will return an error if the provided glort is invalid 28462306a36Sopenharmony_ci **/ 28562306a36Sopenharmony_cibool fm10k_glort_valid_pf(struct fm10k_hw *hw, u16 glort) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci glort &= hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return glort == (hw->mac.dglort_map & FM10K_DGLORTMAP_NONE); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/** 29362306a36Sopenharmony_ci * fm10k_update_xc_addr_pf - Update device addresses 29462306a36Sopenharmony_ci * @hw: pointer to the HW structure 29562306a36Sopenharmony_ci * @glort: base resource tag for this request 29662306a36Sopenharmony_ci * @mac: MAC address to add/remove from table 29762306a36Sopenharmony_ci * @vid: VLAN ID to add/remove from table 29862306a36Sopenharmony_ci * @add: Indicates if this is an add or remove operation 29962306a36Sopenharmony_ci * @flags: flags field to indicate add and secure 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * This function generates a message to the Switch API requesting 30262306a36Sopenharmony_ci * that the given logical port add/remove the given L2 MAC/VLAN address. 30362306a36Sopenharmony_ci **/ 30462306a36Sopenharmony_cistatic s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort, 30562306a36Sopenharmony_ci const u8 *mac, u16 vid, bool add, u8 flags) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct fm10k_mbx_info *mbx = &hw->mbx; 30862306a36Sopenharmony_ci struct fm10k_mac_update mac_update; 30962306a36Sopenharmony_ci u32 msg[5]; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* clear set bit from VLAN ID */ 31262306a36Sopenharmony_ci vid &= ~FM10K_VLAN_CLEAR; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* if glort or VLAN are not valid return error */ 31562306a36Sopenharmony_ci if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX) 31662306a36Sopenharmony_ci return FM10K_ERR_PARAM; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* record fields */ 31962306a36Sopenharmony_ci mac_update.mac_lower = cpu_to_le32(((u32)mac[2] << 24) | 32062306a36Sopenharmony_ci ((u32)mac[3] << 16) | 32162306a36Sopenharmony_ci ((u32)mac[4] << 8) | 32262306a36Sopenharmony_ci ((u32)mac[5])); 32362306a36Sopenharmony_ci mac_update.mac_upper = cpu_to_le16(((u16)mac[0] << 8) | 32462306a36Sopenharmony_ci ((u16)mac[1])); 32562306a36Sopenharmony_ci mac_update.vlan = cpu_to_le16(vid); 32662306a36Sopenharmony_ci mac_update.glort = cpu_to_le16(glort); 32762306a36Sopenharmony_ci mac_update.action = add ? 0 : 1; 32862306a36Sopenharmony_ci mac_update.flags = flags; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* populate mac_update fields */ 33162306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_UPDATE_MAC_FWD_RULE); 33262306a36Sopenharmony_ci fm10k_tlv_attr_put_le_struct(msg, FM10K_PF_ATTR_ID_MAC_UPDATE, 33362306a36Sopenharmony_ci &mac_update, sizeof(mac_update)); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* load onto outgoing mailbox */ 33662306a36Sopenharmony_ci return mbx->ops.enqueue_tx(hw, mbx, msg); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/** 34062306a36Sopenharmony_ci * fm10k_update_uc_addr_pf - Update device unicast addresses 34162306a36Sopenharmony_ci * @hw: pointer to the HW structure 34262306a36Sopenharmony_ci * @glort: base resource tag for this request 34362306a36Sopenharmony_ci * @mac: MAC address to add/remove from table 34462306a36Sopenharmony_ci * @vid: VLAN ID to add/remove from table 34562306a36Sopenharmony_ci * @add: Indicates if this is an add or remove operation 34662306a36Sopenharmony_ci * @flags: flags field to indicate add and secure 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * This function is used to add or remove unicast addresses for 34962306a36Sopenharmony_ci * the PF. 35062306a36Sopenharmony_ci **/ 35162306a36Sopenharmony_cistatic s32 fm10k_update_uc_addr_pf(struct fm10k_hw *hw, u16 glort, 35262306a36Sopenharmony_ci const u8 *mac, u16 vid, bool add, u8 flags) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci /* verify MAC address is valid */ 35562306a36Sopenharmony_ci if (!is_valid_ether_addr(mac)) 35662306a36Sopenharmony_ci return FM10K_ERR_PARAM; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, flags); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/** 36262306a36Sopenharmony_ci * fm10k_update_mc_addr_pf - Update device multicast addresses 36362306a36Sopenharmony_ci * @hw: pointer to the HW structure 36462306a36Sopenharmony_ci * @glort: base resource tag for this request 36562306a36Sopenharmony_ci * @mac: MAC address to add/remove from table 36662306a36Sopenharmony_ci * @vid: VLAN ID to add/remove from table 36762306a36Sopenharmony_ci * @add: Indicates if this is an add or remove operation 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * This function is used to add or remove multicast MAC addresses for 37062306a36Sopenharmony_ci * the PF. 37162306a36Sopenharmony_ci **/ 37262306a36Sopenharmony_cistatic s32 fm10k_update_mc_addr_pf(struct fm10k_hw *hw, u16 glort, 37362306a36Sopenharmony_ci const u8 *mac, u16 vid, bool add) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci /* verify multicast address is valid */ 37662306a36Sopenharmony_ci if (!is_multicast_ether_addr(mac)) 37762306a36Sopenharmony_ci return FM10K_ERR_PARAM; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, 0); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/** 38362306a36Sopenharmony_ci * fm10k_update_xcast_mode_pf - Request update of multicast mode 38462306a36Sopenharmony_ci * @hw: pointer to hardware structure 38562306a36Sopenharmony_ci * @glort: base resource tag for this request 38662306a36Sopenharmony_ci * @mode: integer value indicating mode being requested 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * This function will attempt to request a higher mode for the port 38962306a36Sopenharmony_ci * so that it can enable either multicast, multicast promiscuous, or 39062306a36Sopenharmony_ci * promiscuous mode of operation. 39162306a36Sopenharmony_ci **/ 39262306a36Sopenharmony_cistatic s32 fm10k_update_xcast_mode_pf(struct fm10k_hw *hw, u16 glort, u8 mode) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct fm10k_mbx_info *mbx = &hw->mbx; 39562306a36Sopenharmony_ci u32 msg[3], xcast_mode; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (mode > FM10K_XCAST_MODE_NONE) 39862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* if glort is not valid return error */ 40162306a36Sopenharmony_ci if (!fm10k_glort_valid_pf(hw, glort)) 40262306a36Sopenharmony_ci return FM10K_ERR_PARAM; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* write xcast mode as a single u32 value, 40562306a36Sopenharmony_ci * lower 16 bits: glort 40662306a36Sopenharmony_ci * upper 16 bits: mode 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_ci xcast_mode = ((u32)mode << 16) | glort; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* generate message requesting to change xcast mode */ 41162306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_XCAST_MODES); 41262306a36Sopenharmony_ci fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_XCAST_MODE, xcast_mode); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* load onto outgoing mailbox */ 41562306a36Sopenharmony_ci return mbx->ops.enqueue_tx(hw, mbx, msg); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/** 41962306a36Sopenharmony_ci * fm10k_update_int_moderator_pf - Update interrupt moderator linked list 42062306a36Sopenharmony_ci * @hw: pointer to hardware structure 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * This function walks through the MSI-X vector table to determine the 42362306a36Sopenharmony_ci * number of active interrupts and based on that information updates the 42462306a36Sopenharmony_ci * interrupt moderator linked list. 42562306a36Sopenharmony_ci **/ 42662306a36Sopenharmony_cistatic void fm10k_update_int_moderator_pf(struct fm10k_hw *hw) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci u32 i; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Disable interrupt moderator */ 43162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_INT_CTRL, 0); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* loop through PF from last to first looking enabled vectors */ 43462306a36Sopenharmony_ci for (i = FM10K_ITR_REG_COUNT_PF - 1; i; i--) { 43562306a36Sopenharmony_ci if (!fm10k_read_reg(hw, FM10K_MSIX_VECTOR_MASK(i))) 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* always reset VFITR2[0] to point to last enabled PF vector */ 44062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), i); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* reset ITR2[0] to point to last enabled PF vector */ 44362306a36Sopenharmony_ci if (!hw->iov.num_vfs) 44462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(0), i); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* Enable interrupt moderator */ 44762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/** 45162306a36Sopenharmony_ci * fm10k_update_lport_state_pf - Notify the switch of a change in port state 45262306a36Sopenharmony_ci * @hw: pointer to the HW structure 45362306a36Sopenharmony_ci * @glort: base resource tag for this request 45462306a36Sopenharmony_ci * @count: number of logical ports being updated 45562306a36Sopenharmony_ci * @enable: boolean value indicating enable or disable 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci * This function is used to add/remove a logical port from the switch. 45862306a36Sopenharmony_ci **/ 45962306a36Sopenharmony_cistatic s32 fm10k_update_lport_state_pf(struct fm10k_hw *hw, u16 glort, 46062306a36Sopenharmony_ci u16 count, bool enable) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct fm10k_mbx_info *mbx = &hw->mbx; 46362306a36Sopenharmony_ci u32 msg[3], lport_msg; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* do nothing if we are being asked to create or destroy 0 ports */ 46662306a36Sopenharmony_ci if (!count) 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* if glort is not valid return error */ 47062306a36Sopenharmony_ci if (!fm10k_glort_valid_pf(hw, glort)) 47162306a36Sopenharmony_ci return FM10K_ERR_PARAM; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* reset multicast mode if deleting lport */ 47462306a36Sopenharmony_ci if (!enable) 47562306a36Sopenharmony_ci fm10k_update_xcast_mode_pf(hw, glort, FM10K_XCAST_MODE_NONE); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* construct the lport message from the 2 pieces of data we have */ 47862306a36Sopenharmony_ci lport_msg = ((u32)count << 16) | glort; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* generate lport create/delete message */ 48162306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, enable ? FM10K_PF_MSG_ID_LPORT_CREATE : 48262306a36Sopenharmony_ci FM10K_PF_MSG_ID_LPORT_DELETE); 48362306a36Sopenharmony_ci fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_PORT, lport_msg); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* load onto outgoing mailbox */ 48662306a36Sopenharmony_ci return mbx->ops.enqueue_tx(hw, mbx, msg); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/** 49062306a36Sopenharmony_ci * fm10k_configure_dglort_map_pf - Configures GLORT entry and queues 49162306a36Sopenharmony_ci * @hw: pointer to hardware structure 49262306a36Sopenharmony_ci * @dglort: pointer to dglort configuration structure 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * Reads the configuration structure contained in dglort_cfg and uses 49562306a36Sopenharmony_ci * that information to then populate a DGLORTMAP/DEC entry and the queues 49662306a36Sopenharmony_ci * to which it has been assigned. 49762306a36Sopenharmony_ci **/ 49862306a36Sopenharmony_cistatic s32 fm10k_configure_dglort_map_pf(struct fm10k_hw *hw, 49962306a36Sopenharmony_ci struct fm10k_dglort_cfg *dglort) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci u16 glort, queue_count, vsi_count, pc_count; 50262306a36Sopenharmony_ci u16 vsi, queue, pc, q_idx; 50362306a36Sopenharmony_ci u32 txqctl, dglortdec, dglortmap; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* verify the dglort pointer */ 50662306a36Sopenharmony_ci if (!dglort) 50762306a36Sopenharmony_ci return FM10K_ERR_PARAM; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* verify the dglort values */ 51062306a36Sopenharmony_ci if ((dglort->idx > 7) || (dglort->rss_l > 7) || (dglort->pc_l > 3) || 51162306a36Sopenharmony_ci (dglort->vsi_l > 6) || (dglort->vsi_b > 64) || 51262306a36Sopenharmony_ci (dglort->queue_l > 8) || (dglort->queue_b >= 256)) 51362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* determine count of VSIs and queues */ 51662306a36Sopenharmony_ci queue_count = BIT(dglort->rss_l + dglort->pc_l); 51762306a36Sopenharmony_ci vsi_count = BIT(dglort->vsi_l + dglort->queue_l); 51862306a36Sopenharmony_ci glort = dglort->glort; 51962306a36Sopenharmony_ci q_idx = dglort->queue_b; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* configure SGLORT for queues */ 52262306a36Sopenharmony_ci for (vsi = 0; vsi < vsi_count; vsi++, glort++) { 52362306a36Sopenharmony_ci for (queue = 0; queue < queue_count; queue++, q_idx++) { 52462306a36Sopenharmony_ci if (q_idx >= FM10K_MAX_QUEUES) 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TX_SGLORT(q_idx), glort); 52862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RX_SGLORT(q_idx), glort); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* determine count of PCs and queues */ 53362306a36Sopenharmony_ci queue_count = BIT(dglort->queue_l + dglort->rss_l + dglort->vsi_l); 53462306a36Sopenharmony_ci pc_count = BIT(dglort->pc_l); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* configure PC for Tx queues */ 53762306a36Sopenharmony_ci for (pc = 0; pc < pc_count; pc++) { 53862306a36Sopenharmony_ci q_idx = pc + dglort->queue_b; 53962306a36Sopenharmony_ci for (queue = 0; queue < queue_count; queue++) { 54062306a36Sopenharmony_ci if (q_idx >= FM10K_MAX_QUEUES) 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci txqctl = fm10k_read_reg(hw, FM10K_TXQCTL(q_idx)); 54462306a36Sopenharmony_ci txqctl &= ~FM10K_TXQCTL_PC_MASK; 54562306a36Sopenharmony_ci txqctl |= pc << FM10K_TXQCTL_PC_SHIFT; 54662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXQCTL(q_idx), txqctl); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci q_idx += pc_count; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* configure DGLORTDEC */ 55362306a36Sopenharmony_ci dglortdec = ((u32)(dglort->rss_l) << FM10K_DGLORTDEC_RSSLENGTH_SHIFT) | 55462306a36Sopenharmony_ci ((u32)(dglort->queue_b) << FM10K_DGLORTDEC_QBASE_SHIFT) | 55562306a36Sopenharmony_ci ((u32)(dglort->pc_l) << FM10K_DGLORTDEC_PCLENGTH_SHIFT) | 55662306a36Sopenharmony_ci ((u32)(dglort->vsi_b) << FM10K_DGLORTDEC_VSIBASE_SHIFT) | 55762306a36Sopenharmony_ci ((u32)(dglort->vsi_l) << FM10K_DGLORTDEC_VSILENGTH_SHIFT) | 55862306a36Sopenharmony_ci ((u32)(dglort->queue_l)); 55962306a36Sopenharmony_ci if (dglort->inner_rss) 56062306a36Sopenharmony_ci dglortdec |= FM10K_DGLORTDEC_INNERRSS_ENABLE; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* configure DGLORTMAP */ 56362306a36Sopenharmony_ci dglortmap = (dglort->idx == fm10k_dglort_default) ? 56462306a36Sopenharmony_ci FM10K_DGLORTMAP_ANY : FM10K_DGLORTMAP_ZERO; 56562306a36Sopenharmony_ci dglortmap <<= dglort->vsi_l + dglort->queue_l + dglort->shared_l; 56662306a36Sopenharmony_ci dglortmap |= dglort->glort; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* write values to hardware */ 56962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DGLORTDEC(dglort->idx), dglortdec); 57062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_DGLORTMAP(dglort->idx), dglortmap); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return 0; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ciu16 fm10k_queues_per_pool(struct fm10k_hw *hw) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci u16 num_pools = hw->iov.num_pools; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return (num_pools > 32) ? 2 : (num_pools > 16) ? 4 : (num_pools > 8) ? 58062306a36Sopenharmony_ci 8 : FM10K_MAX_QUEUES_POOL; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ciu16 fm10k_vf_queue_index(struct fm10k_hw *hw, u16 vf_idx) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci u16 num_vfs = hw->iov.num_vfs; 58662306a36Sopenharmony_ci u16 vf_q_idx = FM10K_MAX_QUEUES; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci vf_q_idx -= fm10k_queues_per_pool(hw) * (num_vfs - vf_idx); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return vf_q_idx; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic u16 fm10k_vectors_per_pool(struct fm10k_hw *hw) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci u16 num_pools = hw->iov.num_pools; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return (num_pools > 32) ? 8 : (num_pools > 16) ? 16 : 59862306a36Sopenharmony_ci FM10K_MAX_VECTORS_POOL; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic u16 fm10k_vf_vector_index(struct fm10k_hw *hw, u16 vf_idx) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci u16 vf_v_idx = FM10K_MAX_VECTORS_PF; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci vf_v_idx += fm10k_vectors_per_pool(hw) * vf_idx; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return vf_v_idx; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci/** 61162306a36Sopenharmony_ci * fm10k_iov_assign_resources_pf - Assign pool resources for virtualization 61262306a36Sopenharmony_ci * @hw: pointer to the HW structure 61362306a36Sopenharmony_ci * @num_vfs: number of VFs to be allocated 61462306a36Sopenharmony_ci * @num_pools: number of virtualization pools to be allocated 61562306a36Sopenharmony_ci * 61662306a36Sopenharmony_ci * Allocates queues and traffic classes to virtualization entities to prepare 61762306a36Sopenharmony_ci * the PF for SR-IOV and VMDq 61862306a36Sopenharmony_ci **/ 61962306a36Sopenharmony_cistatic s32 fm10k_iov_assign_resources_pf(struct fm10k_hw *hw, u16 num_vfs, 62062306a36Sopenharmony_ci u16 num_pools) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci u16 qmap_stride, qpp, vpp, vf_q_idx, vf_q_idx0, qmap_idx; 62362306a36Sopenharmony_ci u32 vid = hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT; 62462306a36Sopenharmony_ci int i, j; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* hardware only supports up to 64 pools */ 62762306a36Sopenharmony_ci if (num_pools > 64) 62862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* the number of VFs cannot exceed the number of pools */ 63162306a36Sopenharmony_ci if ((num_vfs > num_pools) || (num_vfs > hw->iov.total_vfs)) 63262306a36Sopenharmony_ci return FM10K_ERR_PARAM; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* record number of virtualization entities */ 63562306a36Sopenharmony_ci hw->iov.num_vfs = num_vfs; 63662306a36Sopenharmony_ci hw->iov.num_pools = num_pools; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* determine qmap offsets and counts */ 63962306a36Sopenharmony_ci qmap_stride = (num_vfs > 8) ? 32 : 256; 64062306a36Sopenharmony_ci qpp = fm10k_queues_per_pool(hw); 64162306a36Sopenharmony_ci vpp = fm10k_vectors_per_pool(hw); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* calculate starting index for queues */ 64462306a36Sopenharmony_ci vf_q_idx = fm10k_vf_queue_index(hw, 0); 64562306a36Sopenharmony_ci qmap_idx = 0; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* establish TCs with -1 credits and no quanta to prevent transmit */ 64862306a36Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 64962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_MAXCREDIT(i), 0); 65062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_RATE(i), 0); 65162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_CREDIT(i), 65262306a36Sopenharmony_ci FM10K_TC_CREDIT_CREDIT_MASK); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* zero out all mbmem registers */ 65662306a36Sopenharmony_ci for (i = FM10K_VFMBMEM_LEN * num_vfs; i--;) 65762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_MBMEM(i), 0); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* clear event notification of VF FLR */ 66062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_PFVFLREC(0), ~0); 66162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_PFVFLREC(1), ~0); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* loop through unallocated rings assigning them back to PF */ 66462306a36Sopenharmony_ci for (i = FM10K_MAX_QUEUES_PF; i < vf_q_idx; i++) { 66562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXDCTL(i), 0); 66662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXQCTL(i), FM10K_TXQCTL_PF | 66762306a36Sopenharmony_ci FM10K_TXQCTL_UNLIMITED_BW | vid); 66862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RXQCTL(i), FM10K_RXQCTL_PF); 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* PF should have already updated VFITR2[0] */ 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* update all ITR registers to flow to VFITR2[0] */ 67462306a36Sopenharmony_ci for (i = FM10K_ITR_REG_COUNT_PF + 1; i < FM10K_ITR_REG_COUNT; i++) { 67562306a36Sopenharmony_ci if (!(i & (vpp - 1))) 67662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(i), i - vpp); 67762306a36Sopenharmony_ci else 67862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(i), i - 1); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* update PF ITR2[0] to reference the last vector */ 68262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(0), 68362306a36Sopenharmony_ci fm10k_vf_vector_index(hw, num_vfs - 1)); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* loop through rings populating rings and TCs */ 68662306a36Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 68762306a36Sopenharmony_ci /* record index for VF queue 0 for use in end of loop */ 68862306a36Sopenharmony_ci vf_q_idx0 = vf_q_idx; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci for (j = 0; j < qpp; j++, qmap_idx++, vf_q_idx++) { 69162306a36Sopenharmony_ci /* assign VF and locked TC to queues */ 69262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXDCTL(vf_q_idx), 0); 69362306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXQCTL(vf_q_idx), 69462306a36Sopenharmony_ci (i << FM10K_TXQCTL_TC_SHIFT) | i | 69562306a36Sopenharmony_ci FM10K_TXQCTL_VF | vid); 69662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RXDCTL(vf_q_idx), 69762306a36Sopenharmony_ci FM10K_RXDCTL_WRITE_BACK_MIN_DELAY | 69862306a36Sopenharmony_ci FM10K_RXDCTL_DROP_ON_EMPTY); 69962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RXQCTL(vf_q_idx), 70062306a36Sopenharmony_ci (i << FM10K_RXQCTL_VF_SHIFT) | 70162306a36Sopenharmony_ci FM10K_RXQCTL_VF); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* map queue pair to VF */ 70462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx), vf_q_idx); 70562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx), vf_q_idx); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* repeat the first ring for all of the remaining VF rings */ 70962306a36Sopenharmony_ci for (; j < qmap_stride; j++, qmap_idx++) { 71062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx), vf_q_idx0); 71162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx), vf_q_idx0); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* loop through remaining indexes assigning all to queue 0 */ 71662306a36Sopenharmony_ci while (qmap_idx < FM10K_TQMAP_TABLE_SIZE) { 71762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx), 0); 71862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx), 0); 71962306a36Sopenharmony_ci qmap_idx++; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci/** 72662306a36Sopenharmony_ci * fm10k_iov_configure_tc_pf - Configure the shaping group for VF 72762306a36Sopenharmony_ci * @hw: pointer to the HW structure 72862306a36Sopenharmony_ci * @vf_idx: index of VF receiving GLORT 72962306a36Sopenharmony_ci * @rate: Rate indicated in Mb/s 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * Configured the TC for a given VF to allow only up to a given number 73262306a36Sopenharmony_ci * of Mb/s of outgoing Tx throughput. 73362306a36Sopenharmony_ci **/ 73462306a36Sopenharmony_cistatic s32 fm10k_iov_configure_tc_pf(struct fm10k_hw *hw, u16 vf_idx, int rate) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci /* configure defaults */ 73762306a36Sopenharmony_ci u32 interval = FM10K_TC_RATE_INTERVAL_4US_GEN3; 73862306a36Sopenharmony_ci u32 tc_rate = FM10K_TC_RATE_QUANTA_MASK; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* verify vf is in range */ 74162306a36Sopenharmony_ci if (vf_idx >= hw->iov.num_vfs) 74262306a36Sopenharmony_ci return FM10K_ERR_PARAM; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* set interval to align with 4.096 usec in all modes */ 74562306a36Sopenharmony_ci switch (hw->bus.speed) { 74662306a36Sopenharmony_ci case fm10k_bus_speed_2500: 74762306a36Sopenharmony_ci interval = FM10K_TC_RATE_INTERVAL_4US_GEN1; 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci case fm10k_bus_speed_5000: 75062306a36Sopenharmony_ci interval = FM10K_TC_RATE_INTERVAL_4US_GEN2; 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci default: 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (rate) { 75762306a36Sopenharmony_ci if (rate > FM10K_VF_TC_MAX || rate < FM10K_VF_TC_MIN) 75862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* The quanta is measured in Bytes per 4.096 or 8.192 usec 76162306a36Sopenharmony_ci * The rate is provided in Mbits per second 76262306a36Sopenharmony_ci * To tralslate from rate to quanta we need to multiply the 76362306a36Sopenharmony_ci * rate by 8.192 usec and divide by 8 bits/byte. To avoid 76462306a36Sopenharmony_ci * dealing with floating point we can round the values up 76562306a36Sopenharmony_ci * to the nearest whole number ratio which gives us 128 / 125. 76662306a36Sopenharmony_ci */ 76762306a36Sopenharmony_ci tc_rate = (rate * 128) / 125; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* try to keep the rate limiting accurate by increasing 77062306a36Sopenharmony_ci * the number of credits and interval for rates less than 4Gb/s 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci if (rate < 4000) 77362306a36Sopenharmony_ci interval <<= 1; 77462306a36Sopenharmony_ci else 77562306a36Sopenharmony_ci tc_rate >>= 1; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* update rate limiter with new values */ 77962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_RATE(vf_idx), tc_rate | interval); 78062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_MAXCREDIT(vf_idx), FM10K_TC_MAXCREDIT_64K); 78162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_CREDIT(vf_idx), FM10K_TC_MAXCREDIT_64K); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/** 78762306a36Sopenharmony_ci * fm10k_iov_assign_int_moderator_pf - Add VF interrupts to moderator list 78862306a36Sopenharmony_ci * @hw: pointer to the HW structure 78962306a36Sopenharmony_ci * @vf_idx: index of VF receiving GLORT 79062306a36Sopenharmony_ci * 79162306a36Sopenharmony_ci * Update the interrupt moderator linked list to include any MSI-X 79262306a36Sopenharmony_ci * interrupts which the VF has enabled in the MSI-X vector table. 79362306a36Sopenharmony_ci **/ 79462306a36Sopenharmony_cistatic s32 fm10k_iov_assign_int_moderator_pf(struct fm10k_hw *hw, u16 vf_idx) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci u16 vf_v_idx, vf_v_limit, i; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* verify vf is in range */ 79962306a36Sopenharmony_ci if (vf_idx >= hw->iov.num_vfs) 80062306a36Sopenharmony_ci return FM10K_ERR_PARAM; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* determine vector offset and count */ 80362306a36Sopenharmony_ci vf_v_idx = fm10k_vf_vector_index(hw, vf_idx); 80462306a36Sopenharmony_ci vf_v_limit = vf_v_idx + fm10k_vectors_per_pool(hw); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* search for first vector that is not masked */ 80762306a36Sopenharmony_ci for (i = vf_v_limit - 1; i > vf_v_idx; i--) { 80862306a36Sopenharmony_ci if (!fm10k_read_reg(hw, FM10K_MSIX_VECTOR_MASK(i))) 80962306a36Sopenharmony_ci break; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* reset linked list so it now includes our active vectors */ 81362306a36Sopenharmony_ci if (vf_idx == (hw->iov.num_vfs - 1)) 81462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(0), i); 81562306a36Sopenharmony_ci else 81662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(vf_v_limit), i); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci return 0; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci/** 82262306a36Sopenharmony_ci * fm10k_iov_assign_default_mac_vlan_pf - Assign a MAC and VLAN to VF 82362306a36Sopenharmony_ci * @hw: pointer to the HW structure 82462306a36Sopenharmony_ci * @vf_info: pointer to VF information structure 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * Assign a MAC address and default VLAN to a VF and notify it of the update 82762306a36Sopenharmony_ci **/ 82862306a36Sopenharmony_cistatic s32 fm10k_iov_assign_default_mac_vlan_pf(struct fm10k_hw *hw, 82962306a36Sopenharmony_ci struct fm10k_vf_info *vf_info) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci u16 qmap_stride, queues_per_pool, vf_q_idx, timeout, qmap_idx, i; 83262306a36Sopenharmony_ci u32 msg[4], txdctl, txqctl, tdbal = 0, tdbah = 0; 83362306a36Sopenharmony_ci s32 err = 0; 83462306a36Sopenharmony_ci u16 vf_idx, vf_vid; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* verify vf is in range */ 83762306a36Sopenharmony_ci if (!vf_info || vf_info->vf_idx >= hw->iov.num_vfs) 83862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* determine qmap offsets and counts */ 84162306a36Sopenharmony_ci qmap_stride = (hw->iov.num_vfs > 8) ? 32 : 256; 84262306a36Sopenharmony_ci queues_per_pool = fm10k_queues_per_pool(hw); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* calculate starting index for queues */ 84562306a36Sopenharmony_ci vf_idx = vf_info->vf_idx; 84662306a36Sopenharmony_ci vf_q_idx = fm10k_vf_queue_index(hw, vf_idx); 84762306a36Sopenharmony_ci qmap_idx = qmap_stride * vf_idx; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* Determine correct default VLAN ID. The FM10K_VLAN_OVERRIDE bit is 85062306a36Sopenharmony_ci * used here to indicate to the VF that it will not have privilege to 85162306a36Sopenharmony_ci * write VLAN_TABLE. All policy is enforced on the PF but this allows 85262306a36Sopenharmony_ci * the VF to correctly report errors to userspace requests. 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_ci if (vf_info->pf_vid) 85562306a36Sopenharmony_ci vf_vid = vf_info->pf_vid | FM10K_VLAN_OVERRIDE; 85662306a36Sopenharmony_ci else 85762306a36Sopenharmony_ci vf_vid = vf_info->sw_vid; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* generate MAC_ADDR request */ 86062306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); 86162306a36Sopenharmony_ci fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_DEFAULT_MAC, 86262306a36Sopenharmony_ci vf_info->mac, vf_vid); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Configure Queue control register with new VLAN ID. The TXQCTL 86562306a36Sopenharmony_ci * register is RO from the VF, so the PF must do this even in the 86662306a36Sopenharmony_ci * case of notifying the VF of a new VID via the mailbox. 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ci txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) & 86962306a36Sopenharmony_ci FM10K_TXQCTL_VID_MASK; 87062306a36Sopenharmony_ci txqctl |= (vf_idx << FM10K_TXQCTL_TC_SHIFT) | 87162306a36Sopenharmony_ci FM10K_TXQCTL_VF | vf_idx; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci for (i = 0; i < queues_per_pool; i++) 87462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXQCTL(vf_q_idx + i), txqctl); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* try loading a message onto outgoing mailbox first */ 87762306a36Sopenharmony_ci if (vf_info->mbx.ops.enqueue_tx) { 87862306a36Sopenharmony_ci err = vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); 87962306a36Sopenharmony_ci if (err != FM10K_MBX_ERR_NO_MBX) 88062306a36Sopenharmony_ci return err; 88162306a36Sopenharmony_ci err = 0; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* If we aren't connected to a mailbox, this is most likely because 88562306a36Sopenharmony_ci * the VF driver is not running. It should thus be safe to re-map 88662306a36Sopenharmony_ci * queues and use the registers to pass the MAC address so that the VF 88762306a36Sopenharmony_ci * driver gets correct information during its initialization. 88862306a36Sopenharmony_ci */ 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* MAP Tx queue back to 0 temporarily, and disable it */ 89162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx), 0); 89262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXDCTL(vf_q_idx), 0); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci /* verify ring has disabled before modifying base address registers */ 89562306a36Sopenharmony_ci txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(vf_q_idx)); 89662306a36Sopenharmony_ci for (timeout = 0; txdctl & FM10K_TXDCTL_ENABLE; timeout++) { 89762306a36Sopenharmony_ci /* limit ourselves to a 1ms timeout */ 89862306a36Sopenharmony_ci if (timeout == 10) { 89962306a36Sopenharmony_ci err = FM10K_ERR_DMA_PENDING; 90062306a36Sopenharmony_ci goto err_out; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci usleep_range(100, 200); 90462306a36Sopenharmony_ci txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(vf_q_idx)); 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* Update base address registers to contain MAC address */ 90862306a36Sopenharmony_ci if (is_valid_ether_addr(vf_info->mac)) { 90962306a36Sopenharmony_ci tdbal = (((u32)vf_info->mac[3]) << 24) | 91062306a36Sopenharmony_ci (((u32)vf_info->mac[4]) << 16) | 91162306a36Sopenharmony_ci (((u32)vf_info->mac[5]) << 8); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci tdbah = (((u32)0xFF) << 24) | 91462306a36Sopenharmony_ci (((u32)vf_info->mac[0]) << 16) | 91562306a36Sopenharmony_ci (((u32)vf_info->mac[1]) << 8) | 91662306a36Sopenharmony_ci ((u32)vf_info->mac[2]); 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci /* Record the base address into queue 0 */ 92062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TDBAL(vf_q_idx), tdbal); 92162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TDBAH(vf_q_idx), tdbah); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* Provide the VF the ITR scale, using software-defined fields in TDLEN 92462306a36Sopenharmony_ci * to pass the information during VF initialization. See definition of 92562306a36Sopenharmony_ci * FM10K_TDLEN_ITR_SCALE_SHIFT for more details. 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TDLEN(vf_q_idx), hw->mac.itr_scale << 92862306a36Sopenharmony_ci FM10K_TDLEN_ITR_SCALE_SHIFT); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cierr_out: 93162306a36Sopenharmony_ci /* restore the queue back to VF ownership */ 93262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx), vf_q_idx); 93362306a36Sopenharmony_ci return err; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci/** 93762306a36Sopenharmony_ci * fm10k_iov_reset_resources_pf - Reassign queues and interrupts to a VF 93862306a36Sopenharmony_ci * @hw: pointer to the HW structure 93962306a36Sopenharmony_ci * @vf_info: pointer to VF information structure 94062306a36Sopenharmony_ci * 94162306a36Sopenharmony_ci * Reassign the interrupts and queues to a VF following an FLR 94262306a36Sopenharmony_ci **/ 94362306a36Sopenharmony_cistatic s32 fm10k_iov_reset_resources_pf(struct fm10k_hw *hw, 94462306a36Sopenharmony_ci struct fm10k_vf_info *vf_info) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci u16 qmap_stride, queues_per_pool, vf_q_idx, qmap_idx; 94762306a36Sopenharmony_ci u32 tdbal = 0, tdbah = 0, txqctl, rxqctl; 94862306a36Sopenharmony_ci u16 vf_v_idx, vf_v_limit, vf_vid; 94962306a36Sopenharmony_ci u8 vf_idx = vf_info->vf_idx; 95062306a36Sopenharmony_ci int i; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* verify vf is in range */ 95362306a36Sopenharmony_ci if (vf_idx >= hw->iov.num_vfs) 95462306a36Sopenharmony_ci return FM10K_ERR_PARAM; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* clear event notification of VF FLR */ 95762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_PFVFLREC(vf_idx / 32), BIT(vf_idx % 32)); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* force timeout and then disconnect the mailbox */ 96062306a36Sopenharmony_ci vf_info->mbx.timeout = 0; 96162306a36Sopenharmony_ci if (vf_info->mbx.ops.disconnect) 96262306a36Sopenharmony_ci vf_info->mbx.ops.disconnect(hw, &vf_info->mbx); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* determine vector offset and count */ 96562306a36Sopenharmony_ci vf_v_idx = fm10k_vf_vector_index(hw, vf_idx); 96662306a36Sopenharmony_ci vf_v_limit = vf_v_idx + fm10k_vectors_per_pool(hw); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* determine qmap offsets and counts */ 96962306a36Sopenharmony_ci qmap_stride = (hw->iov.num_vfs > 8) ? 32 : 256; 97062306a36Sopenharmony_ci queues_per_pool = fm10k_queues_per_pool(hw); 97162306a36Sopenharmony_ci qmap_idx = qmap_stride * vf_idx; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* make all the queues inaccessible to the VF */ 97462306a36Sopenharmony_ci for (i = qmap_idx; i < (qmap_idx + qmap_stride); i++) { 97562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(i), 0); 97662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RQMAP(i), 0); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* calculate starting index for queues */ 98062306a36Sopenharmony_ci vf_q_idx = fm10k_vf_queue_index(hw, vf_idx); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* determine correct default VLAN ID */ 98362306a36Sopenharmony_ci if (vf_info->pf_vid) 98462306a36Sopenharmony_ci vf_vid = vf_info->pf_vid; 98562306a36Sopenharmony_ci else 98662306a36Sopenharmony_ci vf_vid = vf_info->sw_vid; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* configure Queue control register */ 98962306a36Sopenharmony_ci txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) | 99062306a36Sopenharmony_ci (vf_idx << FM10K_TXQCTL_TC_SHIFT) | 99162306a36Sopenharmony_ci FM10K_TXQCTL_VF | vf_idx; 99262306a36Sopenharmony_ci rxqctl = (vf_idx << FM10K_RXQCTL_VF_SHIFT) | FM10K_RXQCTL_VF; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* stop further DMA and reset queue ownership back to VF */ 99562306a36Sopenharmony_ci for (i = vf_q_idx; i < (queues_per_pool + vf_q_idx); i++) { 99662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXDCTL(i), 0); 99762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXQCTL(i), txqctl); 99862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RXDCTL(i), 99962306a36Sopenharmony_ci FM10K_RXDCTL_WRITE_BACK_MIN_DELAY | 100062306a36Sopenharmony_ci FM10K_RXDCTL_DROP_ON_EMPTY); 100162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RXQCTL(i), rxqctl); 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* reset TC with -1 credits and no quanta to prevent transmit */ 100562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_MAXCREDIT(vf_idx), 0); 100662306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_RATE(vf_idx), 0); 100762306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TC_CREDIT(vf_idx), 100862306a36Sopenharmony_ci FM10K_TC_CREDIT_CREDIT_MASK); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci /* update our first entry in the table based on previous VF */ 101162306a36Sopenharmony_ci if (!vf_idx) 101262306a36Sopenharmony_ci hw->mac.ops.update_int_moderator(hw); 101362306a36Sopenharmony_ci else 101462306a36Sopenharmony_ci hw->iov.ops.assign_int_moderator(hw, vf_idx - 1); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* reset linked list so it now includes our active vectors */ 101762306a36Sopenharmony_ci if (vf_idx == (hw->iov.num_vfs - 1)) 101862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(0), vf_v_idx); 101962306a36Sopenharmony_ci else 102062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(vf_v_limit), vf_v_idx); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* link remaining vectors so that next points to previous */ 102362306a36Sopenharmony_ci for (vf_v_idx++; vf_v_idx < vf_v_limit; vf_v_idx++) 102462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_ITR2(vf_v_idx), vf_v_idx - 1); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* zero out MBMEM, VLAN_TABLE, RETA, RSSRK, and MRQC registers */ 102762306a36Sopenharmony_ci for (i = FM10K_VFMBMEM_LEN; i--;) 102862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_MBMEM_VF(vf_idx, i), 0); 102962306a36Sopenharmony_ci for (i = FM10K_VLAN_TABLE_SIZE; i--;) 103062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_VLAN_TABLE(vf_info->vsi, i), 0); 103162306a36Sopenharmony_ci for (i = FM10K_RETA_SIZE; i--;) 103262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RETA(vf_info->vsi, i), 0); 103362306a36Sopenharmony_ci for (i = FM10K_RSSRK_SIZE; i--;) 103462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RSSRK(vf_info->vsi, i), 0); 103562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_MRQC(vf_info->vsi), 0); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* Update base address registers to contain MAC address */ 103862306a36Sopenharmony_ci if (is_valid_ether_addr(vf_info->mac)) { 103962306a36Sopenharmony_ci tdbal = (((u32)vf_info->mac[3]) << 24) | 104062306a36Sopenharmony_ci (((u32)vf_info->mac[4]) << 16) | 104162306a36Sopenharmony_ci (((u32)vf_info->mac[5]) << 8); 104262306a36Sopenharmony_ci tdbah = (((u32)0xFF) << 24) | 104362306a36Sopenharmony_ci (((u32)vf_info->mac[0]) << 16) | 104462306a36Sopenharmony_ci (((u32)vf_info->mac[1]) << 8) | 104562306a36Sopenharmony_ci ((u32)vf_info->mac[2]); 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci /* map queue pairs back to VF from last to first */ 104962306a36Sopenharmony_ci for (i = queues_per_pool; i--;) { 105062306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TDBAL(vf_q_idx + i), tdbal); 105162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TDBAH(vf_q_idx + i), tdbah); 105262306a36Sopenharmony_ci /* See definition of FM10K_TDLEN_ITR_SCALE_SHIFT for an 105362306a36Sopenharmony_ci * explanation of how TDLEN is used. 105462306a36Sopenharmony_ci */ 105562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TDLEN(vf_q_idx + i), 105662306a36Sopenharmony_ci hw->mac.itr_scale << 105762306a36Sopenharmony_ci FM10K_TDLEN_ITR_SCALE_SHIFT); 105862306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx + i), vf_q_idx + i); 105962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* repeat the first ring for all the remaining VF rings */ 106362306a36Sopenharmony_ci for (i = queues_per_pool; i < qmap_stride; i++) { 106462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TQMAP(qmap_idx + i), vf_q_idx); 106562306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci return 0; 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci/** 107262306a36Sopenharmony_ci * fm10k_iov_set_lport_pf - Assign and enable a logical port for a given VF 107362306a36Sopenharmony_ci * @hw: pointer to hardware structure 107462306a36Sopenharmony_ci * @vf_info: pointer to VF information structure 107562306a36Sopenharmony_ci * @lport_idx: Logical port offset from the hardware glort 107662306a36Sopenharmony_ci * @flags: Set of capability flags to extend port beyond basic functionality 107762306a36Sopenharmony_ci * 107862306a36Sopenharmony_ci * This function allows enabling a VF port by assigning it a GLORT and 107962306a36Sopenharmony_ci * setting the flags so that it can enable an Rx mode. 108062306a36Sopenharmony_ci **/ 108162306a36Sopenharmony_cistatic s32 fm10k_iov_set_lport_pf(struct fm10k_hw *hw, 108262306a36Sopenharmony_ci struct fm10k_vf_info *vf_info, 108362306a36Sopenharmony_ci u16 lport_idx, u8 flags) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci u16 glort = (hw->mac.dglort_map + lport_idx) & FM10K_DGLORTMAP_NONE; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci /* if glort is not valid return error */ 108862306a36Sopenharmony_ci if (!fm10k_glort_valid_pf(hw, glort)) 108962306a36Sopenharmony_ci return FM10K_ERR_PARAM; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci vf_info->vf_flags = flags | FM10K_VF_FLAG_NONE_CAPABLE; 109262306a36Sopenharmony_ci vf_info->glort = glort; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci return 0; 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci/** 109862306a36Sopenharmony_ci * fm10k_iov_reset_lport_pf - Disable a logical port for a given VF 109962306a36Sopenharmony_ci * @hw: pointer to hardware structure 110062306a36Sopenharmony_ci * @vf_info: pointer to VF information structure 110162306a36Sopenharmony_ci * 110262306a36Sopenharmony_ci * This function disables a VF port by stripping it of a GLORT and 110362306a36Sopenharmony_ci * setting the flags so that it cannot enable any Rx mode. 110462306a36Sopenharmony_ci **/ 110562306a36Sopenharmony_cistatic void fm10k_iov_reset_lport_pf(struct fm10k_hw *hw, 110662306a36Sopenharmony_ci struct fm10k_vf_info *vf_info) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci u32 msg[1]; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* need to disable the port if it is already enabled */ 111162306a36Sopenharmony_ci if (FM10K_VF_FLAG_ENABLED(vf_info)) { 111262306a36Sopenharmony_ci /* notify switch that this port has been disabled */ 111362306a36Sopenharmony_ci fm10k_update_lport_state_pf(hw, vf_info->glort, 1, false); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* generate port state response to notify VF it is not ready */ 111662306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); 111762306a36Sopenharmony_ci vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* clear flags and glort if it exists */ 112162306a36Sopenharmony_ci vf_info->vf_flags = 0; 112262306a36Sopenharmony_ci vf_info->glort = 0; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci/** 112662306a36Sopenharmony_ci * fm10k_iov_update_stats_pf - Updates hardware related statistics for VFs 112762306a36Sopenharmony_ci * @hw: pointer to hardware structure 112862306a36Sopenharmony_ci * @q: stats for all queues of a VF 112962306a36Sopenharmony_ci * @vf_idx: index of VF 113062306a36Sopenharmony_ci * 113162306a36Sopenharmony_ci * This function collects queue stats for VFs. 113262306a36Sopenharmony_ci **/ 113362306a36Sopenharmony_cistatic void fm10k_iov_update_stats_pf(struct fm10k_hw *hw, 113462306a36Sopenharmony_ci struct fm10k_hw_stats_q *q, 113562306a36Sopenharmony_ci u16 vf_idx) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci u32 idx, qpp; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* get stats for all of the queues */ 114062306a36Sopenharmony_ci qpp = fm10k_queues_per_pool(hw); 114162306a36Sopenharmony_ci idx = fm10k_vf_queue_index(hw, vf_idx); 114262306a36Sopenharmony_ci fm10k_update_hw_stats_q(hw, q, idx, qpp); 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci/** 114662306a36Sopenharmony_ci * fm10k_iov_msg_msix_pf - Message handler for MSI-X request from VF 114762306a36Sopenharmony_ci * @hw: Pointer to hardware structure 114862306a36Sopenharmony_ci * @results: Pointer array to message, results[0] is pointer to message 114962306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 115062306a36Sopenharmony_ci * 115162306a36Sopenharmony_ci * This function is a default handler for MSI-X requests from the VF. The 115262306a36Sopenharmony_ci * assumption is that in this case it is acceptable to just directly 115362306a36Sopenharmony_ci * hand off the message from the VF to the underlying shared code. 115462306a36Sopenharmony_ci **/ 115562306a36Sopenharmony_cis32 fm10k_iov_msg_msix_pf(struct fm10k_hw *hw, u32 __always_unused **results, 115662306a36Sopenharmony_ci struct fm10k_mbx_info *mbx) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; 115962306a36Sopenharmony_ci u8 vf_idx = vf_info->vf_idx; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return hw->iov.ops.assign_int_moderator(hw, vf_idx); 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci/** 116562306a36Sopenharmony_ci * fm10k_iov_select_vid - Select correct default VLAN ID 116662306a36Sopenharmony_ci * @vf_info: pointer to VF information structure 116762306a36Sopenharmony_ci * @vid: VLAN ID to correct 116862306a36Sopenharmony_ci * 116962306a36Sopenharmony_ci * Will report an error if the VLAN ID is out of range. For VID = 0, it will 117062306a36Sopenharmony_ci * return either the pf_vid or sw_vid depending on which one is set. 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_cis32 fm10k_iov_select_vid(struct fm10k_vf_info *vf_info, u16 vid) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci if (!vid) 117562306a36Sopenharmony_ci return vf_info->pf_vid ? vf_info->pf_vid : vf_info->sw_vid; 117662306a36Sopenharmony_ci else if (vf_info->pf_vid && vid != vf_info->pf_vid) 117762306a36Sopenharmony_ci return FM10K_ERR_PARAM; 117862306a36Sopenharmony_ci else 117962306a36Sopenharmony_ci return vid; 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci/** 118362306a36Sopenharmony_ci * fm10k_iov_msg_mac_vlan_pf - Message handler for MAC/VLAN request from VF 118462306a36Sopenharmony_ci * @hw: Pointer to hardware structure 118562306a36Sopenharmony_ci * @results: Pointer array to message, results[0] is pointer to message 118662306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 118762306a36Sopenharmony_ci * 118862306a36Sopenharmony_ci * This function is a default handler for MAC/VLAN requests from the VF. 118962306a36Sopenharmony_ci * The assumption is that in this case it is acceptable to just directly 119062306a36Sopenharmony_ci * hand off the message from the VF to the underlying shared code. 119162306a36Sopenharmony_ci **/ 119262306a36Sopenharmony_cis32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, 119362306a36Sopenharmony_ci struct fm10k_mbx_info *mbx) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; 119662306a36Sopenharmony_ci u8 mac[ETH_ALEN]; 119762306a36Sopenharmony_ci u32 *result; 119862306a36Sopenharmony_ci int err = 0; 119962306a36Sopenharmony_ci bool set; 120062306a36Sopenharmony_ci u16 vlan; 120162306a36Sopenharmony_ci u32 vid; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* we shouldn't be updating rules on a disabled interface */ 120462306a36Sopenharmony_ci if (!FM10K_VF_FLAG_ENABLED(vf_info)) 120562306a36Sopenharmony_ci err = FM10K_ERR_PARAM; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (!err && !!results[FM10K_MAC_VLAN_MSG_VLAN]) { 120862306a36Sopenharmony_ci result = results[FM10K_MAC_VLAN_MSG_VLAN]; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* record VLAN id requested */ 121162306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u32(result, &vid); 121262306a36Sopenharmony_ci if (err) 121362306a36Sopenharmony_ci return err; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci set = !(vid & FM10K_VLAN_CLEAR); 121662306a36Sopenharmony_ci vid &= ~FM10K_VLAN_CLEAR; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci /* if the length field has been set, this is a multi-bit 121962306a36Sopenharmony_ci * update request. For multi-bit requests, simply disallow 122062306a36Sopenharmony_ci * them when the pf_vid has been set. In this case, the PF 122162306a36Sopenharmony_ci * should have already cleared the VLAN_TABLE, and if we 122262306a36Sopenharmony_ci * allowed them, it could allow a rogue VF to receive traffic 122362306a36Sopenharmony_ci * on a VLAN it was not assigned. In the single-bit case, we 122462306a36Sopenharmony_ci * need to modify requests for VLAN 0 to use the default PF or 122562306a36Sopenharmony_ci * SW vid when assigned. 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (vid >> 16) { 122962306a36Sopenharmony_ci /* prevent multi-bit requests when PF has 123062306a36Sopenharmony_ci * administratively set the VLAN for this VF 123162306a36Sopenharmony_ci */ 123262306a36Sopenharmony_ci if (vf_info->pf_vid) 123362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 123462306a36Sopenharmony_ci } else { 123562306a36Sopenharmony_ci err = fm10k_iov_select_vid(vf_info, (u16)vid); 123662306a36Sopenharmony_ci if (err < 0) 123762306a36Sopenharmony_ci return err; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci vid = err; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* update VSI info for VF in regards to VLAN table */ 124362306a36Sopenharmony_ci err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, set); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) { 124762306a36Sopenharmony_ci result = results[FM10K_MAC_VLAN_MSG_MAC]; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci /* record unicast MAC address requested */ 125062306a36Sopenharmony_ci err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); 125162306a36Sopenharmony_ci if (err) 125262306a36Sopenharmony_ci return err; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci /* block attempts to set MAC for a locked device */ 125562306a36Sopenharmony_ci if (is_valid_ether_addr(vf_info->mac) && 125662306a36Sopenharmony_ci !ether_addr_equal(mac, vf_info->mac)) 125762306a36Sopenharmony_ci return FM10K_ERR_PARAM; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci set = !(vlan & FM10K_VLAN_CLEAR); 126062306a36Sopenharmony_ci vlan &= ~FM10K_VLAN_CLEAR; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci err = fm10k_iov_select_vid(vf_info, vlan); 126362306a36Sopenharmony_ci if (err < 0) 126462306a36Sopenharmony_ci return err; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci vlan = (u16)err; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci /* notify switch of request for new unicast address */ 126962306a36Sopenharmony_ci err = hw->mac.ops.update_uc_addr(hw, vf_info->glort, 127062306a36Sopenharmony_ci mac, vlan, set, 0); 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) { 127462306a36Sopenharmony_ci result = results[FM10K_MAC_VLAN_MSG_MULTICAST]; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* record multicast MAC address requested */ 127762306a36Sopenharmony_ci err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); 127862306a36Sopenharmony_ci if (err) 127962306a36Sopenharmony_ci return err; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* verify that the VF is allowed to request multicast */ 128262306a36Sopenharmony_ci if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED)) 128362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci set = !(vlan & FM10K_VLAN_CLEAR); 128662306a36Sopenharmony_ci vlan &= ~FM10K_VLAN_CLEAR; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci err = fm10k_iov_select_vid(vf_info, vlan); 128962306a36Sopenharmony_ci if (err < 0) 129062306a36Sopenharmony_ci return err; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci vlan = (u16)err; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci /* notify switch of request for new multicast address */ 129562306a36Sopenharmony_ci err = hw->mac.ops.update_mc_addr(hw, vf_info->glort, 129662306a36Sopenharmony_ci mac, vlan, set); 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci return err; 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci/** 130362306a36Sopenharmony_ci * fm10k_iov_supported_xcast_mode_pf - Determine best match for xcast mode 130462306a36Sopenharmony_ci * @vf_info: VF info structure containing capability flags 130562306a36Sopenharmony_ci * @mode: Requested xcast mode 130662306a36Sopenharmony_ci * 130762306a36Sopenharmony_ci * This function outputs the mode that most closely matches the requested 130862306a36Sopenharmony_ci * mode. If not modes match it will request we disable the port 130962306a36Sopenharmony_ci **/ 131062306a36Sopenharmony_cistatic u8 fm10k_iov_supported_xcast_mode_pf(struct fm10k_vf_info *vf_info, 131162306a36Sopenharmony_ci u8 mode) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci u8 vf_flags = vf_info->vf_flags; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci /* match up mode to capabilities as best as possible */ 131662306a36Sopenharmony_ci switch (mode) { 131762306a36Sopenharmony_ci case FM10K_XCAST_MODE_PROMISC: 131862306a36Sopenharmony_ci if (vf_flags & FM10K_VF_FLAG_PROMISC_CAPABLE) 131962306a36Sopenharmony_ci return FM10K_XCAST_MODE_PROMISC; 132062306a36Sopenharmony_ci fallthrough; 132162306a36Sopenharmony_ci case FM10K_XCAST_MODE_ALLMULTI: 132262306a36Sopenharmony_ci if (vf_flags & FM10K_VF_FLAG_ALLMULTI_CAPABLE) 132362306a36Sopenharmony_ci return FM10K_XCAST_MODE_ALLMULTI; 132462306a36Sopenharmony_ci fallthrough; 132562306a36Sopenharmony_ci case FM10K_XCAST_MODE_MULTI: 132662306a36Sopenharmony_ci if (vf_flags & FM10K_VF_FLAG_MULTI_CAPABLE) 132762306a36Sopenharmony_ci return FM10K_XCAST_MODE_MULTI; 132862306a36Sopenharmony_ci fallthrough; 132962306a36Sopenharmony_ci case FM10K_XCAST_MODE_NONE: 133062306a36Sopenharmony_ci if (vf_flags & FM10K_VF_FLAG_NONE_CAPABLE) 133162306a36Sopenharmony_ci return FM10K_XCAST_MODE_NONE; 133262306a36Sopenharmony_ci fallthrough; 133362306a36Sopenharmony_ci default: 133462306a36Sopenharmony_ci break; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci /* disable interface as it should not be able to request any */ 133862306a36Sopenharmony_ci return FM10K_XCAST_MODE_DISABLE; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci/** 134262306a36Sopenharmony_ci * fm10k_iov_msg_lport_state_pf - Message handler for port state requests 134362306a36Sopenharmony_ci * @hw: Pointer to hardware structure 134462306a36Sopenharmony_ci * @results: Pointer array to message, results[0] is pointer to message 134562306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 134662306a36Sopenharmony_ci * 134762306a36Sopenharmony_ci * This function is a default handler for port state requests. The port 134862306a36Sopenharmony_ci * state requests for now are basic and consist of enabling or disabling 134962306a36Sopenharmony_ci * the port. 135062306a36Sopenharmony_ci **/ 135162306a36Sopenharmony_cis32 fm10k_iov_msg_lport_state_pf(struct fm10k_hw *hw, u32 **results, 135262306a36Sopenharmony_ci struct fm10k_mbx_info *mbx) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; 135562306a36Sopenharmony_ci s32 err = 0; 135662306a36Sopenharmony_ci u32 msg[2]; 135762306a36Sopenharmony_ci u8 mode = 0; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci /* verify VF is allowed to enable even minimal mode */ 136062306a36Sopenharmony_ci if (!(vf_info->vf_flags & FM10K_VF_FLAG_NONE_CAPABLE)) 136162306a36Sopenharmony_ci return FM10K_ERR_PARAM; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci if (!!results[FM10K_LPORT_STATE_MSG_XCAST_MODE]) { 136462306a36Sopenharmony_ci u32 *result = results[FM10K_LPORT_STATE_MSG_XCAST_MODE]; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* XCAST mode update requested */ 136762306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u8(result, &mode); 136862306a36Sopenharmony_ci if (err) 136962306a36Sopenharmony_ci return FM10K_ERR_PARAM; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* prep for possible demotion depending on capabilities */ 137262306a36Sopenharmony_ci mode = fm10k_iov_supported_xcast_mode_pf(vf_info, mode); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci /* if mode is not currently enabled, enable it */ 137562306a36Sopenharmony_ci if (!(FM10K_VF_FLAG_ENABLED(vf_info) & BIT(mode))) 137662306a36Sopenharmony_ci fm10k_update_xcast_mode_pf(hw, vf_info->glort, mode); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* swap mode back to a bit flag */ 137962306a36Sopenharmony_ci mode = FM10K_VF_FLAG_SET_MODE(mode); 138062306a36Sopenharmony_ci } else if (!results[FM10K_LPORT_STATE_MSG_DISABLE]) { 138162306a36Sopenharmony_ci /* need to disable the port if it is already enabled */ 138262306a36Sopenharmony_ci if (FM10K_VF_FLAG_ENABLED(vf_info)) 138362306a36Sopenharmony_ci err = fm10k_update_lport_state_pf(hw, vf_info->glort, 138462306a36Sopenharmony_ci 1, false); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* we need to clear VF_FLAG_ENABLED flags in order to ensure 138762306a36Sopenharmony_ci * that we actually re-enable the LPORT state below. Note that 138862306a36Sopenharmony_ci * this has no impact if the VF is already disabled, as the 138962306a36Sopenharmony_ci * flags are already cleared. 139062306a36Sopenharmony_ci */ 139162306a36Sopenharmony_ci if (!err) 139262306a36Sopenharmony_ci vf_info->vf_flags = FM10K_VF_FLAG_CAPABLE(vf_info); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci /* when enabling the port we should reset the rate limiters */ 139562306a36Sopenharmony_ci hw->iov.ops.configure_tc(hw, vf_info->vf_idx, vf_info->rate); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* set mode for minimal functionality */ 139862306a36Sopenharmony_ci mode = FM10K_VF_FLAG_SET_MODE_NONE; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* generate port state response to notify VF it is ready */ 140162306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); 140262306a36Sopenharmony_ci fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_READY); 140362306a36Sopenharmony_ci mbx->ops.enqueue_tx(hw, mbx, msg); 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* if enable state toggled note the update */ 140762306a36Sopenharmony_ci if (!err && (!FM10K_VF_FLAG_ENABLED(vf_info) != !mode)) 140862306a36Sopenharmony_ci err = fm10k_update_lport_state_pf(hw, vf_info->glort, 1, 140962306a36Sopenharmony_ci !!mode); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* if state change succeeded, then update our stored state */ 141262306a36Sopenharmony_ci mode |= FM10K_VF_FLAG_CAPABLE(vf_info); 141362306a36Sopenharmony_ci if (!err) 141462306a36Sopenharmony_ci vf_info->vf_flags = mode; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci return err; 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci/** 142062306a36Sopenharmony_ci * fm10k_update_hw_stats_pf - Updates hardware related statistics of PF 142162306a36Sopenharmony_ci * @hw: pointer to hardware structure 142262306a36Sopenharmony_ci * @stats: pointer to the stats structure to update 142362306a36Sopenharmony_ci * 142462306a36Sopenharmony_ci * This function collects and aggregates global and per queue hardware 142562306a36Sopenharmony_ci * statistics. 142662306a36Sopenharmony_ci **/ 142762306a36Sopenharmony_cistatic void fm10k_update_hw_stats_pf(struct fm10k_hw *hw, 142862306a36Sopenharmony_ci struct fm10k_hw_stats *stats) 142962306a36Sopenharmony_ci{ 143062306a36Sopenharmony_ci u32 timeout, ur, ca, um, xec, vlan_drop, loopback_drop, nodesc_drop; 143162306a36Sopenharmony_ci u32 id, id_prev; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* Use Tx queue 0 as a canary to detect a reset */ 143462306a36Sopenharmony_ci id = fm10k_read_reg(hw, FM10K_TXQCTL(0)); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci /* Read Global Statistics */ 143762306a36Sopenharmony_ci do { 143862306a36Sopenharmony_ci timeout = fm10k_read_hw_stats_32b(hw, FM10K_STATS_TIMEOUT, 143962306a36Sopenharmony_ci &stats->timeout); 144062306a36Sopenharmony_ci ur = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UR, &stats->ur); 144162306a36Sopenharmony_ci ca = fm10k_read_hw_stats_32b(hw, FM10K_STATS_CA, &stats->ca); 144262306a36Sopenharmony_ci um = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UM, &stats->um); 144362306a36Sopenharmony_ci xec = fm10k_read_hw_stats_32b(hw, FM10K_STATS_XEC, &stats->xec); 144462306a36Sopenharmony_ci vlan_drop = fm10k_read_hw_stats_32b(hw, FM10K_STATS_VLAN_DROP, 144562306a36Sopenharmony_ci &stats->vlan_drop); 144662306a36Sopenharmony_ci loopback_drop = 144762306a36Sopenharmony_ci fm10k_read_hw_stats_32b(hw, 144862306a36Sopenharmony_ci FM10K_STATS_LOOPBACK_DROP, 144962306a36Sopenharmony_ci &stats->loopback_drop); 145062306a36Sopenharmony_ci nodesc_drop = fm10k_read_hw_stats_32b(hw, 145162306a36Sopenharmony_ci FM10K_STATS_NODESC_DROP, 145262306a36Sopenharmony_ci &stats->nodesc_drop); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* if value has not changed then we have consistent data */ 145562306a36Sopenharmony_ci id_prev = id; 145662306a36Sopenharmony_ci id = fm10k_read_reg(hw, FM10K_TXQCTL(0)); 145762306a36Sopenharmony_ci } while ((id ^ id_prev) & FM10K_TXQCTL_ID_MASK); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci /* drop non-ID bits and set VALID ID bit */ 146062306a36Sopenharmony_ci id &= FM10K_TXQCTL_ID_MASK; 146162306a36Sopenharmony_ci id |= FM10K_STAT_VALID; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* Update Global Statistics */ 146462306a36Sopenharmony_ci if (stats->stats_idx == id) { 146562306a36Sopenharmony_ci stats->timeout.count += timeout; 146662306a36Sopenharmony_ci stats->ur.count += ur; 146762306a36Sopenharmony_ci stats->ca.count += ca; 146862306a36Sopenharmony_ci stats->um.count += um; 146962306a36Sopenharmony_ci stats->xec.count += xec; 147062306a36Sopenharmony_ci stats->vlan_drop.count += vlan_drop; 147162306a36Sopenharmony_ci stats->loopback_drop.count += loopback_drop; 147262306a36Sopenharmony_ci stats->nodesc_drop.count += nodesc_drop; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci /* Update bases and record current PF id */ 147662306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->timeout, timeout); 147762306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->ur, ur); 147862306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->ca, ca); 147962306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->um, um); 148062306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->xec, xec); 148162306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->vlan_drop, vlan_drop); 148262306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->loopback_drop, loopback_drop); 148362306a36Sopenharmony_ci fm10k_update_hw_base_32b(&stats->nodesc_drop, nodesc_drop); 148462306a36Sopenharmony_ci stats->stats_idx = id; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci /* Update Queue Statistics */ 148762306a36Sopenharmony_ci fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci/** 149162306a36Sopenharmony_ci * fm10k_rebind_hw_stats_pf - Resets base for hardware statistics of PF 149262306a36Sopenharmony_ci * @hw: pointer to hardware structure 149362306a36Sopenharmony_ci * @stats: pointer to the stats structure to update 149462306a36Sopenharmony_ci * 149562306a36Sopenharmony_ci * This function resets the base for global and per queue hardware 149662306a36Sopenharmony_ci * statistics. 149762306a36Sopenharmony_ci **/ 149862306a36Sopenharmony_cistatic void fm10k_rebind_hw_stats_pf(struct fm10k_hw *hw, 149962306a36Sopenharmony_ci struct fm10k_hw_stats *stats) 150062306a36Sopenharmony_ci{ 150162306a36Sopenharmony_ci /* Unbind Global Statistics */ 150262306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->timeout); 150362306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->ur); 150462306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->ca); 150562306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->um); 150662306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->xec); 150762306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->vlan_drop); 150862306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->loopback_drop); 150962306a36Sopenharmony_ci fm10k_unbind_hw_stats_32b(&stats->nodesc_drop); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci /* Unbind Queue Statistics */ 151262306a36Sopenharmony_ci fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* Reinitialize bases for all stats */ 151562306a36Sopenharmony_ci fm10k_update_hw_stats_pf(hw, stats); 151662306a36Sopenharmony_ci} 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci/** 151962306a36Sopenharmony_ci * fm10k_set_dma_mask_pf - Configures PhyAddrSpace to limit DMA to system 152062306a36Sopenharmony_ci * @hw: pointer to hardware structure 152162306a36Sopenharmony_ci * @dma_mask: 64 bit DMA mask required for platform 152262306a36Sopenharmony_ci * 152362306a36Sopenharmony_ci * This function sets the PHYADDR.PhyAddrSpace bits for the endpoint in order 152462306a36Sopenharmony_ci * to limit the access to memory beyond what is physically in the system. 152562306a36Sopenharmony_ci **/ 152662306a36Sopenharmony_cistatic void fm10k_set_dma_mask_pf(struct fm10k_hw *hw, u64 dma_mask) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci /* we need to write the upper 32 bits of DMA mask to PhyAddrSpace */ 152962306a36Sopenharmony_ci u32 phyaddr = (u32)(dma_mask >> 32); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_PHYADDR, phyaddr); 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci/** 153562306a36Sopenharmony_ci * fm10k_get_fault_pf - Record a fault in one of the interface units 153662306a36Sopenharmony_ci * @hw: pointer to hardware structure 153762306a36Sopenharmony_ci * @type: pointer to fault type register offset 153862306a36Sopenharmony_ci * @fault: pointer to memory location to record the fault 153962306a36Sopenharmony_ci * 154062306a36Sopenharmony_ci * Record the fault register contents to the fault data structure and 154162306a36Sopenharmony_ci * clear the entry from the register. 154262306a36Sopenharmony_ci * 154362306a36Sopenharmony_ci * Returns ERR_PARAM if invalid register is specified or no error is present. 154462306a36Sopenharmony_ci **/ 154562306a36Sopenharmony_cistatic s32 fm10k_get_fault_pf(struct fm10k_hw *hw, int type, 154662306a36Sopenharmony_ci struct fm10k_fault *fault) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci u32 func; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci /* verify the fault register is in range and is aligned */ 155162306a36Sopenharmony_ci switch (type) { 155262306a36Sopenharmony_ci case FM10K_PCA_FAULT: 155362306a36Sopenharmony_ci case FM10K_THI_FAULT: 155462306a36Sopenharmony_ci case FM10K_FUM_FAULT: 155562306a36Sopenharmony_ci break; 155662306a36Sopenharmony_ci default: 155762306a36Sopenharmony_ci return FM10K_ERR_PARAM; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci /* only service faults that are valid */ 156162306a36Sopenharmony_ci func = fm10k_read_reg(hw, type + FM10K_FAULT_FUNC); 156262306a36Sopenharmony_ci if (!(func & FM10K_FAULT_FUNC_VALID)) 156362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci /* read remaining fields */ 156662306a36Sopenharmony_ci fault->address = fm10k_read_reg(hw, type + FM10K_FAULT_ADDR_HI); 156762306a36Sopenharmony_ci fault->address <<= 32; 156862306a36Sopenharmony_ci fault->address |= fm10k_read_reg(hw, type + FM10K_FAULT_ADDR_LO); 156962306a36Sopenharmony_ci fault->specinfo = fm10k_read_reg(hw, type + FM10K_FAULT_SPECINFO); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* clear valid bit to allow for next error */ 157262306a36Sopenharmony_ci fm10k_write_reg(hw, type + FM10K_FAULT_FUNC, FM10K_FAULT_FUNC_VALID); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci /* Record which function triggered the error */ 157562306a36Sopenharmony_ci if (func & FM10K_FAULT_FUNC_PF) 157662306a36Sopenharmony_ci fault->func = 0; 157762306a36Sopenharmony_ci else 157862306a36Sopenharmony_ci fault->func = 1 + ((func & FM10K_FAULT_FUNC_VF_MASK) >> 157962306a36Sopenharmony_ci FM10K_FAULT_FUNC_VF_SHIFT); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci /* record fault type */ 158262306a36Sopenharmony_ci fault->type = func & FM10K_FAULT_FUNC_TYPE_MASK; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci return 0; 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci/** 158862306a36Sopenharmony_ci * fm10k_request_lport_map_pf - Request LPORT map from the switch API 158962306a36Sopenharmony_ci * @hw: pointer to hardware structure 159062306a36Sopenharmony_ci * 159162306a36Sopenharmony_ci **/ 159262306a36Sopenharmony_cistatic s32 fm10k_request_lport_map_pf(struct fm10k_hw *hw) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci struct fm10k_mbx_info *mbx = &hw->mbx; 159562306a36Sopenharmony_ci u32 msg[1]; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* issue request asking for LPORT map */ 159862306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_LPORT_MAP); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci /* load onto outgoing mailbox */ 160162306a36Sopenharmony_ci return mbx->ops.enqueue_tx(hw, mbx, msg); 160262306a36Sopenharmony_ci} 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci/** 160562306a36Sopenharmony_ci * fm10k_get_host_state_pf - Returns the state of the switch and mailbox 160662306a36Sopenharmony_ci * @hw: pointer to hardware structure 160762306a36Sopenharmony_ci * @switch_ready: pointer to boolean value that will record switch state 160862306a36Sopenharmony_ci * 160962306a36Sopenharmony_ci * This function will check the DMA_CTRL2 register and mailbox in order 161062306a36Sopenharmony_ci * to determine if the switch is ready for the PF to begin requesting 161162306a36Sopenharmony_ci * addresses and mapping traffic to the local interface. 161262306a36Sopenharmony_ci **/ 161362306a36Sopenharmony_cistatic s32 fm10k_get_host_state_pf(struct fm10k_hw *hw, bool *switch_ready) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci u32 dma_ctrl2; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci /* verify the switch is ready for interaction */ 161862306a36Sopenharmony_ci dma_ctrl2 = fm10k_read_reg(hw, FM10K_DMA_CTRL2); 161962306a36Sopenharmony_ci if (!(dma_ctrl2 & FM10K_DMA_CTRL2_SWITCH_READY)) 162062306a36Sopenharmony_ci return 0; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* retrieve generic host state info */ 162362306a36Sopenharmony_ci return fm10k_get_host_state_generic(hw, switch_ready); 162462306a36Sopenharmony_ci} 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci/* This structure defines the attibutes to be parsed below */ 162762306a36Sopenharmony_ciconst struct fm10k_tlv_attr fm10k_lport_map_msg_attr[] = { 162862306a36Sopenharmony_ci FM10K_TLV_ATTR_LE_STRUCT(FM10K_PF_ATTR_ID_ERR, 162962306a36Sopenharmony_ci sizeof(struct fm10k_swapi_error)), 163062306a36Sopenharmony_ci FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_LPORT_MAP), 163162306a36Sopenharmony_ci FM10K_TLV_ATTR_LAST 163262306a36Sopenharmony_ci}; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci/** 163562306a36Sopenharmony_ci * fm10k_msg_lport_map_pf - Message handler for lport_map message from SM 163662306a36Sopenharmony_ci * @hw: Pointer to hardware structure 163762306a36Sopenharmony_ci * @results: pointer array containing parsed data 163862306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 163962306a36Sopenharmony_ci * 164062306a36Sopenharmony_ci * This handler configures the lport mapping based on the reply from the 164162306a36Sopenharmony_ci * switch API. 164262306a36Sopenharmony_ci **/ 164362306a36Sopenharmony_cis32 fm10k_msg_lport_map_pf(struct fm10k_hw *hw, u32 **results, 164462306a36Sopenharmony_ci struct fm10k_mbx_info __always_unused *mbx) 164562306a36Sopenharmony_ci{ 164662306a36Sopenharmony_ci u16 glort, mask; 164762306a36Sopenharmony_ci u32 dglort_map; 164862306a36Sopenharmony_ci s32 err; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_LPORT_MAP], 165162306a36Sopenharmony_ci &dglort_map); 165262306a36Sopenharmony_ci if (err) 165362306a36Sopenharmony_ci return err; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci /* extract values out of the header */ 165662306a36Sopenharmony_ci glort = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_GLORT); 165762306a36Sopenharmony_ci mask = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_MASK); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci /* verify mask is set and none of the masked bits in glort are set */ 166062306a36Sopenharmony_ci if (!mask || (glort & ~mask)) 166162306a36Sopenharmony_ci return FM10K_ERR_PARAM; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci /* verify the mask is contiguous, and that it is 1's followed by 0's */ 166462306a36Sopenharmony_ci if (((~(mask - 1) & mask) + mask) & FM10K_DGLORTMAP_NONE) 166562306a36Sopenharmony_ci return FM10K_ERR_PARAM; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci /* record the glort, mask, and port count */ 166862306a36Sopenharmony_ci hw->mac.dglort_map = dglort_map; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci return 0; 167162306a36Sopenharmony_ci} 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ciconst struct fm10k_tlv_attr fm10k_update_pvid_msg_attr[] = { 167462306a36Sopenharmony_ci FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_UPDATE_PVID), 167562306a36Sopenharmony_ci FM10K_TLV_ATTR_LAST 167662306a36Sopenharmony_ci}; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci/** 167962306a36Sopenharmony_ci * fm10k_msg_update_pvid_pf - Message handler for port VLAN message from SM 168062306a36Sopenharmony_ci * @hw: Pointer to hardware structure 168162306a36Sopenharmony_ci * @results: pointer array containing parsed data 168262306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 168362306a36Sopenharmony_ci * 168462306a36Sopenharmony_ci * This handler configures the default VLAN for the PF 168562306a36Sopenharmony_ci **/ 168662306a36Sopenharmony_cistatic s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *hw, u32 **results, 168762306a36Sopenharmony_ci struct fm10k_mbx_info __always_unused *mbx) 168862306a36Sopenharmony_ci{ 168962306a36Sopenharmony_ci u16 glort, pvid; 169062306a36Sopenharmony_ci u32 pvid_update; 169162306a36Sopenharmony_ci s32 err; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_UPDATE_PVID], 169462306a36Sopenharmony_ci &pvid_update); 169562306a36Sopenharmony_ci if (err) 169662306a36Sopenharmony_ci return err; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci /* extract values from the pvid update */ 169962306a36Sopenharmony_ci glort = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_GLORT); 170062306a36Sopenharmony_ci pvid = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_PVID); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* if glort is not valid return error */ 170362306a36Sopenharmony_ci if (!fm10k_glort_valid_pf(hw, glort)) 170462306a36Sopenharmony_ci return FM10K_ERR_PARAM; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci /* verify VLAN ID is valid */ 170762306a36Sopenharmony_ci if (pvid >= FM10K_VLAN_TABLE_VID_MAX) 170862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci /* record the port VLAN ID value */ 171162306a36Sopenharmony_ci hw->mac.default_vid = pvid; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci return 0; 171462306a36Sopenharmony_ci} 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci/** 171762306a36Sopenharmony_ci * fm10k_record_global_table_data - Move global table data to swapi table info 171862306a36Sopenharmony_ci * @from: pointer to source table data structure 171962306a36Sopenharmony_ci * @to: pointer to destination table info structure 172062306a36Sopenharmony_ci * 172162306a36Sopenharmony_ci * This function is will copy table_data to the table_info contained in 172262306a36Sopenharmony_ci * the hw struct. 172362306a36Sopenharmony_ci **/ 172462306a36Sopenharmony_cistatic void fm10k_record_global_table_data(struct fm10k_global_table_data *from, 172562306a36Sopenharmony_ci struct fm10k_swapi_table_info *to) 172662306a36Sopenharmony_ci{ 172762306a36Sopenharmony_ci /* convert from le32 struct to CPU byte ordered values */ 172862306a36Sopenharmony_ci to->used = le32_to_cpu(from->used); 172962306a36Sopenharmony_ci to->avail = le32_to_cpu(from->avail); 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ciconst struct fm10k_tlv_attr fm10k_err_msg_attr[] = { 173362306a36Sopenharmony_ci FM10K_TLV_ATTR_LE_STRUCT(FM10K_PF_ATTR_ID_ERR, 173462306a36Sopenharmony_ci sizeof(struct fm10k_swapi_error)), 173562306a36Sopenharmony_ci FM10K_TLV_ATTR_LAST 173662306a36Sopenharmony_ci}; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci/** 173962306a36Sopenharmony_ci * fm10k_msg_err_pf - Message handler for error reply 174062306a36Sopenharmony_ci * @hw: Pointer to hardware structure 174162306a36Sopenharmony_ci * @results: pointer array containing parsed data 174262306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 174362306a36Sopenharmony_ci * 174462306a36Sopenharmony_ci * This handler will capture the data for any error replies to previous 174562306a36Sopenharmony_ci * messages that the PF has sent. 174662306a36Sopenharmony_ci **/ 174762306a36Sopenharmony_cis32 fm10k_msg_err_pf(struct fm10k_hw *hw, u32 **results, 174862306a36Sopenharmony_ci struct fm10k_mbx_info __always_unused *mbx) 174962306a36Sopenharmony_ci{ 175062306a36Sopenharmony_ci struct fm10k_swapi_error err_msg; 175162306a36Sopenharmony_ci s32 err; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci /* extract structure from message */ 175462306a36Sopenharmony_ci err = fm10k_tlv_attr_get_le_struct(results[FM10K_PF_ATTR_ID_ERR], 175562306a36Sopenharmony_ci &err_msg, sizeof(err_msg)); 175662306a36Sopenharmony_ci if (err) 175762306a36Sopenharmony_ci return err; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci /* record table status */ 176062306a36Sopenharmony_ci fm10k_record_global_table_data(&err_msg.mac, &hw->swapi.mac); 176162306a36Sopenharmony_ci fm10k_record_global_table_data(&err_msg.nexthop, &hw->swapi.nexthop); 176262306a36Sopenharmony_ci fm10k_record_global_table_data(&err_msg.ffu, &hw->swapi.ffu); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci /* record SW API status value */ 176562306a36Sopenharmony_ci hw->swapi.status = le32_to_cpu(err_msg.status); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci return 0; 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_cistatic const struct fm10k_msg_data fm10k_msg_data_pf[] = { 177162306a36Sopenharmony_ci FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf), 177262306a36Sopenharmony_ci FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf), 177362306a36Sopenharmony_ci FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_msg_lport_map_pf), 177462306a36Sopenharmony_ci FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf), 177562306a36Sopenharmony_ci FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf), 177662306a36Sopenharmony_ci FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_msg_update_pvid_pf), 177762306a36Sopenharmony_ci FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), 177862306a36Sopenharmony_ci}; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_cistatic const struct fm10k_mac_ops mac_ops_pf = { 178162306a36Sopenharmony_ci .get_bus_info = fm10k_get_bus_info_generic, 178262306a36Sopenharmony_ci .reset_hw = fm10k_reset_hw_pf, 178362306a36Sopenharmony_ci .init_hw = fm10k_init_hw_pf, 178462306a36Sopenharmony_ci .start_hw = fm10k_start_hw_generic, 178562306a36Sopenharmony_ci .stop_hw = fm10k_stop_hw_generic, 178662306a36Sopenharmony_ci .update_vlan = fm10k_update_vlan_pf, 178762306a36Sopenharmony_ci .read_mac_addr = fm10k_read_mac_addr_pf, 178862306a36Sopenharmony_ci .update_uc_addr = fm10k_update_uc_addr_pf, 178962306a36Sopenharmony_ci .update_mc_addr = fm10k_update_mc_addr_pf, 179062306a36Sopenharmony_ci .update_xcast_mode = fm10k_update_xcast_mode_pf, 179162306a36Sopenharmony_ci .update_int_moderator = fm10k_update_int_moderator_pf, 179262306a36Sopenharmony_ci .update_lport_state = fm10k_update_lport_state_pf, 179362306a36Sopenharmony_ci .update_hw_stats = fm10k_update_hw_stats_pf, 179462306a36Sopenharmony_ci .rebind_hw_stats = fm10k_rebind_hw_stats_pf, 179562306a36Sopenharmony_ci .configure_dglort_map = fm10k_configure_dglort_map_pf, 179662306a36Sopenharmony_ci .set_dma_mask = fm10k_set_dma_mask_pf, 179762306a36Sopenharmony_ci .get_fault = fm10k_get_fault_pf, 179862306a36Sopenharmony_ci .get_host_state = fm10k_get_host_state_pf, 179962306a36Sopenharmony_ci .request_lport_map = fm10k_request_lport_map_pf, 180062306a36Sopenharmony_ci}; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_cistatic const struct fm10k_iov_ops iov_ops_pf = { 180362306a36Sopenharmony_ci .assign_resources = fm10k_iov_assign_resources_pf, 180462306a36Sopenharmony_ci .configure_tc = fm10k_iov_configure_tc_pf, 180562306a36Sopenharmony_ci .assign_int_moderator = fm10k_iov_assign_int_moderator_pf, 180662306a36Sopenharmony_ci .assign_default_mac_vlan = fm10k_iov_assign_default_mac_vlan_pf, 180762306a36Sopenharmony_ci .reset_resources = fm10k_iov_reset_resources_pf, 180862306a36Sopenharmony_ci .set_lport = fm10k_iov_set_lport_pf, 180962306a36Sopenharmony_ci .reset_lport = fm10k_iov_reset_lport_pf, 181062306a36Sopenharmony_ci .update_stats = fm10k_iov_update_stats_pf, 181162306a36Sopenharmony_ci}; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_cistatic s32 fm10k_get_invariants_pf(struct fm10k_hw *hw) 181462306a36Sopenharmony_ci{ 181562306a36Sopenharmony_ci fm10k_get_invariants_generic(hw); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci return fm10k_sm_mbx_init(hw, &hw->mbx, fm10k_msg_data_pf); 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ciconst struct fm10k_info fm10k_pf_info = { 182162306a36Sopenharmony_ci .mac = fm10k_mac_pf, 182262306a36Sopenharmony_ci .get_invariants = fm10k_get_invariants_pf, 182362306a36Sopenharmony_ci .mac_ops = &mac_ops_pf, 182462306a36Sopenharmony_ci .iov_ops = &iov_ops_pf, 182562306a36Sopenharmony_ci}; 1826