1b6fec18fSAlexander Duyck /* Intel Ethernet Switch Host Interface Driver 2b6fec18fSAlexander Duyck * Copyright(c) 2013 - 2014 Intel Corporation. 3b6fec18fSAlexander Duyck * 4b6fec18fSAlexander Duyck * This program is free software; you can redistribute it and/or modify it 5b6fec18fSAlexander Duyck * under the terms and conditions of the GNU General Public License, 6b6fec18fSAlexander Duyck * version 2, as published by the Free Software Foundation. 7b6fec18fSAlexander Duyck * 8b6fec18fSAlexander Duyck * This program is distributed in the hope it will be useful, but WITHOUT 9b6fec18fSAlexander Duyck * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10b6fec18fSAlexander Duyck * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11b6fec18fSAlexander Duyck * more details. 12b6fec18fSAlexander Duyck * 13b6fec18fSAlexander Duyck * The full GNU General Public License is included in this distribution in 14b6fec18fSAlexander Duyck * the file called "COPYING". 15b6fec18fSAlexander Duyck * 16b6fec18fSAlexander Duyck * Contact Information: 17b6fec18fSAlexander Duyck * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 18b6fec18fSAlexander Duyck * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 19b6fec18fSAlexander Duyck */ 20b6fec18fSAlexander Duyck 21b6fec18fSAlexander Duyck #include "fm10k_pf.h" 22b6fec18fSAlexander Duyck 23b6fec18fSAlexander Duyck /** 24b6fec18fSAlexander Duyck * fm10k_reset_hw_pf - PF hardware reset 25b6fec18fSAlexander Duyck * @hw: pointer to hardware structure 26b6fec18fSAlexander Duyck * 27b6fec18fSAlexander Duyck * This function should return the hardware to a state similar to the 28b6fec18fSAlexander Duyck * one it is in after being powered on. 29b6fec18fSAlexander Duyck **/ 30b6fec18fSAlexander Duyck static s32 fm10k_reset_hw_pf(struct fm10k_hw *hw) 31b6fec18fSAlexander Duyck { 32b6fec18fSAlexander Duyck s32 err; 33b6fec18fSAlexander Duyck u32 reg; 34b6fec18fSAlexander Duyck u16 i; 35b6fec18fSAlexander Duyck 36b6fec18fSAlexander Duyck /* Disable interrupts */ 37b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_EIMR, FM10K_EIMR_DISABLE(ALL)); 38b6fec18fSAlexander Duyck 39b6fec18fSAlexander Duyck /* Lock ITR2 reg 0 into itself and disable interrupt moderation */ 40b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_ITR2(0), 0); 41b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_INT_CTRL, 0); 42b6fec18fSAlexander Duyck 43b6fec18fSAlexander Duyck /* We assume here Tx and Rx queue 0 are owned by the PF */ 44b6fec18fSAlexander Duyck 45b6fec18fSAlexander Duyck /* Shut off VF access to their queues forcing them to queue 0 */ 46b6fec18fSAlexander Duyck for (i = 0; i < FM10K_TQMAP_TABLE_SIZE; i++) { 47b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_TQMAP(i), 0); 48b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_RQMAP(i), 0); 49b6fec18fSAlexander Duyck } 50b6fec18fSAlexander Duyck 51b6fec18fSAlexander Duyck /* shut down all rings */ 52b6fec18fSAlexander Duyck err = fm10k_disable_queues_generic(hw, FM10K_MAX_QUEUES); 53b6fec18fSAlexander Duyck if (err) 54b6fec18fSAlexander Duyck return err; 55b6fec18fSAlexander Duyck 56b6fec18fSAlexander Duyck /* Verify that DMA is no longer active */ 57b6fec18fSAlexander Duyck reg = fm10k_read_reg(hw, FM10K_DMA_CTRL); 58b6fec18fSAlexander Duyck if (reg & (FM10K_DMA_CTRL_TX_ACTIVE | FM10K_DMA_CTRL_RX_ACTIVE)) 59b6fec18fSAlexander Duyck return FM10K_ERR_DMA_PENDING; 60b6fec18fSAlexander Duyck 61b6fec18fSAlexander Duyck /* Inititate data path reset */ 62b6fec18fSAlexander Duyck reg |= FM10K_DMA_CTRL_DATAPATH_RESET; 63b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_DMA_CTRL, reg); 64b6fec18fSAlexander Duyck 65b6fec18fSAlexander Duyck /* Flush write and allow 100us for reset to complete */ 66b6fec18fSAlexander Duyck fm10k_write_flush(hw); 67b6fec18fSAlexander Duyck udelay(FM10K_RESET_TIMEOUT); 68b6fec18fSAlexander Duyck 69b6fec18fSAlexander Duyck /* Verify we made it out of reset */ 70b6fec18fSAlexander Duyck reg = fm10k_read_reg(hw, FM10K_IP); 71b6fec18fSAlexander Duyck if (!(reg & FM10K_IP_NOTINRESET)) 72b6fec18fSAlexander Duyck err = FM10K_ERR_RESET_FAILED; 73b6fec18fSAlexander Duyck 74b6fec18fSAlexander Duyck return err; 75b6fec18fSAlexander Duyck } 76b6fec18fSAlexander Duyck 77b6fec18fSAlexander Duyck /** 78b6fec18fSAlexander Duyck * fm10k_init_hw_pf - PF hardware initialization 79b6fec18fSAlexander Duyck * @hw: pointer to hardware structure 80b6fec18fSAlexander Duyck * 81b6fec18fSAlexander Duyck **/ 82b6fec18fSAlexander Duyck static s32 fm10k_init_hw_pf(struct fm10k_hw *hw) 83b6fec18fSAlexander Duyck { 84b6fec18fSAlexander Duyck u32 dma_ctrl, txqctl; 85b6fec18fSAlexander Duyck u16 i; 86b6fec18fSAlexander Duyck 87b6fec18fSAlexander Duyck /* Establish default VSI as valid */ 88b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_DGLORTDEC(fm10k_dglort_default), 0); 89b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_default), 90b6fec18fSAlexander Duyck FM10K_DGLORTMAP_ANY); 91b6fec18fSAlexander Duyck 92b6fec18fSAlexander Duyck /* Invalidate all other GLORT entries */ 93b6fec18fSAlexander Duyck for (i = 1; i < FM10K_DGLORT_COUNT; i++) 94b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_DGLORTMAP(i), FM10K_DGLORTMAP_NONE); 95b6fec18fSAlexander Duyck 96b6fec18fSAlexander Duyck /* reset ITR2(0) to point to itself */ 97b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_ITR2(0), 0); 98b6fec18fSAlexander Duyck 99b6fec18fSAlexander Duyck /* reset VF ITR2(0) to point to 0 avoid PF registers */ 100b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), 0); 101b6fec18fSAlexander Duyck 102b6fec18fSAlexander Duyck /* loop through all PF ITR2 registers pointing them to the previous */ 103b6fec18fSAlexander Duyck for (i = 1; i < FM10K_ITR_REG_COUNT_PF; i++) 104b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_ITR2(i), i - 1); 105b6fec18fSAlexander Duyck 106b6fec18fSAlexander Duyck /* Enable interrupt moderator if not already enabled */ 107b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); 108b6fec18fSAlexander Duyck 109b6fec18fSAlexander Duyck /* compute the default txqctl configuration */ 110b6fec18fSAlexander Duyck txqctl = FM10K_TXQCTL_PF | FM10K_TXQCTL_UNLIMITED_BW | 111b6fec18fSAlexander Duyck (hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT); 112b6fec18fSAlexander Duyck 113b6fec18fSAlexander Duyck for (i = 0; i < FM10K_MAX_QUEUES; i++) { 114b6fec18fSAlexander Duyck /* configure rings for 256 Queue / 32 Descriptor cache mode */ 115b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_TQDLOC(i), 116b6fec18fSAlexander Duyck (i * FM10K_TQDLOC_BASE_32_DESC) | 117b6fec18fSAlexander Duyck FM10K_TQDLOC_SIZE_32_DESC); 118b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_TXQCTL(i), txqctl); 119b6fec18fSAlexander Duyck 120b6fec18fSAlexander Duyck /* configure rings to provide TPH processing hints */ 121b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_TPH_TXCTRL(i), 122b6fec18fSAlexander Duyck FM10K_TPH_TXCTRL_DESC_TPHEN | 123b6fec18fSAlexander Duyck FM10K_TPH_TXCTRL_DESC_RROEN | 124b6fec18fSAlexander Duyck FM10K_TPH_TXCTRL_DESC_WROEN | 125b6fec18fSAlexander Duyck FM10K_TPH_TXCTRL_DATA_RROEN); 126b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_TPH_RXCTRL(i), 127b6fec18fSAlexander Duyck FM10K_TPH_RXCTRL_DESC_TPHEN | 128b6fec18fSAlexander Duyck FM10K_TPH_RXCTRL_DESC_RROEN | 129b6fec18fSAlexander Duyck FM10K_TPH_RXCTRL_DATA_WROEN | 130b6fec18fSAlexander Duyck FM10K_TPH_RXCTRL_HDR_WROEN); 131b6fec18fSAlexander Duyck } 132b6fec18fSAlexander Duyck 133b6fec18fSAlexander Duyck /* set max hold interval to align with 1.024 usec in all modes */ 134b6fec18fSAlexander Duyck switch (hw->bus.speed) { 135b6fec18fSAlexander Duyck case fm10k_bus_speed_2500: 136b6fec18fSAlexander Duyck dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1; 137b6fec18fSAlexander Duyck break; 138b6fec18fSAlexander Duyck case fm10k_bus_speed_5000: 139b6fec18fSAlexander Duyck dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2; 140b6fec18fSAlexander Duyck break; 141b6fec18fSAlexander Duyck case fm10k_bus_speed_8000: 142b6fec18fSAlexander Duyck dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3; 143b6fec18fSAlexander Duyck break; 144b6fec18fSAlexander Duyck default: 145b6fec18fSAlexander Duyck dma_ctrl = 0; 146b6fec18fSAlexander Duyck break; 147b6fec18fSAlexander Duyck } 148b6fec18fSAlexander Duyck 149b6fec18fSAlexander Duyck /* Configure TSO flags */ 150b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_DTXTCPFLGL, FM10K_TSO_FLAGS_LOW); 151b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_DTXTCPFLGH, FM10K_TSO_FLAGS_HI); 152b6fec18fSAlexander Duyck 153b6fec18fSAlexander Duyck /* Enable DMA engine 154b6fec18fSAlexander Duyck * Set Rx Descriptor size to 32 155b6fec18fSAlexander Duyck * Set Minimum MSS to 64 156b6fec18fSAlexander Duyck * Set Maximum number of Rx queues to 256 / 32 Descriptor 157b6fec18fSAlexander Duyck */ 158b6fec18fSAlexander Duyck dma_ctrl |= FM10K_DMA_CTRL_TX_ENABLE | FM10K_DMA_CTRL_RX_ENABLE | 159b6fec18fSAlexander Duyck FM10K_DMA_CTRL_RX_DESC_SIZE | FM10K_DMA_CTRL_MINMSS_64 | 160b6fec18fSAlexander Duyck FM10K_DMA_CTRL_32_DESC; 161b6fec18fSAlexander Duyck 162b6fec18fSAlexander Duyck fm10k_write_reg(hw, FM10K_DMA_CTRL, dma_ctrl); 163b6fec18fSAlexander Duyck 164b6fec18fSAlexander Duyck /* record maximum queue count, we limit ourselves to 128 */ 165b6fec18fSAlexander Duyck hw->mac.max_queues = FM10K_MAX_QUEUES_PF; 166b6fec18fSAlexander Duyck 167b6fec18fSAlexander Duyck return 0; 168b6fec18fSAlexander Duyck } 169b6fec18fSAlexander Duyck 170b6fec18fSAlexander Duyck /** 171b6fec18fSAlexander Duyck * fm10k_is_slot_appropriate_pf - Indicate appropriate slot for this SKU 172b6fec18fSAlexander Duyck * @hw: pointer to hardware structure 173b6fec18fSAlexander Duyck * 174b6fec18fSAlexander Duyck * Looks at the PCIe bus info to confirm whether or not this slot can support 175b6fec18fSAlexander Duyck * the necessary bandwidth for this device. 176b6fec18fSAlexander Duyck **/ 177b6fec18fSAlexander Duyck static bool fm10k_is_slot_appropriate_pf(struct fm10k_hw *hw) 178b6fec18fSAlexander Duyck { 179b6fec18fSAlexander Duyck return (hw->bus.speed == hw->bus_caps.speed) && 180b6fec18fSAlexander Duyck (hw->bus.width == hw->bus_caps.width); 181b6fec18fSAlexander Duyck } 182b6fec18fSAlexander Duyck 183b6fec18fSAlexander Duyck /** 184401b5383SAlexander Duyck * fm10k_update_vlan_pf - Update status of VLAN ID in VLAN filter table 185401b5383SAlexander Duyck * @hw: pointer to hardware structure 186401b5383SAlexander Duyck * @vid: VLAN ID to add to table 187401b5383SAlexander Duyck * @vsi: Index indicating VF ID or PF ID in table 188401b5383SAlexander Duyck * @set: Indicates if this is a set or clear operation 189401b5383SAlexander Duyck * 190401b5383SAlexander Duyck * This function adds or removes the corresponding VLAN ID from the VLAN 191401b5383SAlexander Duyck * filter table for the corresponding function. In addition to the 192401b5383SAlexander Duyck * standard set/clear that supports one bit a multi-bit write is 193401b5383SAlexander Duyck * supported to set 64 bits at a time. 194401b5383SAlexander Duyck **/ 195401b5383SAlexander Duyck static s32 fm10k_update_vlan_pf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set) 196401b5383SAlexander Duyck { 197401b5383SAlexander Duyck u32 vlan_table, reg, mask, bit, len; 198401b5383SAlexander Duyck 199401b5383SAlexander Duyck /* verify the VSI index is valid */ 200401b5383SAlexander Duyck if (vsi > FM10K_VLAN_TABLE_VSI_MAX) 201401b5383SAlexander Duyck return FM10K_ERR_PARAM; 202401b5383SAlexander Duyck 203401b5383SAlexander Duyck /* VLAN multi-bit write: 204401b5383SAlexander Duyck * The multi-bit write has several parts to it. 205401b5383SAlexander Duyck * 3 2 1 0 206401b5383SAlexander Duyck * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 207401b5383SAlexander Duyck * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 208401b5383SAlexander Duyck * | RSVD0 | Length |C|RSVD0| VLAN ID | 209401b5383SAlexander Duyck * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 210401b5383SAlexander Duyck * 211401b5383SAlexander Duyck * VLAN ID: Vlan Starting value 212401b5383SAlexander Duyck * RSVD0: Reserved section, must be 0 213401b5383SAlexander Duyck * C: Flag field, 0 is set, 1 is clear (Used in VF VLAN message) 214401b5383SAlexander Duyck * Length: Number of times to repeat the bit being set 215401b5383SAlexander Duyck */ 216401b5383SAlexander Duyck len = vid >> 16; 217401b5383SAlexander Duyck vid = (vid << 17) >> 17; 218401b5383SAlexander Duyck 219401b5383SAlexander Duyck /* verify the reserved 0 fields are 0 */ 220401b5383SAlexander Duyck if (len >= FM10K_VLAN_TABLE_VID_MAX || 221401b5383SAlexander Duyck vid >= FM10K_VLAN_TABLE_VID_MAX) 222401b5383SAlexander Duyck return FM10K_ERR_PARAM; 223401b5383SAlexander Duyck 224401b5383SAlexander Duyck /* Loop through the table updating all required VLANs */ 225401b5383SAlexander Duyck for (reg = FM10K_VLAN_TABLE(vsi, vid / 32), bit = vid % 32; 226401b5383SAlexander Duyck len < FM10K_VLAN_TABLE_VID_MAX; 227401b5383SAlexander Duyck len -= 32 - bit, reg++, bit = 0) { 228401b5383SAlexander Duyck /* record the initial state of the register */ 229401b5383SAlexander Duyck vlan_table = fm10k_read_reg(hw, reg); 230401b5383SAlexander Duyck 231401b5383SAlexander Duyck /* truncate mask if we are at the start or end of the run */ 232401b5383SAlexander Duyck mask = (~(u32)0 >> ((len < 31) ? 31 - len : 0)) << bit; 233401b5383SAlexander Duyck 234401b5383SAlexander Duyck /* make necessary modifications to the register */ 235401b5383SAlexander Duyck mask &= set ? ~vlan_table : vlan_table; 236401b5383SAlexander Duyck if (mask) 237401b5383SAlexander Duyck fm10k_write_reg(hw, reg, vlan_table ^ mask); 238401b5383SAlexander Duyck } 239401b5383SAlexander Duyck 240401b5383SAlexander Duyck return 0; 241401b5383SAlexander Duyck } 242401b5383SAlexander Duyck 243401b5383SAlexander Duyck /** 244b6fec18fSAlexander Duyck * fm10k_read_mac_addr_pf - Read device MAC address 245b6fec18fSAlexander Duyck * @hw: pointer to the HW structure 246b6fec18fSAlexander Duyck * 247b6fec18fSAlexander Duyck * Reads the device MAC address from the SM_AREA and stores the value. 248b6fec18fSAlexander Duyck **/ 249b6fec18fSAlexander Duyck static s32 fm10k_read_mac_addr_pf(struct fm10k_hw *hw) 250b6fec18fSAlexander Duyck { 251b6fec18fSAlexander Duyck u8 perm_addr[ETH_ALEN]; 252b6fec18fSAlexander Duyck u32 serial_num; 253b6fec18fSAlexander Duyck int i; 254b6fec18fSAlexander Duyck 255b6fec18fSAlexander Duyck serial_num = fm10k_read_reg(hw, FM10K_SM_AREA(1)); 256b6fec18fSAlexander Duyck 257b6fec18fSAlexander Duyck /* last byte should be all 1's */ 258b6fec18fSAlexander Duyck if ((~serial_num) << 24) 259b6fec18fSAlexander Duyck return FM10K_ERR_INVALID_MAC_ADDR; 260b6fec18fSAlexander Duyck 261b6fec18fSAlexander Duyck perm_addr[0] = (u8)(serial_num >> 24); 262b6fec18fSAlexander Duyck perm_addr[1] = (u8)(serial_num >> 16); 263b6fec18fSAlexander Duyck perm_addr[2] = (u8)(serial_num >> 8); 264b6fec18fSAlexander Duyck 265b6fec18fSAlexander Duyck serial_num = fm10k_read_reg(hw, FM10K_SM_AREA(0)); 266b6fec18fSAlexander Duyck 267b6fec18fSAlexander Duyck /* first byte should be all 1's */ 268b6fec18fSAlexander Duyck if ((~serial_num) >> 24) 269b6fec18fSAlexander Duyck return FM10K_ERR_INVALID_MAC_ADDR; 270b6fec18fSAlexander Duyck 271b6fec18fSAlexander Duyck perm_addr[3] = (u8)(serial_num >> 16); 272b6fec18fSAlexander Duyck perm_addr[4] = (u8)(serial_num >> 8); 273b6fec18fSAlexander Duyck perm_addr[5] = (u8)(serial_num); 274b6fec18fSAlexander Duyck 275b6fec18fSAlexander Duyck for (i = 0; i < ETH_ALEN; i++) { 276b6fec18fSAlexander Duyck hw->mac.perm_addr[i] = perm_addr[i]; 277b6fec18fSAlexander Duyck hw->mac.addr[i] = perm_addr[i]; 278b6fec18fSAlexander Duyck } 279b6fec18fSAlexander Duyck 280b6fec18fSAlexander Duyck return 0; 281b6fec18fSAlexander Duyck } 282b6fec18fSAlexander Duyck 283b6fec18fSAlexander Duyck /** 284401b5383SAlexander Duyck * fm10k_glort_valid_pf - Validate that the provided glort is valid 285401b5383SAlexander Duyck * @hw: pointer to the HW structure 286401b5383SAlexander Duyck * @glort: base glort to be validated 287401b5383SAlexander Duyck * 288401b5383SAlexander Duyck * This function will return an error if the provided glort is invalid 289401b5383SAlexander Duyck **/ 290401b5383SAlexander Duyck bool fm10k_glort_valid_pf(struct fm10k_hw *hw, u16 glort) 291401b5383SAlexander Duyck { 292401b5383SAlexander Duyck glort &= hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT; 293401b5383SAlexander Duyck 294401b5383SAlexander Duyck return glort == (hw->mac.dglort_map & FM10K_DGLORTMAP_NONE); 295401b5383SAlexander Duyck } 296401b5383SAlexander Duyck 297401b5383SAlexander Duyck /** 298401b5383SAlexander Duyck * fm10k_update_uc_addr_pf - Update device unicast addresss 299401b5383SAlexander Duyck * @hw: pointer to the HW structure 300401b5383SAlexander Duyck * @glort: base resource tag for this request 301401b5383SAlexander Duyck * @mac: MAC address to add/remove from table 302401b5383SAlexander Duyck * @vid: VLAN ID to add/remove from table 303401b5383SAlexander Duyck * @add: Indicates if this is an add or remove operation 304401b5383SAlexander Duyck * @flags: flags field to indicate add and secure 305401b5383SAlexander Duyck * 306401b5383SAlexander Duyck * This function generates a message to the Switch API requesting 307401b5383SAlexander Duyck * that the given logical port add/remove the given L2 MAC/VLAN address. 308401b5383SAlexander Duyck **/ 309401b5383SAlexander Duyck static s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort, 310401b5383SAlexander Duyck const u8 *mac, u16 vid, bool add, u8 flags) 311401b5383SAlexander Duyck { 312401b5383SAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx; 313401b5383SAlexander Duyck struct fm10k_mac_update mac_update; 314401b5383SAlexander Duyck u32 msg[5]; 315401b5383SAlexander Duyck 316401b5383SAlexander Duyck /* if glort is not valid return error */ 317401b5383SAlexander Duyck if (!fm10k_glort_valid_pf(hw, glort)) 318401b5383SAlexander Duyck return FM10K_ERR_PARAM; 319401b5383SAlexander Duyck 320401b5383SAlexander Duyck /* drop upper 4 bits of VLAN ID */ 321401b5383SAlexander Duyck vid = (vid << 4) >> 4; 322401b5383SAlexander Duyck 323401b5383SAlexander Duyck /* record fields */ 324401b5383SAlexander Duyck mac_update.mac_lower = cpu_to_le32(((u32)mac[2] << 24) | 325401b5383SAlexander Duyck ((u32)mac[3] << 16) | 326401b5383SAlexander Duyck ((u32)mac[4] << 8) | 327401b5383SAlexander Duyck ((u32)mac[5])); 328401b5383SAlexander Duyck mac_update.mac_upper = cpu_to_le16(((u32)mac[0] << 8) | 329401b5383SAlexander Duyck ((u32)mac[1])); 330401b5383SAlexander Duyck mac_update.vlan = cpu_to_le16(vid); 331401b5383SAlexander Duyck mac_update.glort = cpu_to_le16(glort); 332401b5383SAlexander Duyck mac_update.action = add ? 0 : 1; 333401b5383SAlexander Duyck mac_update.flags = flags; 334401b5383SAlexander Duyck 335401b5383SAlexander Duyck /* populate mac_update fields */ 336401b5383SAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_UPDATE_MAC_FWD_RULE); 337401b5383SAlexander Duyck fm10k_tlv_attr_put_le_struct(msg, FM10K_PF_ATTR_ID_MAC_UPDATE, 338401b5383SAlexander Duyck &mac_update, sizeof(mac_update)); 339401b5383SAlexander Duyck 340401b5383SAlexander Duyck /* load onto outgoing mailbox */ 341401b5383SAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg); 342401b5383SAlexander Duyck } 343401b5383SAlexander Duyck 344401b5383SAlexander Duyck /** 345401b5383SAlexander Duyck * fm10k_update_uc_addr_pf - Update device unicast addresss 346401b5383SAlexander Duyck * @hw: pointer to the HW structure 347401b5383SAlexander Duyck * @glort: base resource tag for this request 348401b5383SAlexander Duyck * @mac: MAC address to add/remove from table 349401b5383SAlexander Duyck * @vid: VLAN ID to add/remove from table 350401b5383SAlexander Duyck * @add: Indicates if this is an add or remove operation 351401b5383SAlexander Duyck * @flags: flags field to indicate add and secure 352401b5383SAlexander Duyck * 353401b5383SAlexander Duyck * This function is used to add or remove unicast addresses for 354401b5383SAlexander Duyck * the PF. 355401b5383SAlexander Duyck **/ 356401b5383SAlexander Duyck static s32 fm10k_update_uc_addr_pf(struct fm10k_hw *hw, u16 glort, 357401b5383SAlexander Duyck const u8 *mac, u16 vid, bool add, u8 flags) 358401b5383SAlexander Duyck { 359401b5383SAlexander Duyck /* verify MAC address is valid */ 360401b5383SAlexander Duyck if (!is_valid_ether_addr(mac)) 361401b5383SAlexander Duyck return FM10K_ERR_PARAM; 362401b5383SAlexander Duyck 363401b5383SAlexander Duyck return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, flags); 364401b5383SAlexander Duyck } 365401b5383SAlexander Duyck 366401b5383SAlexander Duyck /** 367401b5383SAlexander Duyck * fm10k_update_mc_addr_pf - Update device multicast addresses 368401b5383SAlexander Duyck * @hw: pointer to the HW structure 369401b5383SAlexander Duyck * @glort: base resource tag for this request 370401b5383SAlexander Duyck * @mac: MAC address to add/remove from table 371401b5383SAlexander Duyck * @vid: VLAN ID to add/remove from table 372401b5383SAlexander Duyck * @add: Indicates if this is an add or remove operation 373401b5383SAlexander Duyck * 374401b5383SAlexander Duyck * This function is used to add or remove multicast MAC addresses for 375401b5383SAlexander Duyck * the PF. 376401b5383SAlexander Duyck **/ 377401b5383SAlexander Duyck static s32 fm10k_update_mc_addr_pf(struct fm10k_hw *hw, u16 glort, 378401b5383SAlexander Duyck const u8 *mac, u16 vid, bool add) 379401b5383SAlexander Duyck { 380401b5383SAlexander Duyck /* verify multicast address is valid */ 381401b5383SAlexander Duyck if (!is_multicast_ether_addr(mac)) 382401b5383SAlexander Duyck return FM10K_ERR_PARAM; 383401b5383SAlexander Duyck 384401b5383SAlexander Duyck return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, 0); 385401b5383SAlexander Duyck } 386401b5383SAlexander Duyck 387401b5383SAlexander Duyck /** 388401b5383SAlexander Duyck * fm10k_update_xcast_mode_pf - Request update of multicast mode 389401b5383SAlexander Duyck * @hw: pointer to hardware structure 390401b5383SAlexander Duyck * @glort: base resource tag for this request 391401b5383SAlexander Duyck * @mode: integer value indicating mode being requested 392401b5383SAlexander Duyck * 393401b5383SAlexander Duyck * This function will attempt to request a higher mode for the port 394401b5383SAlexander Duyck * so that it can enable either multicast, multicast promiscuous, or 395401b5383SAlexander Duyck * promiscuous mode of operation. 396401b5383SAlexander Duyck **/ 397401b5383SAlexander Duyck static s32 fm10k_update_xcast_mode_pf(struct fm10k_hw *hw, u16 glort, u8 mode) 398401b5383SAlexander Duyck { 399401b5383SAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx; 400401b5383SAlexander Duyck u32 msg[3], xcast_mode; 401401b5383SAlexander Duyck 402401b5383SAlexander Duyck if (mode > FM10K_XCAST_MODE_NONE) 403401b5383SAlexander Duyck return FM10K_ERR_PARAM; 404401b5383SAlexander Duyck /* if glort is not valid return error */ 405401b5383SAlexander Duyck if (!fm10k_glort_valid_pf(hw, glort)) 406401b5383SAlexander Duyck return FM10K_ERR_PARAM; 407401b5383SAlexander Duyck 408401b5383SAlexander Duyck /* write xcast mode as a single u32 value, 409401b5383SAlexander Duyck * lower 16 bits: glort 410401b5383SAlexander Duyck * upper 16 bits: mode 411401b5383SAlexander Duyck */ 412401b5383SAlexander Duyck xcast_mode = ((u32)mode << 16) | glort; 413401b5383SAlexander Duyck 414401b5383SAlexander Duyck /* generate message requesting to change xcast mode */ 415401b5383SAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_XCAST_MODES); 416401b5383SAlexander Duyck fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_XCAST_MODE, xcast_mode); 417401b5383SAlexander Duyck 418401b5383SAlexander Duyck /* load onto outgoing mailbox */ 419401b5383SAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg); 420401b5383SAlexander Duyck } 421401b5383SAlexander Duyck 422401b5383SAlexander Duyck /** 423401b5383SAlexander Duyck * fm10k_update_int_moderator_pf - Update interrupt moderator linked list 424401b5383SAlexander Duyck * @hw: pointer to hardware structure 425401b5383SAlexander Duyck * 426401b5383SAlexander Duyck * This function walks through the MSI-X vector table to determine the 427401b5383SAlexander Duyck * number of active interrupts and based on that information updates the 428401b5383SAlexander Duyck * interrupt moderator linked list. 429401b5383SAlexander Duyck **/ 430401b5383SAlexander Duyck static void fm10k_update_int_moderator_pf(struct fm10k_hw *hw) 431401b5383SAlexander Duyck { 432401b5383SAlexander Duyck u32 i; 433401b5383SAlexander Duyck 434401b5383SAlexander Duyck /* Disable interrupt moderator */ 435401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_INT_CTRL, 0); 436401b5383SAlexander Duyck 437401b5383SAlexander Duyck /* loop through PF from last to first looking enabled vectors */ 438401b5383SAlexander Duyck for (i = FM10K_ITR_REG_COUNT_PF - 1; i; i--) { 439401b5383SAlexander Duyck if (!fm10k_read_reg(hw, FM10K_MSIX_VECTOR_MASK(i))) 440401b5383SAlexander Duyck break; 441401b5383SAlexander Duyck } 442401b5383SAlexander Duyck 443401b5383SAlexander Duyck /* always reset VFITR2[0] to point to last enabled PF vector*/ 444401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), i); 445401b5383SAlexander Duyck 446401b5383SAlexander Duyck /* reset ITR2[0] to point to last enabled PF vector */ 447401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_ITR2(0), i); 448401b5383SAlexander Duyck 449401b5383SAlexander Duyck /* Enable interrupt moderator */ 450401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); 451401b5383SAlexander Duyck } 452401b5383SAlexander Duyck 453401b5383SAlexander Duyck /** 454401b5383SAlexander Duyck * fm10k_update_lport_state_pf - Notify the switch of a change in port state 455401b5383SAlexander Duyck * @hw: pointer to the HW structure 456401b5383SAlexander Duyck * @glort: base resource tag for this request 457401b5383SAlexander Duyck * @count: number of logical ports being updated 458401b5383SAlexander Duyck * @enable: boolean value indicating enable or disable 459401b5383SAlexander Duyck * 460401b5383SAlexander Duyck * This function is used to add/remove a logical port from the switch. 461401b5383SAlexander Duyck **/ 462401b5383SAlexander Duyck static s32 fm10k_update_lport_state_pf(struct fm10k_hw *hw, u16 glort, 463401b5383SAlexander Duyck u16 count, bool enable) 464401b5383SAlexander Duyck { 465401b5383SAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx; 466401b5383SAlexander Duyck u32 msg[3], lport_msg; 467401b5383SAlexander Duyck 468401b5383SAlexander Duyck /* do nothing if we are being asked to create or destroy 0 ports */ 469401b5383SAlexander Duyck if (!count) 470401b5383SAlexander Duyck return 0; 471401b5383SAlexander Duyck 472401b5383SAlexander Duyck /* if glort is not valid return error */ 473401b5383SAlexander Duyck if (!fm10k_glort_valid_pf(hw, glort)) 474401b5383SAlexander Duyck return FM10K_ERR_PARAM; 475401b5383SAlexander Duyck 476401b5383SAlexander Duyck /* construct the lport message from the 2 pieces of data we have */ 477401b5383SAlexander Duyck lport_msg = ((u32)count << 16) | glort; 478401b5383SAlexander Duyck 479401b5383SAlexander Duyck /* generate lport create/delete message */ 480401b5383SAlexander Duyck fm10k_tlv_msg_init(msg, enable ? FM10K_PF_MSG_ID_LPORT_CREATE : 481401b5383SAlexander Duyck FM10K_PF_MSG_ID_LPORT_DELETE); 482401b5383SAlexander Duyck fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_PORT, lport_msg); 483401b5383SAlexander Duyck 484401b5383SAlexander Duyck /* load onto outgoing mailbox */ 485401b5383SAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg); 486401b5383SAlexander Duyck } 487401b5383SAlexander Duyck 488401b5383SAlexander Duyck /** 489401b5383SAlexander Duyck * fm10k_configure_dglort_map_pf - Configures GLORT entry and queues 490401b5383SAlexander Duyck * @hw: pointer to hardware structure 491401b5383SAlexander Duyck * @dglort: pointer to dglort configuration structure 492401b5383SAlexander Duyck * 493401b5383SAlexander Duyck * Reads the configuration structure contained in dglort_cfg and uses 494401b5383SAlexander Duyck * that information to then populate a DGLORTMAP/DEC entry and the queues 495401b5383SAlexander Duyck * to which it has been assigned. 496401b5383SAlexander Duyck **/ 497401b5383SAlexander Duyck static s32 fm10k_configure_dglort_map_pf(struct fm10k_hw *hw, 498401b5383SAlexander Duyck struct fm10k_dglort_cfg *dglort) 499401b5383SAlexander Duyck { 500401b5383SAlexander Duyck u16 glort, queue_count, vsi_count, pc_count; 501401b5383SAlexander Duyck u16 vsi, queue, pc, q_idx; 502401b5383SAlexander Duyck u32 txqctl, dglortdec, dglortmap; 503401b5383SAlexander Duyck 504401b5383SAlexander Duyck /* verify the dglort pointer */ 505401b5383SAlexander Duyck if (!dglort) 506401b5383SAlexander Duyck return FM10K_ERR_PARAM; 507401b5383SAlexander Duyck 508401b5383SAlexander Duyck /* verify the dglort values */ 509401b5383SAlexander Duyck if ((dglort->idx > 7) || (dglort->rss_l > 7) || (dglort->pc_l > 3) || 510401b5383SAlexander Duyck (dglort->vsi_l > 6) || (dglort->vsi_b > 64) || 511401b5383SAlexander Duyck (dglort->queue_l > 8) || (dglort->queue_b >= 256)) 512401b5383SAlexander Duyck return FM10K_ERR_PARAM; 513401b5383SAlexander Duyck 514401b5383SAlexander Duyck /* determine count of VSIs and queues */ 515401b5383SAlexander Duyck queue_count = 1 << (dglort->rss_l + dglort->pc_l); 516401b5383SAlexander Duyck vsi_count = 1 << (dglort->vsi_l + dglort->queue_l); 517401b5383SAlexander Duyck glort = dglort->glort; 518401b5383SAlexander Duyck q_idx = dglort->queue_b; 519401b5383SAlexander Duyck 520401b5383SAlexander Duyck /* configure SGLORT for queues */ 521401b5383SAlexander Duyck for (vsi = 0; vsi < vsi_count; vsi++, glort++) { 522401b5383SAlexander Duyck for (queue = 0; queue < queue_count; queue++, q_idx++) { 523401b5383SAlexander Duyck if (q_idx >= FM10K_MAX_QUEUES) 524401b5383SAlexander Duyck break; 525401b5383SAlexander Duyck 526401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_TX_SGLORT(q_idx), glort); 527401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_RX_SGLORT(q_idx), glort); 528401b5383SAlexander Duyck } 529401b5383SAlexander Duyck } 530401b5383SAlexander Duyck 531401b5383SAlexander Duyck /* determine count of PCs and queues */ 532401b5383SAlexander Duyck queue_count = 1 << (dglort->queue_l + dglort->rss_l + dglort->vsi_l); 533401b5383SAlexander Duyck pc_count = 1 << dglort->pc_l; 534401b5383SAlexander Duyck 535401b5383SAlexander Duyck /* configure PC for Tx queues */ 536401b5383SAlexander Duyck for (pc = 0; pc < pc_count; pc++) { 537401b5383SAlexander Duyck q_idx = pc + dglort->queue_b; 538401b5383SAlexander Duyck for (queue = 0; queue < queue_count; queue++) { 539401b5383SAlexander Duyck if (q_idx >= FM10K_MAX_QUEUES) 540401b5383SAlexander Duyck break; 541401b5383SAlexander Duyck 542401b5383SAlexander Duyck txqctl = fm10k_read_reg(hw, FM10K_TXQCTL(q_idx)); 543401b5383SAlexander Duyck txqctl &= ~FM10K_TXQCTL_PC_MASK; 544401b5383SAlexander Duyck txqctl |= pc << FM10K_TXQCTL_PC_SHIFT; 545401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_TXQCTL(q_idx), txqctl); 546401b5383SAlexander Duyck 547401b5383SAlexander Duyck q_idx += pc_count; 548401b5383SAlexander Duyck } 549401b5383SAlexander Duyck } 550401b5383SAlexander Duyck 551401b5383SAlexander Duyck /* configure DGLORTDEC */ 552401b5383SAlexander Duyck dglortdec = ((u32)(dglort->rss_l) << FM10K_DGLORTDEC_RSSLENGTH_SHIFT) | 553401b5383SAlexander Duyck ((u32)(dglort->queue_b) << FM10K_DGLORTDEC_QBASE_SHIFT) | 554401b5383SAlexander Duyck ((u32)(dglort->pc_l) << FM10K_DGLORTDEC_PCLENGTH_SHIFT) | 555401b5383SAlexander Duyck ((u32)(dglort->vsi_b) << FM10K_DGLORTDEC_VSIBASE_SHIFT) | 556401b5383SAlexander Duyck ((u32)(dglort->vsi_l) << FM10K_DGLORTDEC_VSILENGTH_SHIFT) | 557401b5383SAlexander Duyck ((u32)(dglort->queue_l)); 558401b5383SAlexander Duyck if (dglort->inner_rss) 559401b5383SAlexander Duyck dglortdec |= FM10K_DGLORTDEC_INNERRSS_ENABLE; 560401b5383SAlexander Duyck 561401b5383SAlexander Duyck /* configure DGLORTMAP */ 562401b5383SAlexander Duyck dglortmap = (dglort->idx == fm10k_dglort_default) ? 563401b5383SAlexander Duyck FM10K_DGLORTMAP_ANY : FM10K_DGLORTMAP_ZERO; 564401b5383SAlexander Duyck dglortmap <<= dglort->vsi_l + dglort->queue_l + dglort->shared_l; 565401b5383SAlexander Duyck dglortmap |= dglort->glort; 566401b5383SAlexander Duyck 567401b5383SAlexander Duyck /* write values to hardware */ 568401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_DGLORTDEC(dglort->idx), dglortdec); 569401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_DGLORTMAP(dglort->idx), dglortmap); 570401b5383SAlexander Duyck 571401b5383SAlexander Duyck return 0; 572401b5383SAlexander Duyck } 573401b5383SAlexander Duyck 574401b5383SAlexander Duyck /** 575b6fec18fSAlexander Duyck * fm10k_update_stats_hw_pf - Updates hardware related statistics of PF 576b6fec18fSAlexander Duyck * @hw: pointer to hardware structure 577b6fec18fSAlexander Duyck * @stats: pointer to the stats structure to update 578b6fec18fSAlexander Duyck * 579b6fec18fSAlexander Duyck * This function collects and aggregates global and per queue hardware 580b6fec18fSAlexander Duyck * statistics. 581b6fec18fSAlexander Duyck **/ 582b6fec18fSAlexander Duyck static void fm10k_update_hw_stats_pf(struct fm10k_hw *hw, 583b6fec18fSAlexander Duyck struct fm10k_hw_stats *stats) 584b6fec18fSAlexander Duyck { 585b6fec18fSAlexander Duyck u32 timeout, ur, ca, um, xec, vlan_drop, loopback_drop, nodesc_drop; 586b6fec18fSAlexander Duyck u32 id, id_prev; 587b6fec18fSAlexander Duyck 588b6fec18fSAlexander Duyck /* Use Tx queue 0 as a canary to detect a reset */ 589b6fec18fSAlexander Duyck id = fm10k_read_reg(hw, FM10K_TXQCTL(0)); 590b6fec18fSAlexander Duyck 591b6fec18fSAlexander Duyck /* Read Global Statistics */ 592b6fec18fSAlexander Duyck do { 593b6fec18fSAlexander Duyck timeout = fm10k_read_hw_stats_32b(hw, FM10K_STATS_TIMEOUT, 594b6fec18fSAlexander Duyck &stats->timeout); 595b6fec18fSAlexander Duyck ur = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UR, &stats->ur); 596b6fec18fSAlexander Duyck ca = fm10k_read_hw_stats_32b(hw, FM10K_STATS_CA, &stats->ca); 597b6fec18fSAlexander Duyck um = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UM, &stats->um); 598b6fec18fSAlexander Duyck xec = fm10k_read_hw_stats_32b(hw, FM10K_STATS_XEC, &stats->xec); 599b6fec18fSAlexander Duyck vlan_drop = fm10k_read_hw_stats_32b(hw, FM10K_STATS_VLAN_DROP, 600b6fec18fSAlexander Duyck &stats->vlan_drop); 601b6fec18fSAlexander Duyck loopback_drop = fm10k_read_hw_stats_32b(hw, 602b6fec18fSAlexander Duyck FM10K_STATS_LOOPBACK_DROP, 603b6fec18fSAlexander Duyck &stats->loopback_drop); 604b6fec18fSAlexander Duyck nodesc_drop = fm10k_read_hw_stats_32b(hw, 605b6fec18fSAlexander Duyck FM10K_STATS_NODESC_DROP, 606b6fec18fSAlexander Duyck &stats->nodesc_drop); 607b6fec18fSAlexander Duyck 608b6fec18fSAlexander Duyck /* if value has not changed then we have consistent data */ 609b6fec18fSAlexander Duyck id_prev = id; 610b6fec18fSAlexander Duyck id = fm10k_read_reg(hw, FM10K_TXQCTL(0)); 611b6fec18fSAlexander Duyck } while ((id ^ id_prev) & FM10K_TXQCTL_ID_MASK); 612b6fec18fSAlexander Duyck 613b6fec18fSAlexander Duyck /* drop non-ID bits and set VALID ID bit */ 614b6fec18fSAlexander Duyck id &= FM10K_TXQCTL_ID_MASK; 615b6fec18fSAlexander Duyck id |= FM10K_STAT_VALID; 616b6fec18fSAlexander Duyck 617b6fec18fSAlexander Duyck /* Update Global Statistics */ 618b6fec18fSAlexander Duyck if (stats->stats_idx == id) { 619b6fec18fSAlexander Duyck stats->timeout.count += timeout; 620b6fec18fSAlexander Duyck stats->ur.count += ur; 621b6fec18fSAlexander Duyck stats->ca.count += ca; 622b6fec18fSAlexander Duyck stats->um.count += um; 623b6fec18fSAlexander Duyck stats->xec.count += xec; 624b6fec18fSAlexander Duyck stats->vlan_drop.count += vlan_drop; 625b6fec18fSAlexander Duyck stats->loopback_drop.count += loopback_drop; 626b6fec18fSAlexander Duyck stats->nodesc_drop.count += nodesc_drop; 627b6fec18fSAlexander Duyck } 628b6fec18fSAlexander Duyck 629b6fec18fSAlexander Duyck /* Update bases and record current PF id */ 630b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->timeout, timeout); 631b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->ur, ur); 632b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->ca, ca); 633b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->um, um); 634b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->xec, xec); 635b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->vlan_drop, vlan_drop); 636b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->loopback_drop, loopback_drop); 637b6fec18fSAlexander Duyck fm10k_update_hw_base_32b(&stats->nodesc_drop, nodesc_drop); 638b6fec18fSAlexander Duyck stats->stats_idx = id; 639b6fec18fSAlexander Duyck 640b6fec18fSAlexander Duyck /* Update Queue Statistics */ 641b6fec18fSAlexander Duyck fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); 642b6fec18fSAlexander Duyck } 643b6fec18fSAlexander Duyck 644b6fec18fSAlexander Duyck /** 645b6fec18fSAlexander Duyck * fm10k_rebind_hw_stats_pf - Resets base for hardware statistics of PF 646b6fec18fSAlexander Duyck * @hw: pointer to hardware structure 647b6fec18fSAlexander Duyck * @stats: pointer to the stats structure to update 648b6fec18fSAlexander Duyck * 649b6fec18fSAlexander Duyck * This function resets the base for global and per queue hardware 650b6fec18fSAlexander Duyck * statistics. 651b6fec18fSAlexander Duyck **/ 652b6fec18fSAlexander Duyck static void fm10k_rebind_hw_stats_pf(struct fm10k_hw *hw, 653b6fec18fSAlexander Duyck struct fm10k_hw_stats *stats) 654b6fec18fSAlexander Duyck { 655b6fec18fSAlexander Duyck /* Unbind Global Statistics */ 656b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->timeout); 657b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->ur); 658b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->ca); 659b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->um); 660b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->xec); 661b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->vlan_drop); 662b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->loopback_drop); 663b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_32b(&stats->nodesc_drop); 664b6fec18fSAlexander Duyck 665b6fec18fSAlexander Duyck /* Unbind Queue Statistics */ 666b6fec18fSAlexander Duyck fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); 667b6fec18fSAlexander Duyck 668b6fec18fSAlexander Duyck /* Reinitialize bases for all stats */ 669b6fec18fSAlexander Duyck fm10k_update_hw_stats_pf(hw, stats); 670b6fec18fSAlexander Duyck } 671b6fec18fSAlexander Duyck 672b6fec18fSAlexander Duyck /** 673401b5383SAlexander Duyck * fm10k_set_dma_mask_pf - Configures PhyAddrSpace to limit DMA to system 674401b5383SAlexander Duyck * @hw: pointer to hardware structure 675401b5383SAlexander Duyck * @dma_mask: 64 bit DMA mask required for platform 676401b5383SAlexander Duyck * 677401b5383SAlexander Duyck * This function sets the PHYADDR.PhyAddrSpace bits for the endpoint in order 678401b5383SAlexander Duyck * to limit the access to memory beyond what is physically in the system. 679401b5383SAlexander Duyck **/ 680401b5383SAlexander Duyck static void fm10k_set_dma_mask_pf(struct fm10k_hw *hw, u64 dma_mask) 681401b5383SAlexander Duyck { 682401b5383SAlexander Duyck /* we need to write the upper 32 bits of DMA mask to PhyAddrSpace */ 683401b5383SAlexander Duyck u32 phyaddr = (u32)(dma_mask >> 32); 684401b5383SAlexander Duyck 685401b5383SAlexander Duyck fm10k_write_reg(hw, FM10K_PHYADDR, phyaddr); 686401b5383SAlexander Duyck } 687401b5383SAlexander Duyck 688401b5383SAlexander Duyck /** 689b6fec18fSAlexander Duyck * fm10k_get_fault_pf - Record a fault in one of the interface units 690b6fec18fSAlexander Duyck * @hw: pointer to hardware structure 691b6fec18fSAlexander Duyck * @type: pointer to fault type register offset 692b6fec18fSAlexander Duyck * @fault: pointer to memory location to record the fault 693b6fec18fSAlexander Duyck * 694b6fec18fSAlexander Duyck * Record the fault register contents to the fault data structure and 695b6fec18fSAlexander Duyck * clear the entry from the register. 696b6fec18fSAlexander Duyck * 697b6fec18fSAlexander Duyck * Returns ERR_PARAM if invalid register is specified or no error is present. 698b6fec18fSAlexander Duyck **/ 699b6fec18fSAlexander Duyck static s32 fm10k_get_fault_pf(struct fm10k_hw *hw, int type, 700b6fec18fSAlexander Duyck struct fm10k_fault *fault) 701b6fec18fSAlexander Duyck { 702b6fec18fSAlexander Duyck u32 func; 703b6fec18fSAlexander Duyck 704b6fec18fSAlexander Duyck /* verify the fault register is in range and is aligned */ 705b6fec18fSAlexander Duyck switch (type) { 706b6fec18fSAlexander Duyck case FM10K_PCA_FAULT: 707b6fec18fSAlexander Duyck case FM10K_THI_FAULT: 708b6fec18fSAlexander Duyck case FM10K_FUM_FAULT: 709b6fec18fSAlexander Duyck break; 710b6fec18fSAlexander Duyck default: 711b6fec18fSAlexander Duyck return FM10K_ERR_PARAM; 712b6fec18fSAlexander Duyck } 713b6fec18fSAlexander Duyck 714b6fec18fSAlexander Duyck /* only service faults that are valid */ 715b6fec18fSAlexander Duyck func = fm10k_read_reg(hw, type + FM10K_FAULT_FUNC); 716b6fec18fSAlexander Duyck if (!(func & FM10K_FAULT_FUNC_VALID)) 717b6fec18fSAlexander Duyck return FM10K_ERR_PARAM; 718b6fec18fSAlexander Duyck 719b6fec18fSAlexander Duyck /* read remaining fields */ 720b6fec18fSAlexander Duyck fault->address = fm10k_read_reg(hw, type + FM10K_FAULT_ADDR_HI); 721b6fec18fSAlexander Duyck fault->address <<= 32; 722b6fec18fSAlexander Duyck fault->address = fm10k_read_reg(hw, type + FM10K_FAULT_ADDR_LO); 723b6fec18fSAlexander Duyck fault->specinfo = fm10k_read_reg(hw, type + FM10K_FAULT_SPECINFO); 724b6fec18fSAlexander Duyck 725b6fec18fSAlexander Duyck /* clear valid bit to allow for next error */ 726b6fec18fSAlexander Duyck fm10k_write_reg(hw, type + FM10K_FAULT_FUNC, FM10K_FAULT_FUNC_VALID); 727b6fec18fSAlexander Duyck 728b6fec18fSAlexander Duyck /* Record which function triggered the error */ 729b6fec18fSAlexander Duyck if (func & FM10K_FAULT_FUNC_PF) 730b6fec18fSAlexander Duyck fault->func = 0; 731b6fec18fSAlexander Duyck else 732b6fec18fSAlexander Duyck fault->func = 1 + ((func & FM10K_FAULT_FUNC_VF_MASK) >> 733b6fec18fSAlexander Duyck FM10K_FAULT_FUNC_VF_SHIFT); 734b6fec18fSAlexander Duyck 735b6fec18fSAlexander Duyck /* record fault type */ 736b6fec18fSAlexander Duyck fault->type = func & FM10K_FAULT_FUNC_TYPE_MASK; 737b6fec18fSAlexander Duyck 738b6fec18fSAlexander Duyck return 0; 739b6fec18fSAlexander Duyck } 740b6fec18fSAlexander Duyck 741401b5383SAlexander Duyck /** 742401b5383SAlexander Duyck * fm10k_request_lport_map_pf - Request LPORT map from the switch API 743401b5383SAlexander Duyck * @hw: pointer to hardware structure 744401b5383SAlexander Duyck * 745401b5383SAlexander Duyck **/ 746401b5383SAlexander Duyck static s32 fm10k_request_lport_map_pf(struct fm10k_hw *hw) 747401b5383SAlexander Duyck { 748401b5383SAlexander Duyck struct fm10k_mbx_info *mbx = &hw->mbx; 749401b5383SAlexander Duyck u32 msg[1]; 750401b5383SAlexander Duyck 751401b5383SAlexander Duyck /* issue request asking for LPORT map */ 752401b5383SAlexander Duyck fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_LPORT_MAP); 753401b5383SAlexander Duyck 754401b5383SAlexander Duyck /* load onto outgoing mailbox */ 755401b5383SAlexander Duyck return mbx->ops.enqueue_tx(hw, mbx, msg); 756401b5383SAlexander Duyck } 757401b5383SAlexander Duyck 758401b5383SAlexander Duyck /** 759401b5383SAlexander Duyck * fm10k_get_host_state_pf - Returns the state of the switch and mailbox 760401b5383SAlexander Duyck * @hw: pointer to hardware structure 761401b5383SAlexander Duyck * @switch_ready: pointer to boolean value that will record switch state 762401b5383SAlexander Duyck * 763401b5383SAlexander Duyck * This funciton will check the DMA_CTRL2 register and mailbox in order 764401b5383SAlexander Duyck * to determine if the switch is ready for the PF to begin requesting 765401b5383SAlexander Duyck * addresses and mapping traffic to the local interface. 766401b5383SAlexander Duyck **/ 767401b5383SAlexander Duyck static s32 fm10k_get_host_state_pf(struct fm10k_hw *hw, bool *switch_ready) 768401b5383SAlexander Duyck { 769401b5383SAlexander Duyck s32 ret_val = 0; 770401b5383SAlexander Duyck u32 dma_ctrl2; 771401b5383SAlexander Duyck 772401b5383SAlexander Duyck /* verify the switch is ready for interraction */ 773401b5383SAlexander Duyck dma_ctrl2 = fm10k_read_reg(hw, FM10K_DMA_CTRL2); 774401b5383SAlexander Duyck if (!(dma_ctrl2 & FM10K_DMA_CTRL2_SWITCH_READY)) 775401b5383SAlexander Duyck goto out; 776401b5383SAlexander Duyck 777401b5383SAlexander Duyck /* retrieve generic host state info */ 778401b5383SAlexander Duyck ret_val = fm10k_get_host_state_generic(hw, switch_ready); 779401b5383SAlexander Duyck if (ret_val) 780401b5383SAlexander Duyck goto out; 781401b5383SAlexander Duyck 782401b5383SAlexander Duyck /* interface cannot receive traffic without logical ports */ 783401b5383SAlexander Duyck if (hw->mac.dglort_map == FM10K_DGLORTMAP_NONE) 784401b5383SAlexander Duyck ret_val = fm10k_request_lport_map_pf(hw); 785401b5383SAlexander Duyck 786401b5383SAlexander Duyck out: 787401b5383SAlexander Duyck return ret_val; 788401b5383SAlexander Duyck } 789401b5383SAlexander Duyck 790401b5383SAlexander Duyck /* This structure defines the attibutes to be parsed below */ 791401b5383SAlexander Duyck const struct fm10k_tlv_attr fm10k_lport_map_msg_attr[] = { 792401b5383SAlexander Duyck FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_LPORT_MAP), 793401b5383SAlexander Duyck FM10K_TLV_ATTR_LAST 794401b5383SAlexander Duyck }; 795401b5383SAlexander Duyck 796401b5383SAlexander Duyck /** 797401b5383SAlexander Duyck * fm10k_msg_lport_map_pf - Message handler for lport_map message from SM 798401b5383SAlexander Duyck * @hw: Pointer to hardware structure 799401b5383SAlexander Duyck * @results: pointer array containing parsed data 800401b5383SAlexander Duyck * @mbx: Pointer to mailbox information structure 801401b5383SAlexander Duyck * 802401b5383SAlexander Duyck * This handler configures the lport mapping based on the reply from the 803401b5383SAlexander Duyck * switch API. 804401b5383SAlexander Duyck **/ 805401b5383SAlexander Duyck s32 fm10k_msg_lport_map_pf(struct fm10k_hw *hw, u32 **results, 806401b5383SAlexander Duyck struct fm10k_mbx_info *mbx) 807401b5383SAlexander Duyck { 808401b5383SAlexander Duyck u16 glort, mask; 809401b5383SAlexander Duyck u32 dglort_map; 810401b5383SAlexander Duyck s32 err; 811401b5383SAlexander Duyck 812401b5383SAlexander Duyck err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_LPORT_MAP], 813401b5383SAlexander Duyck &dglort_map); 814401b5383SAlexander Duyck if (err) 815401b5383SAlexander Duyck return err; 816401b5383SAlexander Duyck 817401b5383SAlexander Duyck /* extract values out of the header */ 818401b5383SAlexander Duyck glort = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_GLORT); 819401b5383SAlexander Duyck mask = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_MASK); 820401b5383SAlexander Duyck 821401b5383SAlexander Duyck /* verify mask is set and none of the masked bits in glort are set */ 822401b5383SAlexander Duyck if (!mask || (glort & ~mask)) 823401b5383SAlexander Duyck return FM10K_ERR_PARAM; 824401b5383SAlexander Duyck 825401b5383SAlexander Duyck /* verify the mask is contiguous, and that it is 1's followed by 0's */ 826401b5383SAlexander Duyck if (((~(mask - 1) & mask) + mask) & FM10K_DGLORTMAP_NONE) 827401b5383SAlexander Duyck return FM10K_ERR_PARAM; 828401b5383SAlexander Duyck 829401b5383SAlexander Duyck /* record the glort, mask, and port count */ 830401b5383SAlexander Duyck hw->mac.dglort_map = dglort_map; 831401b5383SAlexander Duyck 832401b5383SAlexander Duyck return 0; 833401b5383SAlexander Duyck } 834401b5383SAlexander Duyck 835401b5383SAlexander Duyck const struct fm10k_tlv_attr fm10k_update_pvid_msg_attr[] = { 836401b5383SAlexander Duyck FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_UPDATE_PVID), 837401b5383SAlexander Duyck FM10K_TLV_ATTR_LAST 838401b5383SAlexander Duyck }; 839401b5383SAlexander Duyck 840401b5383SAlexander Duyck /** 841401b5383SAlexander Duyck * fm10k_msg_update_pvid_pf - Message handler for port VLAN message from SM 842401b5383SAlexander Duyck * @hw: Pointer to hardware structure 843401b5383SAlexander Duyck * @results: pointer array containing parsed data 844401b5383SAlexander Duyck * @mbx: Pointer to mailbox information structure 845401b5383SAlexander Duyck * 846401b5383SAlexander Duyck * This handler configures the default VLAN for the PF 847401b5383SAlexander Duyck **/ 848401b5383SAlexander Duyck s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *hw, u32 **results, 849401b5383SAlexander Duyck struct fm10k_mbx_info *mbx) 850401b5383SAlexander Duyck { 851401b5383SAlexander Duyck u16 glort, pvid; 852401b5383SAlexander Duyck u32 pvid_update; 853401b5383SAlexander Duyck s32 err; 854401b5383SAlexander Duyck 855401b5383SAlexander Duyck err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_UPDATE_PVID], 856401b5383SAlexander Duyck &pvid_update); 857401b5383SAlexander Duyck if (err) 858401b5383SAlexander Duyck return err; 859401b5383SAlexander Duyck 860401b5383SAlexander Duyck /* extract values from the pvid update */ 861401b5383SAlexander Duyck glort = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_GLORT); 862401b5383SAlexander Duyck pvid = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_PVID); 863401b5383SAlexander Duyck 864401b5383SAlexander Duyck /* if glort is not valid return error */ 865401b5383SAlexander Duyck if (!fm10k_glort_valid_pf(hw, glort)) 866401b5383SAlexander Duyck return FM10K_ERR_PARAM; 867401b5383SAlexander Duyck 868401b5383SAlexander Duyck /* verify VID is valid */ 869401b5383SAlexander Duyck if (pvid >= FM10K_VLAN_TABLE_VID_MAX) 870401b5383SAlexander Duyck return FM10K_ERR_PARAM; 871401b5383SAlexander Duyck 872401b5383SAlexander Duyck /* record the port VLAN ID value */ 873401b5383SAlexander Duyck hw->mac.default_vid = pvid; 874401b5383SAlexander Duyck 875401b5383SAlexander Duyck return 0; 876401b5383SAlexander Duyck } 877401b5383SAlexander Duyck 878401b5383SAlexander Duyck /** 879401b5383SAlexander Duyck * fm10k_record_global_table_data - Move global table data to swapi table info 880401b5383SAlexander Duyck * @from: pointer to source table data structure 881401b5383SAlexander Duyck * @to: pointer to destination table info structure 882401b5383SAlexander Duyck * 883401b5383SAlexander Duyck * This function is will copy table_data to the table_info contained in 884401b5383SAlexander Duyck * the hw struct. 885401b5383SAlexander Duyck **/ 886401b5383SAlexander Duyck static void fm10k_record_global_table_data(struct fm10k_global_table_data *from, 887401b5383SAlexander Duyck struct fm10k_swapi_table_info *to) 888401b5383SAlexander Duyck { 889401b5383SAlexander Duyck /* convert from le32 struct to CPU byte ordered values */ 890401b5383SAlexander Duyck to->used = le32_to_cpu(from->used); 891401b5383SAlexander Duyck to->avail = le32_to_cpu(from->avail); 892401b5383SAlexander Duyck } 893401b5383SAlexander Duyck 894401b5383SAlexander Duyck const struct fm10k_tlv_attr fm10k_err_msg_attr[] = { 895401b5383SAlexander Duyck FM10K_TLV_ATTR_LE_STRUCT(FM10K_PF_ATTR_ID_ERR, 896401b5383SAlexander Duyck sizeof(struct fm10k_swapi_error)), 897401b5383SAlexander Duyck FM10K_TLV_ATTR_LAST 898401b5383SAlexander Duyck }; 899401b5383SAlexander Duyck 900401b5383SAlexander Duyck /** 901401b5383SAlexander Duyck * fm10k_msg_err_pf - Message handler for error reply 902401b5383SAlexander Duyck * @hw: Pointer to hardware structure 903401b5383SAlexander Duyck * @results: pointer array containing parsed data 904401b5383SAlexander Duyck * @mbx: Pointer to mailbox information structure 905401b5383SAlexander Duyck * 906401b5383SAlexander Duyck * This handler will capture the data for any error replies to previous 907401b5383SAlexander Duyck * messages that the PF has sent. 908401b5383SAlexander Duyck **/ 909401b5383SAlexander Duyck s32 fm10k_msg_err_pf(struct fm10k_hw *hw, u32 **results, 910401b5383SAlexander Duyck struct fm10k_mbx_info *mbx) 911401b5383SAlexander Duyck { 912401b5383SAlexander Duyck struct fm10k_swapi_error err_msg; 913401b5383SAlexander Duyck s32 err; 914401b5383SAlexander Duyck 915401b5383SAlexander Duyck /* extract structure from message */ 916401b5383SAlexander Duyck err = fm10k_tlv_attr_get_le_struct(results[FM10K_PF_ATTR_ID_ERR], 917401b5383SAlexander Duyck &err_msg, sizeof(err_msg)); 918401b5383SAlexander Duyck if (err) 919401b5383SAlexander Duyck return err; 920401b5383SAlexander Duyck 921401b5383SAlexander Duyck /* record table status */ 922401b5383SAlexander Duyck fm10k_record_global_table_data(&err_msg.mac, &hw->swapi.mac); 923401b5383SAlexander Duyck fm10k_record_global_table_data(&err_msg.nexthop, &hw->swapi.nexthop); 924401b5383SAlexander Duyck fm10k_record_global_table_data(&err_msg.ffu, &hw->swapi.ffu); 925401b5383SAlexander Duyck 926401b5383SAlexander Duyck /* record SW API status value */ 927401b5383SAlexander Duyck hw->swapi.status = le32_to_cpu(err_msg.status); 928401b5383SAlexander Duyck 929401b5383SAlexander Duyck return 0; 930401b5383SAlexander Duyck } 931401b5383SAlexander Duyck 932401b5383SAlexander Duyck static const struct fm10k_msg_data fm10k_msg_data_pf[] = { 933401b5383SAlexander Duyck FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf), 934401b5383SAlexander Duyck FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf), 935401b5383SAlexander Duyck FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_msg_lport_map_pf), 936401b5383SAlexander Duyck FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf), 937401b5383SAlexander Duyck FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf), 938401b5383SAlexander Duyck FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_msg_update_pvid_pf), 939401b5383SAlexander Duyck FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), 940401b5383SAlexander Duyck }; 941401b5383SAlexander Duyck 942b6fec18fSAlexander Duyck static struct fm10k_mac_ops mac_ops_pf = { 943b6fec18fSAlexander Duyck .get_bus_info = &fm10k_get_bus_info_generic, 944b6fec18fSAlexander Duyck .reset_hw = &fm10k_reset_hw_pf, 945b6fec18fSAlexander Duyck .init_hw = &fm10k_init_hw_pf, 946b6fec18fSAlexander Duyck .start_hw = &fm10k_start_hw_generic, 947b6fec18fSAlexander Duyck .stop_hw = &fm10k_stop_hw_generic, 948b6fec18fSAlexander Duyck .is_slot_appropriate = &fm10k_is_slot_appropriate_pf, 949401b5383SAlexander Duyck .update_vlan = &fm10k_update_vlan_pf, 950b6fec18fSAlexander Duyck .read_mac_addr = &fm10k_read_mac_addr_pf, 951401b5383SAlexander Duyck .update_uc_addr = &fm10k_update_uc_addr_pf, 952401b5383SAlexander Duyck .update_mc_addr = &fm10k_update_mc_addr_pf, 953401b5383SAlexander Duyck .update_xcast_mode = &fm10k_update_xcast_mode_pf, 954401b5383SAlexander Duyck .update_int_moderator = &fm10k_update_int_moderator_pf, 955401b5383SAlexander Duyck .update_lport_state = &fm10k_update_lport_state_pf, 956b6fec18fSAlexander Duyck .update_hw_stats = &fm10k_update_hw_stats_pf, 957b6fec18fSAlexander Duyck .rebind_hw_stats = &fm10k_rebind_hw_stats_pf, 958401b5383SAlexander Duyck .configure_dglort_map = &fm10k_configure_dglort_map_pf, 959401b5383SAlexander Duyck .set_dma_mask = &fm10k_set_dma_mask_pf, 960b6fec18fSAlexander Duyck .get_fault = &fm10k_get_fault_pf, 961401b5383SAlexander Duyck .get_host_state = &fm10k_get_host_state_pf, 962b6fec18fSAlexander Duyck }; 963b6fec18fSAlexander Duyck 964401b5383SAlexander Duyck static s32 fm10k_get_invariants_pf(struct fm10k_hw *hw) 965401b5383SAlexander Duyck { 966401b5383SAlexander Duyck fm10k_get_invariants_generic(hw); 967401b5383SAlexander Duyck 968401b5383SAlexander Duyck return fm10k_sm_mbx_init(hw, &hw->mbx, fm10k_msg_data_pf); 969401b5383SAlexander Duyck } 970401b5383SAlexander Duyck 971b6fec18fSAlexander Duyck struct fm10k_info fm10k_pf_info = { 972b6fec18fSAlexander Duyck .mac = fm10k_mac_pf, 973401b5383SAlexander Duyck .get_invariants = &fm10k_get_invariants_pf, 974b6fec18fSAlexander Duyck .mac_ops = &mac_ops_pf, 975b6fec18fSAlexander Duyck }; 976