1ca853deeSEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */ 2*e53a21abSEric Joyner /* Copyright (c) 2024, Intel Corporation 3ca853deeSEric Joyner * All rights reserved. 4ca853deeSEric Joyner * 5ca853deeSEric Joyner * Redistribution and use in source and binary forms, with or without 6ca853deeSEric Joyner * modification, are permitted provided that the following conditions are met: 7ca853deeSEric Joyner * 8ca853deeSEric Joyner * 1. Redistributions of source code must retain the above copyright notice, 9ca853deeSEric Joyner * this list of conditions and the following disclaimer. 10ca853deeSEric Joyner * 11ca853deeSEric Joyner * 2. Redistributions in binary form must reproduce the above copyright 12ca853deeSEric Joyner * notice, this list of conditions and the following disclaimer in the 13ca853deeSEric Joyner * documentation and/or other materials provided with the distribution. 14ca853deeSEric Joyner * 15ca853deeSEric Joyner * 3. Neither the name of the Intel Corporation nor the names of its 16ca853deeSEric Joyner * contributors may be used to endorse or promote products derived from 17ca853deeSEric Joyner * this software without specific prior written permission. 18ca853deeSEric Joyner * 19ca853deeSEric Joyner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20ca853deeSEric Joyner * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21ca853deeSEric Joyner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22ca853deeSEric Joyner * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23ca853deeSEric Joyner * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24ca853deeSEric Joyner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25ca853deeSEric Joyner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26ca853deeSEric Joyner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27ca853deeSEric Joyner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28ca853deeSEric Joyner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29ca853deeSEric Joyner * POSSIBILITY OF SUCH DAMAGE. 30ca853deeSEric Joyner */ 31ca853deeSEric Joyner 32ca853deeSEric Joyner /** 33ca853deeSEric Joyner * @file iavf_lib.c 34ca853deeSEric Joyner * @brief library code common to both legacy and iflib 35ca853deeSEric Joyner * 36ca853deeSEric Joyner * Contains functions common to the iflib and legacy drivers. Includes 37ca853deeSEric Joyner * hardware initialization and control functions, as well as sysctl handlers 38ca853deeSEric Joyner * for the sysctls which are shared between the legacy and iflib drivers. 39ca853deeSEric Joyner */ 40ca853deeSEric Joyner #include "iavf_iflib.h" 41ca853deeSEric Joyner #include "iavf_vc_common.h" 42ca853deeSEric Joyner 43ca853deeSEric Joyner static void iavf_init_hw(struct iavf_hw *hw, device_t dev); 44ca853deeSEric Joyner static u_int iavf_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int cnt); 45ca853deeSEric Joyner 46ca853deeSEric Joyner /** 47ca853deeSEric Joyner * iavf_msec_pause - Pause for at least the specified number of milliseconds 48ca853deeSEric Joyner * @msecs: number of milliseconds to pause for 49ca853deeSEric Joyner * 50ca853deeSEric Joyner * Pause execution of the current thread for a specified number of 51ca853deeSEric Joyner * milliseconds. Used to enforce minimum delay times when waiting for various 52ca853deeSEric Joyner * hardware events. 53ca853deeSEric Joyner */ 54ca853deeSEric Joyner void 55ca853deeSEric Joyner iavf_msec_pause(int msecs) 56ca853deeSEric Joyner { 57ca853deeSEric Joyner pause("iavf_msec_pause", MSEC_2_TICKS(msecs)); 58ca853deeSEric Joyner } 59ca853deeSEric Joyner 60ca853deeSEric Joyner /** 61ca853deeSEric Joyner * iavf_get_default_rss_key - Get the default RSS key for this driver 62ca853deeSEric Joyner * @key: output parameter to store the key in 63ca853deeSEric Joyner * 64ca853deeSEric Joyner * Copies the driver's default RSS key into the provided key variable. 65ca853deeSEric Joyner * 66ca853deeSEric Joyner * @pre assumes that key is not NULL and has at least IAVF_RSS_KEY_SIZE 67ca853deeSEric Joyner * storage space. 68ca853deeSEric Joyner */ 69ca853deeSEric Joyner void 70ca853deeSEric Joyner iavf_get_default_rss_key(u32 *key) 71ca853deeSEric Joyner { 72ca853deeSEric Joyner MPASS(key != NULL); 73ca853deeSEric Joyner 74ca853deeSEric Joyner u32 rss_seed[IAVF_RSS_KEY_SIZE_REG] = {0x41b01687, 75ca853deeSEric Joyner 0x183cfd8c, 0xce880440, 0x580cbc3c, 76ca853deeSEric Joyner 0x35897377, 0x328b25e1, 0x4fa98922, 77ca853deeSEric Joyner 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1, 78ca853deeSEric Joyner 0x0, 0x0, 0x0}; 79ca853deeSEric Joyner 80ca853deeSEric Joyner bcopy(rss_seed, key, IAVF_RSS_KEY_SIZE); 81ca853deeSEric Joyner } 82ca853deeSEric Joyner 83ca853deeSEric Joyner /** 84ca853deeSEric Joyner * iavf_allocate_pci_resources_common - Allocate PCI resources 85ca853deeSEric Joyner * @sc: the private device softc pointer 86ca853deeSEric Joyner * 87ca853deeSEric Joyner * @pre sc->dev is set 88ca853deeSEric Joyner * 89ca853deeSEric Joyner * Allocates the common PCI resources used by the driver. 90ca853deeSEric Joyner * 91ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 92ca853deeSEric Joyner */ 93ca853deeSEric Joyner int 94ca853deeSEric Joyner iavf_allocate_pci_resources_common(struct iavf_sc *sc) 95ca853deeSEric Joyner { 96ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 97ca853deeSEric Joyner device_t dev = sc->dev; 98ca853deeSEric Joyner int rid; 99ca853deeSEric Joyner 100ca853deeSEric Joyner /* Map PCI BAR0 */ 101ca853deeSEric Joyner rid = PCIR_BAR(0); 102ca853deeSEric Joyner sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 103ca853deeSEric Joyner &rid, RF_ACTIVE); 104ca853deeSEric Joyner 105ca853deeSEric Joyner if (!(sc->pci_mem)) { 106ca853deeSEric Joyner device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); 107ca853deeSEric Joyner return (ENXIO); 108ca853deeSEric Joyner } 109ca853deeSEric Joyner 110ca853deeSEric Joyner iavf_init_hw(hw, dev); 111ca853deeSEric Joyner 112ca853deeSEric Joyner /* Save off register access information */ 113ca853deeSEric Joyner sc->osdep.mem_bus_space_tag = 114ca853deeSEric Joyner rman_get_bustag(sc->pci_mem); 115ca853deeSEric Joyner sc->osdep.mem_bus_space_handle = 116ca853deeSEric Joyner rman_get_bushandle(sc->pci_mem); 117ca853deeSEric Joyner sc->osdep.mem_bus_space_size = rman_get_size(sc->pci_mem); 118ca853deeSEric Joyner sc->osdep.flush_reg = IAVF_VFGEN_RSTAT; 119ca853deeSEric Joyner sc->osdep.dev = dev; 120ca853deeSEric Joyner 121ca853deeSEric Joyner sc->hw.hw_addr = (u8 *)&sc->osdep.mem_bus_space_handle; 122ca853deeSEric Joyner sc->hw.back = &sc->osdep; 123ca853deeSEric Joyner 124ca853deeSEric Joyner return (0); 125ca853deeSEric Joyner } 126ca853deeSEric Joyner 127ca853deeSEric Joyner /** 128ca853deeSEric Joyner * iavf_init_hw - Initialize the device HW 129ca853deeSEric Joyner * @hw: device hardware structure 130ca853deeSEric Joyner * @dev: the stack device_t pointer 131ca853deeSEric Joyner * 132ca853deeSEric Joyner * Attach helper function. Gathers information about the (virtual) hardware 133ca853deeSEric Joyner * for use elsewhere in the driver. 134ca853deeSEric Joyner */ 135ca853deeSEric Joyner static void 136ca853deeSEric Joyner iavf_init_hw(struct iavf_hw *hw, device_t dev) 137ca853deeSEric Joyner { 138ca853deeSEric Joyner /* Save off the information about this board */ 139ca853deeSEric Joyner hw->vendor_id = pci_get_vendor(dev); 140ca853deeSEric Joyner hw->device_id = pci_get_device(dev); 141ca853deeSEric Joyner hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 142ca853deeSEric Joyner hw->subsystem_vendor_id = 143ca853deeSEric Joyner pci_read_config(dev, PCIR_SUBVEND_0, 2); 144ca853deeSEric Joyner hw->subsystem_device_id = 145ca853deeSEric Joyner pci_read_config(dev, PCIR_SUBDEV_0, 2); 146ca853deeSEric Joyner 147ca853deeSEric Joyner hw->bus.device = pci_get_slot(dev); 148ca853deeSEric Joyner hw->bus.func = pci_get_function(dev); 149ca853deeSEric Joyner } 150ca853deeSEric Joyner 151ca853deeSEric Joyner /** 152ca853deeSEric Joyner * iavf_sysctl_current_speed - Sysctl to display the current device speed 153ca853deeSEric Joyner * @oidp: syctl oid pointer 154ca853deeSEric Joyner * @arg1: pointer to the device softc typecasted to void * 155ca853deeSEric Joyner * @arg2: unused sysctl argument 156ca853deeSEric Joyner * @req: sysctl request structure 157ca853deeSEric Joyner * 158ca853deeSEric Joyner * Reads the current speed reported from the physical device into a string for 159ca853deeSEric Joyner * display by the current_speed sysctl. 160ca853deeSEric Joyner * 161ca853deeSEric Joyner * @returns zero or an error code on failure. 162ca853deeSEric Joyner */ 163ca853deeSEric Joyner int 164ca853deeSEric Joyner iavf_sysctl_current_speed(SYSCTL_HANDLER_ARGS) 165ca853deeSEric Joyner { 166ca853deeSEric Joyner struct iavf_sc *sc = (struct iavf_sc *)arg1; 167ca853deeSEric Joyner int error = 0; 168ca853deeSEric Joyner 169ca853deeSEric Joyner UNREFERENCED_PARAMETER(arg2); 170ca853deeSEric Joyner 171ca853deeSEric Joyner if (iavf_driver_is_detaching(sc)) 172ca853deeSEric Joyner return (ESHUTDOWN); 173ca853deeSEric Joyner 174ca853deeSEric Joyner if (IAVF_CAP_ADV_LINK_SPEED(sc)) 175ca853deeSEric Joyner error = sysctl_handle_string(oidp, 176ca853deeSEric Joyner __DECONST(char *, iavf_ext_speed_to_str(iavf_adv_speed_to_ext_speed(sc->link_speed_adv))), 177ca853deeSEric Joyner 8, req); 178ca853deeSEric Joyner else 179ca853deeSEric Joyner error = sysctl_handle_string(oidp, 180ca853deeSEric Joyner __DECONST(char *, iavf_vc_speed_to_string(sc->link_speed)), 181ca853deeSEric Joyner 8, req); 182ca853deeSEric Joyner 183ca853deeSEric Joyner return (error); 184ca853deeSEric Joyner } 185ca853deeSEric Joyner 186ca853deeSEric Joyner /** 187ca853deeSEric Joyner * iavf_reset_complete - Wait for a device reset to complete 188ca853deeSEric Joyner * @hw: pointer to the hardware structure 189ca853deeSEric Joyner * 190ca853deeSEric Joyner * Reads the reset registers and waits until they indicate that a device reset 191ca853deeSEric Joyner * is complete. 192ca853deeSEric Joyner * 193ca853deeSEric Joyner * @pre this function may call pause() and must not be called from a context 194ca853deeSEric Joyner * that cannot sleep. 195ca853deeSEric Joyner * 196ca853deeSEric Joyner * @returns zero on success, or EBUSY if it times out waiting for reset. 197ca853deeSEric Joyner */ 198ca853deeSEric Joyner int 199ca853deeSEric Joyner iavf_reset_complete(struct iavf_hw *hw) 200ca853deeSEric Joyner { 201ca853deeSEric Joyner u32 reg; 202ca853deeSEric Joyner 203ca853deeSEric Joyner /* Wait up to ~10 seconds */ 204ca853deeSEric Joyner for (int i = 0; i < 100; i++) { 205ca853deeSEric Joyner reg = rd32(hw, IAVF_VFGEN_RSTAT) & 206ca853deeSEric Joyner IAVF_VFGEN_RSTAT_VFR_STATE_MASK; 207ca853deeSEric Joyner 208ca853deeSEric Joyner if ((reg == VIRTCHNL_VFR_VFACTIVE) || 209ca853deeSEric Joyner (reg == VIRTCHNL_VFR_COMPLETED)) 210ca853deeSEric Joyner return (0); 211ca853deeSEric Joyner iavf_msec_pause(100); 212ca853deeSEric Joyner } 213ca853deeSEric Joyner 214ca853deeSEric Joyner return (EBUSY); 215ca853deeSEric Joyner } 216ca853deeSEric Joyner 217ca853deeSEric Joyner /** 218ca853deeSEric Joyner * iavf_setup_vc - Setup virtchnl communication 219ca853deeSEric Joyner * @sc: device private softc 220ca853deeSEric Joyner * 221ca853deeSEric Joyner * iavf_attach() helper function. Initializes the admin queue and attempts to 222ca853deeSEric Joyner * establish contact with the PF by retrying the initial "API version" message 223ca853deeSEric Joyner * several times or until the PF responds. 224ca853deeSEric Joyner * 225ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 226ca853deeSEric Joyner */ 227ca853deeSEric Joyner int 228ca853deeSEric Joyner iavf_setup_vc(struct iavf_sc *sc) 229ca853deeSEric Joyner { 230ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 231ca853deeSEric Joyner device_t dev = sc->dev; 232ca853deeSEric Joyner int error = 0, ret_error = 0, asq_retries = 0; 233ca853deeSEric Joyner bool send_api_ver_retried = 0; 234ca853deeSEric Joyner 235ca853deeSEric Joyner /* Need to set these AQ parameters before initializing AQ */ 236ca853deeSEric Joyner hw->aq.num_arq_entries = IAVF_AQ_LEN; 237ca853deeSEric Joyner hw->aq.num_asq_entries = IAVF_AQ_LEN; 238ca853deeSEric Joyner hw->aq.arq_buf_size = IAVF_AQ_BUF_SZ; 239ca853deeSEric Joyner hw->aq.asq_buf_size = IAVF_AQ_BUF_SZ; 240ca853deeSEric Joyner 241ca853deeSEric Joyner for (int i = 0; i < IAVF_AQ_MAX_ERR; i++) { 242ca853deeSEric Joyner /* Initialize admin queue */ 243ca853deeSEric Joyner error = iavf_init_adminq(hw); 244ca853deeSEric Joyner if (error) { 245ca853deeSEric Joyner device_printf(dev, "%s: init_adminq failed: %d\n", 246ca853deeSEric Joyner __func__, error); 247ca853deeSEric Joyner ret_error = 1; 248ca853deeSEric Joyner continue; 249ca853deeSEric Joyner } 250ca853deeSEric Joyner 251ca853deeSEric Joyner iavf_dbg_init(sc, "Initialized Admin Queue; starting" 252ca853deeSEric Joyner " send_api_ver attempt %d", i+1); 253ca853deeSEric Joyner 254ca853deeSEric Joyner retry_send: 255ca853deeSEric Joyner /* Send VF's API version */ 256ca853deeSEric Joyner error = iavf_send_api_ver(sc); 257ca853deeSEric Joyner if (error) { 258ca853deeSEric Joyner iavf_shutdown_adminq(hw); 259ca853deeSEric Joyner ret_error = 2; 260ca853deeSEric Joyner device_printf(dev, "%s: unable to send api" 261ca853deeSEric Joyner " version to PF on attempt %d, error %d\n", 262ca853deeSEric Joyner __func__, i+1, error); 263ca853deeSEric Joyner } 264ca853deeSEric Joyner 265ca853deeSEric Joyner asq_retries = 0; 266ca853deeSEric Joyner while (!iavf_asq_done(hw)) { 267ca853deeSEric Joyner if (++asq_retries > IAVF_AQ_MAX_ERR) { 268ca853deeSEric Joyner iavf_shutdown_adminq(hw); 269ca853deeSEric Joyner device_printf(dev, "Admin Queue timeout " 270ca853deeSEric Joyner "(waiting for send_api_ver), %d more tries...\n", 271ca853deeSEric Joyner IAVF_AQ_MAX_ERR - (i + 1)); 272ca853deeSEric Joyner ret_error = 3; 273ca853deeSEric Joyner break; 274ca853deeSEric Joyner } 275ca853deeSEric Joyner iavf_msec_pause(10); 276ca853deeSEric Joyner } 277ca853deeSEric Joyner if (asq_retries > IAVF_AQ_MAX_ERR) 278ca853deeSEric Joyner continue; 279ca853deeSEric Joyner 280ca853deeSEric Joyner iavf_dbg_init(sc, "Sent API version message to PF"); 281ca853deeSEric Joyner 282ca853deeSEric Joyner /* Verify that the VF accepts the PF's API version */ 283ca853deeSEric Joyner error = iavf_verify_api_ver(sc); 284ca853deeSEric Joyner if (error == ETIMEDOUT) { 285ca853deeSEric Joyner if (!send_api_ver_retried) { 286ca853deeSEric Joyner /* Resend message, one more time */ 287ca853deeSEric Joyner send_api_ver_retried = true; 288ca853deeSEric Joyner device_printf(dev, 289ca853deeSEric Joyner "%s: Timeout while verifying API version on first" 290ca853deeSEric Joyner " try!\n", __func__); 291ca853deeSEric Joyner goto retry_send; 292ca853deeSEric Joyner } else { 293ca853deeSEric Joyner device_printf(dev, 294ca853deeSEric Joyner "%s: Timeout while verifying API version on second" 295ca853deeSEric Joyner " try!\n", __func__); 296ca853deeSEric Joyner ret_error = 4; 297ca853deeSEric Joyner break; 298ca853deeSEric Joyner } 299ca853deeSEric Joyner } 300ca853deeSEric Joyner if (error) { 301ca853deeSEric Joyner device_printf(dev, 302ca853deeSEric Joyner "%s: Unable to verify API version," 303ca853deeSEric Joyner " error %d\n", __func__, error); 304ca853deeSEric Joyner ret_error = 5; 305ca853deeSEric Joyner } 306ca853deeSEric Joyner break; 307ca853deeSEric Joyner } 308ca853deeSEric Joyner 309ca853deeSEric Joyner if (ret_error >= 4) 310ca853deeSEric Joyner iavf_shutdown_adminq(hw); 311ca853deeSEric Joyner return (ret_error); 312ca853deeSEric Joyner } 313ca853deeSEric Joyner 314ca853deeSEric Joyner /** 315ca853deeSEric Joyner * iavf_reset - Requests a VF reset from the PF. 316ca853deeSEric Joyner * @sc: device private softc 317ca853deeSEric Joyner * 318ca853deeSEric Joyner * @pre Requires the VF's Admin Queue to be initialized. 319ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 320ca853deeSEric Joyner */ 321ca853deeSEric Joyner int 322ca853deeSEric Joyner iavf_reset(struct iavf_sc *sc) 323ca853deeSEric Joyner { 324ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 325ca853deeSEric Joyner device_t dev = sc->dev; 326ca853deeSEric Joyner int error = 0; 327ca853deeSEric Joyner 328ca853deeSEric Joyner /* Ask the PF to reset us if we are initiating */ 329ca853deeSEric Joyner if (!iavf_test_state(&sc->state, IAVF_STATE_RESET_PENDING)) 330ca853deeSEric Joyner iavf_request_reset(sc); 331ca853deeSEric Joyner 332ca853deeSEric Joyner iavf_msec_pause(100); 333ca853deeSEric Joyner error = iavf_reset_complete(hw); 334ca853deeSEric Joyner if (error) { 335ca853deeSEric Joyner device_printf(dev, "%s: VF reset failed\n", 336ca853deeSEric Joyner __func__); 337ca853deeSEric Joyner return (error); 338ca853deeSEric Joyner } 339ca853deeSEric Joyner pci_enable_busmaster(dev); 340ca853deeSEric Joyner 341ca853deeSEric Joyner error = iavf_shutdown_adminq(hw); 342ca853deeSEric Joyner if (error) { 343ca853deeSEric Joyner device_printf(dev, "%s: shutdown_adminq failed: %d\n", 344ca853deeSEric Joyner __func__, error); 345ca853deeSEric Joyner return (error); 346ca853deeSEric Joyner } 347ca853deeSEric Joyner 348ca853deeSEric Joyner error = iavf_init_adminq(hw); 349ca853deeSEric Joyner if (error) { 350ca853deeSEric Joyner device_printf(dev, "%s: init_adminq failed: %d\n", 351ca853deeSEric Joyner __func__, error); 352ca853deeSEric Joyner return (error); 353ca853deeSEric Joyner } 354ca853deeSEric Joyner 355ca853deeSEric Joyner /* IFLIB: This is called only in the iflib driver */ 356ca853deeSEric Joyner iavf_enable_adminq_irq(hw); 357ca853deeSEric Joyner return (0); 358ca853deeSEric Joyner } 359ca853deeSEric Joyner 360ca853deeSEric Joyner /** 361ca853deeSEric Joyner * iavf_enable_admin_irq - Enable the administrative interrupt 362ca853deeSEric Joyner * @hw: pointer to the hardware structure 363ca853deeSEric Joyner * 364ca853deeSEric Joyner * Writes to registers to enable the administrative interrupt cause, in order 365ca853deeSEric Joyner * to handle non-queue related interrupt events. 366ca853deeSEric Joyner */ 367ca853deeSEric Joyner void 368ca853deeSEric Joyner iavf_enable_adminq_irq(struct iavf_hw *hw) 369ca853deeSEric Joyner { 370ca853deeSEric Joyner wr32(hw, IAVF_VFINT_DYN_CTL01, 371ca853deeSEric Joyner IAVF_VFINT_DYN_CTL01_INTENA_MASK | 372ca853deeSEric Joyner IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK | 373ca853deeSEric Joyner IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK); 374ca853deeSEric Joyner wr32(hw, IAVF_VFINT_ICR0_ENA1, IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK); 375ca853deeSEric Joyner /* flush */ 376ca853deeSEric Joyner rd32(hw, IAVF_VFGEN_RSTAT); 377ca853deeSEric Joyner } 378ca853deeSEric Joyner 379ca853deeSEric Joyner /** 380ca853deeSEric Joyner * iavf_disable_admin_irq - Disable the administrative interrupt cause 381ca853deeSEric Joyner * @hw: pointer to the hardware structure 382ca853deeSEric Joyner * 383ca853deeSEric Joyner * Writes to registers to disable the administrative interrupt cause. 384ca853deeSEric Joyner */ 385ca853deeSEric Joyner void 386ca853deeSEric Joyner iavf_disable_adminq_irq(struct iavf_hw *hw) 387ca853deeSEric Joyner { 388ca853deeSEric Joyner wr32(hw, IAVF_VFINT_DYN_CTL01, 0); 389ca853deeSEric Joyner wr32(hw, IAVF_VFINT_ICR0_ENA1, 0); 390ca853deeSEric Joyner iavf_flush(hw); 391ca853deeSEric Joyner } 392ca853deeSEric Joyner 393ca853deeSEric Joyner /** 394ca853deeSEric Joyner * iavf_vf_config - Configure this VF over the virtchnl 395ca853deeSEric Joyner * @sc: device private softc 396ca853deeSEric Joyner * 397ca853deeSEric Joyner * iavf_attach() helper function. Asks the PF for this VF's configuration, and 398ca853deeSEric Joyner * saves the information if it receives it. 399ca853deeSEric Joyner * 400ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 401ca853deeSEric Joyner */ 402ca853deeSEric Joyner int 403ca853deeSEric Joyner iavf_vf_config(struct iavf_sc *sc) 404ca853deeSEric Joyner { 405ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 406ca853deeSEric Joyner device_t dev = sc->dev; 407ca853deeSEric Joyner int bufsz, error = 0, ret_error = 0; 408ca853deeSEric Joyner int asq_retries, retried = 0; 409ca853deeSEric Joyner 410ca853deeSEric Joyner retry_config: 411ca853deeSEric Joyner error = iavf_send_vf_config_msg(sc); 412ca853deeSEric Joyner if (error) { 413ca853deeSEric Joyner device_printf(dev, 414ca853deeSEric Joyner "%s: Unable to send VF config request, attempt %d," 415ca853deeSEric Joyner " error %d\n", __func__, retried + 1, error); 416ca853deeSEric Joyner ret_error = 2; 417ca853deeSEric Joyner } 418ca853deeSEric Joyner 419ca853deeSEric Joyner asq_retries = 0; 420ca853deeSEric Joyner while (!iavf_asq_done(hw)) { 421ca853deeSEric Joyner if (++asq_retries > IAVF_AQ_MAX_ERR) { 422ca853deeSEric Joyner device_printf(dev, "%s: Admin Queue timeout " 423ca853deeSEric Joyner "(waiting for send_vf_config_msg), attempt %d\n", 424ca853deeSEric Joyner __func__, retried + 1); 425ca853deeSEric Joyner ret_error = 3; 426ca853deeSEric Joyner goto fail; 427ca853deeSEric Joyner } 428ca853deeSEric Joyner iavf_msec_pause(10); 429ca853deeSEric Joyner } 430ca853deeSEric Joyner 431ca853deeSEric Joyner iavf_dbg_init(sc, "Sent VF config message to PF, attempt %d\n", 432ca853deeSEric Joyner retried + 1); 433ca853deeSEric Joyner 434ca853deeSEric Joyner if (!sc->vf_res) { 435ca853deeSEric Joyner bufsz = sizeof(struct virtchnl_vf_resource) + 436ca853deeSEric Joyner (IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource)); 437ca853deeSEric Joyner sc->vf_res = (struct virtchnl_vf_resource *)malloc(bufsz, M_IAVF, M_NOWAIT); 438ca853deeSEric Joyner if (!sc->vf_res) { 439ca853deeSEric Joyner device_printf(dev, 440ca853deeSEric Joyner "%s: Unable to allocate memory for VF configuration" 441ca853deeSEric Joyner " message from PF on attempt %d\n", __func__, retried + 1); 442ca853deeSEric Joyner ret_error = 1; 443ca853deeSEric Joyner goto fail; 444ca853deeSEric Joyner } 445ca853deeSEric Joyner } 446ca853deeSEric Joyner 447ca853deeSEric Joyner /* Check for VF config response */ 448ca853deeSEric Joyner error = iavf_get_vf_config(sc); 449ca853deeSEric Joyner if (error == ETIMEDOUT) { 450ca853deeSEric Joyner /* The 1st time we timeout, send the configuration message again */ 451ca853deeSEric Joyner if (!retried) { 452ca853deeSEric Joyner retried++; 453ca853deeSEric Joyner goto retry_config; 454ca853deeSEric Joyner } 455ca853deeSEric Joyner device_printf(dev, 456ca853deeSEric Joyner "%s: iavf_get_vf_config() timed out waiting for a response\n", 457ca853deeSEric Joyner __func__); 458ca853deeSEric Joyner } 459ca853deeSEric Joyner if (error) { 460ca853deeSEric Joyner device_printf(dev, 461ca853deeSEric Joyner "%s: Unable to get VF configuration from PF after %d tries!\n", 462ca853deeSEric Joyner __func__, retried + 1); 463ca853deeSEric Joyner ret_error = 4; 464ca853deeSEric Joyner } 465ca853deeSEric Joyner goto done; 466ca853deeSEric Joyner 467ca853deeSEric Joyner fail: 468ca853deeSEric Joyner free(sc->vf_res, M_IAVF); 469ca853deeSEric Joyner done: 470ca853deeSEric Joyner return (ret_error); 471ca853deeSEric Joyner } 472ca853deeSEric Joyner 473ca853deeSEric Joyner /** 474ca853deeSEric Joyner * iavf_print_device_info - Print some device parameters at attach 475ca853deeSEric Joyner * @sc: device private softc 476ca853deeSEric Joyner * 477ca853deeSEric Joyner * Log a message about this virtual device's capabilities at attach time. 478ca853deeSEric Joyner */ 479ca853deeSEric Joyner void 480ca853deeSEric Joyner iavf_print_device_info(struct iavf_sc *sc) 481ca853deeSEric Joyner { 482ca853deeSEric Joyner device_t dev = sc->dev; 483ca853deeSEric Joyner 484ca853deeSEric Joyner device_printf(dev, 485ca853deeSEric Joyner "VSIs %d, QPs %d, MSI-X %d, RSS sizes: key %d lut %d\n", 486ca853deeSEric Joyner sc->vf_res->num_vsis, 487ca853deeSEric Joyner sc->vf_res->num_queue_pairs, 488ca853deeSEric Joyner sc->vf_res->max_vectors, 489ca853deeSEric Joyner sc->vf_res->rss_key_size, 490ca853deeSEric Joyner sc->vf_res->rss_lut_size); 491ca853deeSEric Joyner iavf_dbg_info(sc, "Capabilities=%b\n", 492ca853deeSEric Joyner sc->vf_res->vf_cap_flags, IAVF_PRINTF_VF_OFFLOAD_FLAGS); 493ca853deeSEric Joyner } 494ca853deeSEric Joyner 495ca853deeSEric Joyner /** 496ca853deeSEric Joyner * iavf_get_vsi_res_from_vf_res - Get VSI parameters and info for this VF 497ca853deeSEric Joyner * @sc: device private softc 498ca853deeSEric Joyner * 499ca853deeSEric Joyner * Get the VSI parameters and information from the general VF resource info 500ca853deeSEric Joyner * received by the physical device. 501ca853deeSEric Joyner * 502ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 503ca853deeSEric Joyner */ 504ca853deeSEric Joyner int 505ca853deeSEric Joyner iavf_get_vsi_res_from_vf_res(struct iavf_sc *sc) 506ca853deeSEric Joyner { 507ca853deeSEric Joyner struct iavf_vsi *vsi = &sc->vsi; 508ca853deeSEric Joyner device_t dev = sc->dev; 509ca853deeSEric Joyner 510ca853deeSEric Joyner sc->vsi_res = NULL; 511ca853deeSEric Joyner 512ca853deeSEric Joyner for (int i = 0; i < sc->vf_res->num_vsis; i++) { 513ca853deeSEric Joyner /* XXX: We only use the first VSI we find */ 51467be1e19SDimitry Andric if (sc->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV) 515ca853deeSEric Joyner sc->vsi_res = &sc->vf_res->vsi_res[i]; 516ca853deeSEric Joyner } 517ca853deeSEric Joyner if (!sc->vsi_res) { 518ca853deeSEric Joyner device_printf(dev, "%s: no LAN VSI found\n", __func__); 519ca853deeSEric Joyner return (EIO); 520ca853deeSEric Joyner } 521ca853deeSEric Joyner 522ca853deeSEric Joyner vsi->id = sc->vsi_res->vsi_id; 523ca853deeSEric Joyner return (0); 524ca853deeSEric Joyner } 525ca853deeSEric Joyner 526ca853deeSEric Joyner /** 527ca853deeSEric Joyner * iavf_set_mac_addresses - Set the MAC address for this interface 528ca853deeSEric Joyner * @sc: device private softc 529ca853deeSEric Joyner * 530ca853deeSEric Joyner * Set the permanent MAC address field in the HW structure. If a MAC address 531ca853deeSEric Joyner * has not yet been set for this device by the physical function, generate one 532ca853deeSEric Joyner * randomly. 533ca853deeSEric Joyner */ 534ca853deeSEric Joyner void 535ca853deeSEric Joyner iavf_set_mac_addresses(struct iavf_sc *sc) 536ca853deeSEric Joyner { 537ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 538ca853deeSEric Joyner device_t dev = sc->dev; 539ca853deeSEric Joyner u8 addr[ETHER_ADDR_LEN]; 540ca853deeSEric Joyner 541ca853deeSEric Joyner /* If no mac address was assigned just make a random one */ 542ca853deeSEric Joyner if (ETHER_IS_ZERO(hw->mac.addr)) { 543ca853deeSEric Joyner arc4rand(&addr, sizeof(addr), 0); 544ca853deeSEric Joyner addr[0] &= 0xFE; 545ca853deeSEric Joyner addr[0] |= 0x02; 546ca853deeSEric Joyner memcpy(hw->mac.addr, addr, sizeof(addr)); 547ca853deeSEric Joyner device_printf(dev, "Generated random MAC address\n"); 548ca853deeSEric Joyner } 549ca853deeSEric Joyner memcpy(hw->mac.perm_addr, hw->mac.addr, ETHER_ADDR_LEN); 550ca853deeSEric Joyner } 551ca853deeSEric Joyner 552ca853deeSEric Joyner /** 553ca853deeSEric Joyner * iavf_init_filters - Initialize filter structures 554ca853deeSEric Joyner * @sc: device private softc 555ca853deeSEric Joyner * 556ca853deeSEric Joyner * Initialize the MAC and VLAN filter list heads. 557ca853deeSEric Joyner * 558ca853deeSEric Joyner * @remark this is intended to be called only once during the device attach 559ca853deeSEric Joyner * process. 560ca853deeSEric Joyner * 561ca853deeSEric Joyner * @pre Because it uses M_WAITOK, this function should only be called in 562ca853deeSEric Joyner * a context that is safe to sleep. 563ca853deeSEric Joyner */ 564ca853deeSEric Joyner void 565ca853deeSEric Joyner iavf_init_filters(struct iavf_sc *sc) 566ca853deeSEric Joyner { 567ca853deeSEric Joyner sc->mac_filters = (struct mac_list *)malloc(sizeof(struct iavf_mac_filter), 568ca853deeSEric Joyner M_IAVF, M_WAITOK | M_ZERO); 569ca853deeSEric Joyner SLIST_INIT(sc->mac_filters); 570ca853deeSEric Joyner sc->vlan_filters = (struct vlan_list *)malloc(sizeof(struct iavf_vlan_filter), 571ca853deeSEric Joyner M_IAVF, M_WAITOK | M_ZERO); 572ca853deeSEric Joyner SLIST_INIT(sc->vlan_filters); 573ca853deeSEric Joyner } 574ca853deeSEric Joyner 575ca853deeSEric Joyner /** 576ca853deeSEric Joyner * iavf_free_filters - Release filter lists 577ca853deeSEric Joyner * @sc: device private softc 578ca853deeSEric Joyner * 579ca853deeSEric Joyner * Free the MAC and VLAN filter lists. 580ca853deeSEric Joyner * 581ca853deeSEric Joyner * @remark this is intended to be called only once during the device detach 582ca853deeSEric Joyner * process. 583ca853deeSEric Joyner */ 584ca853deeSEric Joyner void 585ca853deeSEric Joyner iavf_free_filters(struct iavf_sc *sc) 586ca853deeSEric Joyner { 587ca853deeSEric Joyner struct iavf_mac_filter *f; 588ca853deeSEric Joyner struct iavf_vlan_filter *v; 589ca853deeSEric Joyner 590ca853deeSEric Joyner while (!SLIST_EMPTY(sc->mac_filters)) { 591ca853deeSEric Joyner f = SLIST_FIRST(sc->mac_filters); 592ca853deeSEric Joyner SLIST_REMOVE_HEAD(sc->mac_filters, next); 593ca853deeSEric Joyner free(f, M_IAVF); 594ca853deeSEric Joyner } 595ca853deeSEric Joyner free(sc->mac_filters, M_IAVF); 596ca853deeSEric Joyner while (!SLIST_EMPTY(sc->vlan_filters)) { 597ca853deeSEric Joyner v = SLIST_FIRST(sc->vlan_filters); 598ca853deeSEric Joyner SLIST_REMOVE_HEAD(sc->vlan_filters, next); 599ca853deeSEric Joyner free(v, M_IAVF); 600ca853deeSEric Joyner } 601ca853deeSEric Joyner free(sc->vlan_filters, M_IAVF); 602ca853deeSEric Joyner } 603ca853deeSEric Joyner 604ca853deeSEric Joyner /** 605ca853deeSEric Joyner * iavf_add_device_sysctls_common - Initialize common device sysctls 606ca853deeSEric Joyner * @sc: device private softc 607ca853deeSEric Joyner * 608ca853deeSEric Joyner * Setup sysctls common to both the iflib and legacy drivers. 609ca853deeSEric Joyner */ 610ca853deeSEric Joyner void 611ca853deeSEric Joyner iavf_add_device_sysctls_common(struct iavf_sc *sc) 612ca853deeSEric Joyner { 613ca853deeSEric Joyner device_t dev = sc->dev; 614ca853deeSEric Joyner struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 615ca853deeSEric Joyner struct sysctl_oid_list *ctx_list = 616ca853deeSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 617ca853deeSEric Joyner 618ca853deeSEric Joyner SYSCTL_ADD_PROC(ctx, ctx_list, 619ca853deeSEric Joyner OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD, 620ca853deeSEric Joyner sc, 0, iavf_sysctl_current_speed, "A", "Current Port Speed"); 621ca853deeSEric Joyner 622ca853deeSEric Joyner SYSCTL_ADD_PROC(ctx, ctx_list, 623ca853deeSEric Joyner OID_AUTO, "tx_itr", CTLTYPE_INT | CTLFLAG_RW, 624ca853deeSEric Joyner sc, 0, iavf_sysctl_tx_itr, "I", 625ca853deeSEric Joyner "Immediately set TX ITR value for all queues"); 626ca853deeSEric Joyner 627ca853deeSEric Joyner SYSCTL_ADD_PROC(ctx, ctx_list, 628ca853deeSEric Joyner OID_AUTO, "rx_itr", CTLTYPE_INT | CTLFLAG_RW, 629ca853deeSEric Joyner sc, 0, iavf_sysctl_rx_itr, "I", 630ca853deeSEric Joyner "Immediately set RX ITR value for all queues"); 631ca853deeSEric Joyner 632ca853deeSEric Joyner SYSCTL_ADD_UQUAD(ctx, ctx_list, 633ca853deeSEric Joyner OID_AUTO, "admin_irq", CTLFLAG_RD, 634ca853deeSEric Joyner &sc->admin_irq, "Admin Queue IRQ Handled"); 635ca853deeSEric Joyner } 636ca853deeSEric Joyner 637ca853deeSEric Joyner /** 638ca853deeSEric Joyner * iavf_add_debug_sysctls_common - Initialize common debug sysctls 639ca853deeSEric Joyner * @sc: device private softc 640ca853deeSEric Joyner * @debug_list: pionter to debug sysctl node 641ca853deeSEric Joyner * 642ca853deeSEric Joyner * Setup sysctls used for debugging the device driver into the debug sysctl 643ca853deeSEric Joyner * node. 644ca853deeSEric Joyner */ 645ca853deeSEric Joyner void 646ca853deeSEric Joyner iavf_add_debug_sysctls_common(struct iavf_sc *sc, struct sysctl_oid_list *debug_list) 647ca853deeSEric Joyner { 648ca853deeSEric Joyner device_t dev = sc->dev; 649ca853deeSEric Joyner struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 650ca853deeSEric Joyner 651ca853deeSEric Joyner SYSCTL_ADD_UINT(ctx, debug_list, 652ca853deeSEric Joyner OID_AUTO, "shared_debug_mask", CTLFLAG_RW, 653ca853deeSEric Joyner &sc->hw.debug_mask, 0, "Shared code debug message level"); 654ca853deeSEric Joyner 655ca853deeSEric Joyner SYSCTL_ADD_UINT(ctx, debug_list, 656ca853deeSEric Joyner OID_AUTO, "core_debug_mask", CTLFLAG_RW, 657ca853deeSEric Joyner (unsigned int *)&sc->dbg_mask, 0, "Non-shared code debug message level"); 658ca853deeSEric Joyner 659ca853deeSEric Joyner SYSCTL_ADD_PROC(ctx, debug_list, 660ca853deeSEric Joyner OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD, 661ca853deeSEric Joyner sc, 0, iavf_sysctl_sw_filter_list, "A", "SW Filter List"); 662ca853deeSEric Joyner } 663ca853deeSEric Joyner 664ca853deeSEric Joyner /** 665ca853deeSEric Joyner * iavf_sysctl_tx_itr - Sysctl to set the Tx ITR value 666ca853deeSEric Joyner * @oidp: sysctl oid pointer 667ca853deeSEric Joyner * @arg1: pointer to the device softc 668ca853deeSEric Joyner * @arg2: unused sysctl argument 669ca853deeSEric Joyner * @req: sysctl req pointer 670ca853deeSEric Joyner * 671ca853deeSEric Joyner * On read, returns the Tx ITR value for all of the VF queues. On write, 672ca853deeSEric Joyner * update the Tx ITR registers with the new Tx ITR value. 673ca853deeSEric Joyner * 674ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 675ca853deeSEric Joyner */ 676ca853deeSEric Joyner int 677ca853deeSEric Joyner iavf_sysctl_tx_itr(SYSCTL_HANDLER_ARGS) 678ca853deeSEric Joyner { 679ca853deeSEric Joyner struct iavf_sc *sc = (struct iavf_sc *)arg1; 680ca853deeSEric Joyner device_t dev = sc->dev; 681ca853deeSEric Joyner int requested_tx_itr; 682ca853deeSEric Joyner int error = 0; 683ca853deeSEric Joyner 684ca853deeSEric Joyner UNREFERENCED_PARAMETER(arg2); 685ca853deeSEric Joyner 686ca853deeSEric Joyner if (iavf_driver_is_detaching(sc)) 687ca853deeSEric Joyner return (ESHUTDOWN); 688ca853deeSEric Joyner 689ca853deeSEric Joyner requested_tx_itr = sc->tx_itr; 690ca853deeSEric Joyner error = sysctl_handle_int(oidp, &requested_tx_itr, 0, req); 691ca853deeSEric Joyner if ((error) || (req->newptr == NULL)) 692ca853deeSEric Joyner return (error); 693ca853deeSEric Joyner if (requested_tx_itr < 0 || requested_tx_itr > IAVF_MAX_ITR) { 694ca853deeSEric Joyner device_printf(dev, 695ca853deeSEric Joyner "Invalid TX itr value; value must be between 0 and %d\n", 696ca853deeSEric Joyner IAVF_MAX_ITR); 697ca853deeSEric Joyner return (EINVAL); 698ca853deeSEric Joyner } 699ca853deeSEric Joyner 700ca853deeSEric Joyner sc->tx_itr = requested_tx_itr; 701ca853deeSEric Joyner iavf_configure_tx_itr(sc); 702ca853deeSEric Joyner 703ca853deeSEric Joyner return (error); 704ca853deeSEric Joyner } 705ca853deeSEric Joyner 706ca853deeSEric Joyner /** 707ca853deeSEric Joyner * iavf_sysctl_rx_itr - Sysctl to set the Rx ITR value 708ca853deeSEric Joyner * @oidp: sysctl oid pointer 709ca853deeSEric Joyner * @arg1: pointer to the device softc 710ca853deeSEric Joyner * @arg2: unused sysctl argument 711ca853deeSEric Joyner * @req: sysctl req pointer 712ca853deeSEric Joyner * 713ca853deeSEric Joyner * On read, returns the Rx ITR value for all of the VF queues. On write, 714ca853deeSEric Joyner * update the ITR registers with the new Rx ITR value. 715ca853deeSEric Joyner * 716ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 717ca853deeSEric Joyner */ 718ca853deeSEric Joyner int 719ca853deeSEric Joyner iavf_sysctl_rx_itr(SYSCTL_HANDLER_ARGS) 720ca853deeSEric Joyner { 721ca853deeSEric Joyner struct iavf_sc *sc = (struct iavf_sc *)arg1; 722ca853deeSEric Joyner device_t dev = sc->dev; 723ca853deeSEric Joyner int requested_rx_itr; 724ca853deeSEric Joyner int error = 0; 725ca853deeSEric Joyner 726ca853deeSEric Joyner UNREFERENCED_PARAMETER(arg2); 727ca853deeSEric Joyner 728ca853deeSEric Joyner if (iavf_driver_is_detaching(sc)) 729ca853deeSEric Joyner return (ESHUTDOWN); 730ca853deeSEric Joyner 731ca853deeSEric Joyner requested_rx_itr = sc->rx_itr; 732ca853deeSEric Joyner error = sysctl_handle_int(oidp, &requested_rx_itr, 0, req); 733ca853deeSEric Joyner if ((error) || (req->newptr == NULL)) 734ca853deeSEric Joyner return (error); 735ca853deeSEric Joyner if (requested_rx_itr < 0 || requested_rx_itr > IAVF_MAX_ITR) { 736ca853deeSEric Joyner device_printf(dev, 737ca853deeSEric Joyner "Invalid RX itr value; value must be between 0 and %d\n", 738ca853deeSEric Joyner IAVF_MAX_ITR); 739ca853deeSEric Joyner return (EINVAL); 740ca853deeSEric Joyner } 741ca853deeSEric Joyner 742ca853deeSEric Joyner sc->rx_itr = requested_rx_itr; 743ca853deeSEric Joyner iavf_configure_rx_itr(sc); 744ca853deeSEric Joyner 745ca853deeSEric Joyner return (error); 746ca853deeSEric Joyner } 747ca853deeSEric Joyner 748ca853deeSEric Joyner /** 749ca853deeSEric Joyner * iavf_configure_tx_itr - Configure the Tx ITR 750ca853deeSEric Joyner * @sc: device private softc 751ca853deeSEric Joyner * 752ca853deeSEric Joyner * Updates the ITR registers with a new Tx ITR setting. 753ca853deeSEric Joyner */ 754ca853deeSEric Joyner void 755ca853deeSEric Joyner iavf_configure_tx_itr(struct iavf_sc *sc) 756ca853deeSEric Joyner { 757ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 758ca853deeSEric Joyner struct iavf_vsi *vsi = &sc->vsi; 759ca853deeSEric Joyner struct iavf_tx_queue *que = vsi->tx_queues; 760ca853deeSEric Joyner 761ca853deeSEric Joyner vsi->tx_itr_setting = sc->tx_itr; 762ca853deeSEric Joyner 763ca853deeSEric Joyner for (int i = 0; i < IAVF_NTXQS(vsi); i++, que++) { 764ca853deeSEric Joyner struct tx_ring *txr = &que->txr; 765ca853deeSEric Joyner 766ca853deeSEric Joyner wr32(hw, IAVF_VFINT_ITRN1(IAVF_TX_ITR, i), 767ca853deeSEric Joyner vsi->tx_itr_setting); 768ca853deeSEric Joyner txr->itr = vsi->tx_itr_setting; 769ca853deeSEric Joyner txr->latency = IAVF_AVE_LATENCY; 770ca853deeSEric Joyner } 771ca853deeSEric Joyner } 772ca853deeSEric Joyner 773ca853deeSEric Joyner /** 774ca853deeSEric Joyner * iavf_configure_rx_itr - Configure the Rx ITR 775ca853deeSEric Joyner * @sc: device private softc 776ca853deeSEric Joyner * 777ca853deeSEric Joyner * Updates the ITR registers with a new Rx ITR setting. 778ca853deeSEric Joyner */ 779ca853deeSEric Joyner void 780ca853deeSEric Joyner iavf_configure_rx_itr(struct iavf_sc *sc) 781ca853deeSEric Joyner { 782ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 783ca853deeSEric Joyner struct iavf_vsi *vsi = &sc->vsi; 784ca853deeSEric Joyner struct iavf_rx_queue *que = vsi->rx_queues; 785ca853deeSEric Joyner 786ca853deeSEric Joyner vsi->rx_itr_setting = sc->rx_itr; 787ca853deeSEric Joyner 788ca853deeSEric Joyner for (int i = 0; i < IAVF_NRXQS(vsi); i++, que++) { 789ca853deeSEric Joyner struct rx_ring *rxr = &que->rxr; 790ca853deeSEric Joyner 791ca853deeSEric Joyner wr32(hw, IAVF_VFINT_ITRN1(IAVF_RX_ITR, i), 792ca853deeSEric Joyner vsi->rx_itr_setting); 793ca853deeSEric Joyner rxr->itr = vsi->rx_itr_setting; 794ca853deeSEric Joyner rxr->latency = IAVF_AVE_LATENCY; 795ca853deeSEric Joyner } 796ca853deeSEric Joyner } 797ca853deeSEric Joyner 798ca853deeSEric Joyner /** 799ca853deeSEric Joyner * iavf_create_debug_sysctl_tree - Create a debug sysctl node 800ca853deeSEric Joyner * @sc: device private softc 801ca853deeSEric Joyner * 802ca853deeSEric Joyner * Create a sysctl node meant to hold sysctls used to print debug information. 803ca853deeSEric Joyner * Mark it as CTLFLAG_SKIP so that these sysctls do not show up in the 804ca853deeSEric Joyner * "sysctl -a" output. 805ca853deeSEric Joyner * 806ca853deeSEric Joyner * @returns a pointer to the created sysctl node. 807ca853deeSEric Joyner */ 808ca853deeSEric Joyner struct sysctl_oid_list * 809ca853deeSEric Joyner iavf_create_debug_sysctl_tree(struct iavf_sc *sc) 810ca853deeSEric Joyner { 811ca853deeSEric Joyner device_t dev = sc->dev; 812ca853deeSEric Joyner struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 813ca853deeSEric Joyner struct sysctl_oid_list *ctx_list = 814ca853deeSEric Joyner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); 815ca853deeSEric Joyner struct sysctl_oid *debug_node; 816ca853deeSEric Joyner 817ca853deeSEric Joyner debug_node = SYSCTL_ADD_NODE(ctx, ctx_list, 818ca853deeSEric Joyner OID_AUTO, "debug", CTLFLAG_RD | CTLFLAG_SKIP, NULL, "Debug Sysctls"); 819ca853deeSEric Joyner 820ca853deeSEric Joyner return (SYSCTL_CHILDREN(debug_node)); 821ca853deeSEric Joyner } 822ca853deeSEric Joyner 823ca853deeSEric Joyner /** 824ca853deeSEric Joyner * iavf_add_vsi_sysctls - Add sysctls for a given VSI 825ca853deeSEric Joyner * @dev: device pointer 826ca853deeSEric Joyner * @vsi: pointer to the VSI 827ca853deeSEric Joyner * @ctx: sysctl context to add to 828ca853deeSEric Joyner * @sysctl_name: name of the sysctl node (containing the VSI number) 829ca853deeSEric Joyner * 830ca853deeSEric Joyner * Adds a new sysctl node for holding specific sysctls for the given VSI. 831ca853deeSEric Joyner */ 832ca853deeSEric Joyner void 833ca853deeSEric Joyner iavf_add_vsi_sysctls(device_t dev, struct iavf_vsi *vsi, 834ca853deeSEric Joyner struct sysctl_ctx_list *ctx, const char *sysctl_name) 835ca853deeSEric Joyner { 836ca853deeSEric Joyner struct sysctl_oid *tree; 837ca853deeSEric Joyner struct sysctl_oid_list *child; 838ca853deeSEric Joyner struct sysctl_oid_list *vsi_list; 839ca853deeSEric Joyner 840ca853deeSEric Joyner tree = device_get_sysctl_tree(dev); 841ca853deeSEric Joyner child = SYSCTL_CHILDREN(tree); 842ca853deeSEric Joyner vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name, 843ca853deeSEric Joyner CTLFLAG_RD, NULL, "VSI Number"); 844ca853deeSEric Joyner vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); 845ca853deeSEric Joyner 846ca853deeSEric Joyner iavf_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats); 847ca853deeSEric Joyner } 848ca853deeSEric Joyner 849ca853deeSEric Joyner /** 850ca853deeSEric Joyner * iavf_sysctl_sw_filter_list - Dump software filters 851ca853deeSEric Joyner * @oidp: sysctl oid pointer 852ca853deeSEric Joyner * @arg1: pointer to the device softc 853ca853deeSEric Joyner * @arg2: unused sysctl argument 854ca853deeSEric Joyner * @req: sysctl req pointer 855ca853deeSEric Joyner * 856ca853deeSEric Joyner * On read, generates a string which lists the MAC and VLAN filters added to 857ca853deeSEric Joyner * this virtual device. Useful for debugging to see whether or not the 858ca853deeSEric Joyner * expected filters have been configured by software. 859ca853deeSEric Joyner * 860ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 861ca853deeSEric Joyner */ 862ca853deeSEric Joyner int 863ca853deeSEric Joyner iavf_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS) 864ca853deeSEric Joyner { 865ca853deeSEric Joyner struct iavf_sc *sc = (struct iavf_sc *)arg1; 866ca853deeSEric Joyner struct iavf_mac_filter *f; 867ca853deeSEric Joyner struct iavf_vlan_filter *v; 868ca853deeSEric Joyner device_t dev = sc->dev; 869ca853deeSEric Joyner int ftl_len, ftl_counter = 0, error = 0; 870ca853deeSEric Joyner struct sbuf *buf; 871ca853deeSEric Joyner 872ca853deeSEric Joyner UNREFERENCED_2PARAMETER(arg2, oidp); 873ca853deeSEric Joyner 874ca853deeSEric Joyner if (iavf_driver_is_detaching(sc)) 875ca853deeSEric Joyner return (ESHUTDOWN); 876ca853deeSEric Joyner 877ca853deeSEric Joyner buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); 878ca853deeSEric Joyner if (!buf) { 879ca853deeSEric Joyner device_printf(dev, "Could not allocate sbuf for output.\n"); 880ca853deeSEric Joyner return (ENOMEM); 881ca853deeSEric Joyner } 882ca853deeSEric Joyner 883ca853deeSEric Joyner sbuf_printf(buf, "\n"); 884ca853deeSEric Joyner 885ca853deeSEric Joyner /* Print MAC filters */ 886ca853deeSEric Joyner sbuf_printf(buf, "MAC Filters:\n"); 887ca853deeSEric Joyner ftl_len = 0; 888ca853deeSEric Joyner SLIST_FOREACH(f, sc->mac_filters, next) 889ca853deeSEric Joyner ftl_len++; 890ca853deeSEric Joyner if (ftl_len < 1) 891ca853deeSEric Joyner sbuf_printf(buf, "(none)\n"); 892ca853deeSEric Joyner else { 893ca853deeSEric Joyner SLIST_FOREACH(f, sc->mac_filters, next) { 894ca853deeSEric Joyner sbuf_printf(buf, 895ca853deeSEric Joyner MAC_FORMAT ", flags %#06x\n", 896ca853deeSEric Joyner MAC_FORMAT_ARGS(f->macaddr), f->flags); 897ca853deeSEric Joyner } 898ca853deeSEric Joyner } 899ca853deeSEric Joyner 900ca853deeSEric Joyner /* Print VLAN filters */ 901ca853deeSEric Joyner sbuf_printf(buf, "VLAN Filters:\n"); 902ca853deeSEric Joyner ftl_len = 0; 903ca853deeSEric Joyner SLIST_FOREACH(v, sc->vlan_filters, next) 904ca853deeSEric Joyner ftl_len++; 905ca853deeSEric Joyner if (ftl_len < 1) 906ca853deeSEric Joyner sbuf_printf(buf, "(none)"); 907ca853deeSEric Joyner else { 908ca853deeSEric Joyner SLIST_FOREACH(v, sc->vlan_filters, next) { 909ca853deeSEric Joyner sbuf_printf(buf, 910ca853deeSEric Joyner "%d, flags %#06x", 911ca853deeSEric Joyner v->vlan, v->flags); 912ca853deeSEric Joyner /* don't print '\n' for last entry */ 913ca853deeSEric Joyner if (++ftl_counter != ftl_len) 914ca853deeSEric Joyner sbuf_printf(buf, "\n"); 915ca853deeSEric Joyner } 916ca853deeSEric Joyner } 917ca853deeSEric Joyner 918ca853deeSEric Joyner error = sbuf_finish(buf); 919ca853deeSEric Joyner if (error) 920ca853deeSEric Joyner device_printf(dev, "Error finishing sbuf: %d\n", error); 921ca853deeSEric Joyner 922ca853deeSEric Joyner sbuf_delete(buf); 923ca853deeSEric Joyner return (error); 924ca853deeSEric Joyner } 925ca853deeSEric Joyner 926ca853deeSEric Joyner /** 927ca853deeSEric Joyner * iavf_media_status_common - Get media status for this device 928ca853deeSEric Joyner * @sc: device softc pointer 929ca853deeSEric Joyner * @ifmr: ifmedia request structure 930ca853deeSEric Joyner * 931ca853deeSEric Joyner * Report the media status for this device into the given ifmr structure. 932ca853deeSEric Joyner */ 933ca853deeSEric Joyner void 934ca853deeSEric Joyner iavf_media_status_common(struct iavf_sc *sc, struct ifmediareq *ifmr) 935ca853deeSEric Joyner { 936ca853deeSEric Joyner enum iavf_ext_link_speed ext_speed; 937ca853deeSEric Joyner 938ca853deeSEric Joyner iavf_update_link_status(sc); 939ca853deeSEric Joyner 940ca853deeSEric Joyner ifmr->ifm_status = IFM_AVALID; 941ca853deeSEric Joyner ifmr->ifm_active = IFM_ETHER; 942ca853deeSEric Joyner 943ca853deeSEric Joyner if (!sc->link_up) 944ca853deeSEric Joyner return; 945ca853deeSEric Joyner 946ca853deeSEric Joyner ifmr->ifm_status |= IFM_ACTIVE; 947ca853deeSEric Joyner /* Hardware is always full-duplex */ 948ca853deeSEric Joyner ifmr->ifm_active |= IFM_FDX; 949ca853deeSEric Joyner 950ca853deeSEric Joyner /* Based on the link speed reported by the PF over the AdminQ, choose a 951ca853deeSEric Joyner * PHY type to report. This isn't 100% correct since we don't really 952ca853deeSEric Joyner * know the underlying PHY type of the PF, but at least we can report 953ca853deeSEric Joyner * a valid link speed... 954ca853deeSEric Joyner */ 955ca853deeSEric Joyner if (IAVF_CAP_ADV_LINK_SPEED(sc)) 956ca853deeSEric Joyner ext_speed = iavf_adv_speed_to_ext_speed(sc->link_speed_adv); 957ca853deeSEric Joyner else 958ca853deeSEric Joyner ext_speed = iavf_vc_speed_to_ext_speed(sc->link_speed); 959ca853deeSEric Joyner 960ca853deeSEric Joyner ifmr->ifm_active |= iavf_ext_speed_to_ifmedia(ext_speed); 961ca853deeSEric Joyner } 962ca853deeSEric Joyner 963ca853deeSEric Joyner /** 964ca853deeSEric Joyner * iavf_media_change_common - Change the media type for this device 965ca853deeSEric Joyner * @ifp: ifnet structure 966ca853deeSEric Joyner * 967ca853deeSEric Joyner * @returns ENODEV because changing the media and speed is not supported. 968ca853deeSEric Joyner */ 969ca853deeSEric Joyner int 970d8096b2dSJustin Hibbits iavf_media_change_common(if_t ifp) 971ca853deeSEric Joyner { 972ca853deeSEric Joyner if_printf(ifp, "Changing speed is not supported\n"); 973ca853deeSEric Joyner 974ca853deeSEric Joyner return (ENODEV); 975ca853deeSEric Joyner } 976ca853deeSEric Joyner 977ca853deeSEric Joyner /** 978ca853deeSEric Joyner * iavf_set_initial_baudrate - Set the initial device baudrate 979ca853deeSEric Joyner * @ifp: ifnet structure 980ca853deeSEric Joyner * 981ca853deeSEric Joyner * Set the baudrate for this ifnet structure to the expected initial value of 982ca853deeSEric Joyner * 40Gbps. This maybe updated to a lower baudrate after the physical function 983ca853deeSEric Joyner * reports speed to us over the virtchnl interface. 984ca853deeSEric Joyner */ 985ca853deeSEric Joyner void 986d8096b2dSJustin Hibbits iavf_set_initial_baudrate(if_t ifp) 987ca853deeSEric Joyner { 988ca853deeSEric Joyner if_setbaudrate(ifp, IF_Gbps(40)); 989ca853deeSEric Joyner } 990ca853deeSEric Joyner 991ca853deeSEric Joyner /** 992ca853deeSEric Joyner * iavf_add_sysctls_eth_stats - Add ethernet statistics sysctls 993ca853deeSEric Joyner * @ctx: the sysctl ctx to add to 994ca853deeSEric Joyner * @child: the node to add the sysctls to 995ca853deeSEric Joyner * @eth_stats: ethernet stats structure 996ca853deeSEric Joyner * 997ca853deeSEric Joyner * Creates sysctls that report the values of the provided ethernet stats 998ca853deeSEric Joyner * structure. 999ca853deeSEric Joyner */ 1000ca853deeSEric Joyner void 1001ca853deeSEric Joyner iavf_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, 1002ca853deeSEric Joyner struct sysctl_oid_list *child, 1003ca853deeSEric Joyner struct iavf_eth_stats *eth_stats) 1004ca853deeSEric Joyner { 1005ca853deeSEric Joyner struct iavf_sysctl_info ctls[] = 1006ca853deeSEric Joyner { 1007ca853deeSEric Joyner {ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, 1008ca853deeSEric Joyner {ð_stats->rx_unicast, "ucast_pkts_rcvd", 1009ca853deeSEric Joyner "Unicast Packets Received"}, 1010ca853deeSEric Joyner {ð_stats->rx_multicast, "mcast_pkts_rcvd", 1011ca853deeSEric Joyner "Multicast Packets Received"}, 1012ca853deeSEric Joyner {ð_stats->rx_broadcast, "bcast_pkts_rcvd", 1013ca853deeSEric Joyner "Broadcast Packets Received"}, 1014ca853deeSEric Joyner {ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, 1015ca853deeSEric Joyner {ð_stats->rx_unknown_protocol, "rx_unknown_proto", 1016ca853deeSEric Joyner "RX unknown protocol packets"}, 1017ca853deeSEric Joyner {ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, 1018ca853deeSEric Joyner {ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, 1019ca853deeSEric Joyner {ð_stats->tx_multicast, "mcast_pkts_txd", 1020ca853deeSEric Joyner "Multicast Packets Transmitted"}, 1021ca853deeSEric Joyner {ð_stats->tx_broadcast, "bcast_pkts_txd", 1022ca853deeSEric Joyner "Broadcast Packets Transmitted"}, 1023ca853deeSEric Joyner {ð_stats->tx_errors, "tx_errors", "TX packet errors"}, 1024ca853deeSEric Joyner // end 1025ca853deeSEric Joyner {0,0,0} 1026ca853deeSEric Joyner }; 1027ca853deeSEric Joyner 1028ca853deeSEric Joyner struct iavf_sysctl_info *entry = ctls; 1029ca853deeSEric Joyner 1030ca853deeSEric Joyner while (entry->stat != 0) 1031ca853deeSEric Joyner { 1032ca853deeSEric Joyner SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, 1033ca853deeSEric Joyner CTLFLAG_RD, entry->stat, 1034ca853deeSEric Joyner entry->description); 1035ca853deeSEric Joyner entry++; 1036ca853deeSEric Joyner } 1037ca853deeSEric Joyner } 1038ca853deeSEric Joyner 1039ca853deeSEric Joyner /** 1040ca853deeSEric Joyner * iavf_max_vc_speed_to_value - Convert link speed to IF speed value 1041ca853deeSEric Joyner * @link_speeds: bitmap of supported link speeds 1042ca853deeSEric Joyner * 1043ca853deeSEric Joyner * @returns the link speed value for the highest speed reported in the 1044ca853deeSEric Joyner * link_speeds bitmap. 1045ca853deeSEric Joyner */ 1046ca853deeSEric Joyner u64 1047ca853deeSEric Joyner iavf_max_vc_speed_to_value(u8 link_speeds) 1048ca853deeSEric Joyner { 1049ca853deeSEric Joyner if (link_speeds & VIRTCHNL_LINK_SPEED_40GB) 1050ca853deeSEric Joyner return IF_Gbps(40); 1051ca853deeSEric Joyner if (link_speeds & VIRTCHNL_LINK_SPEED_25GB) 1052ca853deeSEric Joyner return IF_Gbps(25); 1053ca853deeSEric Joyner if (link_speeds & VIRTCHNL_LINK_SPEED_20GB) 1054ca853deeSEric Joyner return IF_Gbps(20); 1055ca853deeSEric Joyner if (link_speeds & VIRTCHNL_LINK_SPEED_10GB) 1056ca853deeSEric Joyner return IF_Gbps(10); 1057ca853deeSEric Joyner if (link_speeds & VIRTCHNL_LINK_SPEED_1GB) 1058ca853deeSEric Joyner return IF_Gbps(1); 1059ca853deeSEric Joyner if (link_speeds & VIRTCHNL_LINK_SPEED_100MB) 1060ca853deeSEric Joyner return IF_Mbps(100); 1061ca853deeSEric Joyner else 1062ca853deeSEric Joyner /* Minimum supported link speed */ 1063ca853deeSEric Joyner return IF_Mbps(100); 1064ca853deeSEric Joyner } 1065ca853deeSEric Joyner 1066ca853deeSEric Joyner /** 1067ca853deeSEric Joyner * iavf_config_rss_reg - Configure RSS using registers 1068ca853deeSEric Joyner * @sc: device private softc 1069ca853deeSEric Joyner * 1070ca853deeSEric Joyner * Configures RSS for this function using the device registers. Called if the 1071ca853deeSEric Joyner * PF does not support configuring RSS over the virtchnl interface. 1072ca853deeSEric Joyner */ 1073ca853deeSEric Joyner void 1074ca853deeSEric Joyner iavf_config_rss_reg(struct iavf_sc *sc) 1075ca853deeSEric Joyner { 1076ca853deeSEric Joyner struct iavf_hw *hw = &sc->hw; 1077ca853deeSEric Joyner struct iavf_vsi *vsi = &sc->vsi; 1078ca853deeSEric Joyner u32 lut = 0; 1079ca853deeSEric Joyner u64 set_hena = 0, hena; 1080ca853deeSEric Joyner int i, j, que_id; 1081ca853deeSEric Joyner u32 rss_seed[IAVF_RSS_KEY_SIZE_REG]; 1082ca853deeSEric Joyner #ifdef RSS 1083ca853deeSEric Joyner u32 rss_hash_config; 1084ca853deeSEric Joyner #endif 1085ca853deeSEric Joyner 1086ca853deeSEric Joyner /* Don't set up RSS if using a single queue */ 1087ca853deeSEric Joyner if (IAVF_NRXQS(vsi) == 1) { 1088ca853deeSEric Joyner wr32(hw, IAVF_VFQF_HENA(0), 0); 1089ca853deeSEric Joyner wr32(hw, IAVF_VFQF_HENA(1), 0); 1090ca853deeSEric Joyner iavf_flush(hw); 1091ca853deeSEric Joyner return; 1092ca853deeSEric Joyner } 1093ca853deeSEric Joyner 1094ca853deeSEric Joyner #ifdef RSS 1095ca853deeSEric Joyner /* Fetch the configured RSS key */ 1096ca853deeSEric Joyner rss_getkey((uint8_t *) &rss_seed); 1097ca853deeSEric Joyner #else 1098ca853deeSEric Joyner iavf_get_default_rss_key(rss_seed); 1099ca853deeSEric Joyner #endif 1100ca853deeSEric Joyner 1101ca853deeSEric Joyner /* Fill out hash function seed */ 1102ca853deeSEric Joyner for (i = 0; i < IAVF_RSS_KEY_SIZE_REG; i++) 1103ca853deeSEric Joyner wr32(hw, IAVF_VFQF_HKEY(i), rss_seed[i]); 1104ca853deeSEric Joyner 1105ca853deeSEric Joyner /* Enable PCTYPES for RSS: */ 1106ca853deeSEric Joyner #ifdef RSS 1107ca853deeSEric Joyner rss_hash_config = rss_gethashconfig(); 1108ca853deeSEric Joyner if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) 1109ca853deeSEric Joyner set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV4_OTHER); 1110ca853deeSEric Joyner if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) 1111ca853deeSEric Joyner set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV4_TCP); 1112ca853deeSEric Joyner if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) 1113ca853deeSEric Joyner set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV4_UDP); 1114ca853deeSEric Joyner if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) 1115ca853deeSEric Joyner set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV6_OTHER); 1116ca853deeSEric Joyner if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) 1117ca853deeSEric Joyner set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_FRAG_IPV6); 1118ca853deeSEric Joyner if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) 1119ca853deeSEric Joyner set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV6_TCP); 1120ca853deeSEric Joyner if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) 1121ca853deeSEric Joyner set_hena |= ((u64)1 << IAVF_FILTER_PCTYPE_NONF_IPV6_UDP); 1122ca853deeSEric Joyner #else 1123ca853deeSEric Joyner set_hena = IAVF_DEFAULT_RSS_HENA_XL710; 1124ca853deeSEric Joyner #endif 1125ca853deeSEric Joyner hena = (u64)rd32(hw, IAVF_VFQF_HENA(0)) | 1126ca853deeSEric Joyner ((u64)rd32(hw, IAVF_VFQF_HENA(1)) << 32); 1127ca853deeSEric Joyner hena |= set_hena; 1128ca853deeSEric Joyner wr32(hw, IAVF_VFQF_HENA(0), (u32)hena); 1129ca853deeSEric Joyner wr32(hw, IAVF_VFQF_HENA(1), (u32)(hena >> 32)); 1130ca853deeSEric Joyner 1131ca853deeSEric Joyner /* Populate the LUT with max no. of queues in round robin fashion */ 1132ca853deeSEric Joyner for (i = 0, j = 0; i < IAVF_RSS_VSI_LUT_SIZE; i++, j++) { 1133ca853deeSEric Joyner if (j == IAVF_NRXQS(vsi)) 1134ca853deeSEric Joyner j = 0; 1135ca853deeSEric Joyner #ifdef RSS 1136ca853deeSEric Joyner /* 1137ca853deeSEric Joyner * Fetch the RSS bucket id for the given indirection entry. 1138ca853deeSEric Joyner * Cap it at the number of configured buckets (which is 1139ca853deeSEric Joyner * num_rx_queues.) 1140ca853deeSEric Joyner */ 1141ca853deeSEric Joyner que_id = rss_get_indirection_to_bucket(i); 1142ca853deeSEric Joyner que_id = que_id % IAVF_NRXQS(vsi); 1143ca853deeSEric Joyner #else 1144ca853deeSEric Joyner que_id = j; 1145ca853deeSEric Joyner #endif 1146ca853deeSEric Joyner /* lut = 4-byte sliding window of 4 lut entries */ 1147ca853deeSEric Joyner lut = (lut << 8) | (que_id & IAVF_RSS_VF_LUT_ENTRY_MASK); 1148ca853deeSEric Joyner /* On i = 3, we have 4 entries in lut; write to the register */ 1149ca853deeSEric Joyner if ((i & 3) == 3) { 1150ca853deeSEric Joyner wr32(hw, IAVF_VFQF_HLUT(i >> 2), lut); 1151ca853deeSEric Joyner iavf_dbg_rss(sc, "%s: HLUT(%2d): %#010x", __func__, 1152ca853deeSEric Joyner i, lut); 1153ca853deeSEric Joyner } 1154ca853deeSEric Joyner } 1155ca853deeSEric Joyner iavf_flush(hw); 1156ca853deeSEric Joyner } 1157ca853deeSEric Joyner 1158ca853deeSEric Joyner /** 1159ca853deeSEric Joyner * iavf_config_rss_pf - Configure RSS using PF virtchnl messages 1160ca853deeSEric Joyner * @sc: device private softc 1161ca853deeSEric Joyner * 1162ca853deeSEric Joyner * Configure RSS by sending virtchnl messages to the PF. 1163ca853deeSEric Joyner */ 1164ca853deeSEric Joyner void 1165ca853deeSEric Joyner iavf_config_rss_pf(struct iavf_sc *sc) 1166ca853deeSEric Joyner { 1167ca853deeSEric Joyner iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIG_RSS_KEY); 1168ca853deeSEric Joyner 1169ca853deeSEric Joyner iavf_send_vc_msg(sc, IAVF_FLAG_AQ_SET_RSS_HENA); 1170ca853deeSEric Joyner 1171ca853deeSEric Joyner iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIG_RSS_LUT); 1172ca853deeSEric Joyner } 1173ca853deeSEric Joyner 1174ca853deeSEric Joyner /** 1175ca853deeSEric Joyner * iavf_config_rss - setup RSS 1176ca853deeSEric Joyner * @sc: device private softc 1177ca853deeSEric Joyner * 1178ca853deeSEric Joyner * Configures RSS using the method determined by capability flags in the VF 1179ca853deeSEric Joyner * resources structure sent from the PF over the virtchnl interface. 1180ca853deeSEric Joyner * 1181ca853deeSEric Joyner * @remark RSS keys and table are cleared on VF reset. 1182ca853deeSEric Joyner */ 1183ca853deeSEric Joyner void 1184ca853deeSEric Joyner iavf_config_rss(struct iavf_sc *sc) 1185ca853deeSEric Joyner { 1186ca853deeSEric Joyner if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_REG) { 1187ca853deeSEric Joyner iavf_dbg_info(sc, "Setting up RSS using VF registers...\n"); 1188ca853deeSEric Joyner iavf_config_rss_reg(sc); 1189ca853deeSEric Joyner } else if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) { 1190ca853deeSEric Joyner iavf_dbg_info(sc, "Setting up RSS using messages to PF...\n"); 1191ca853deeSEric Joyner iavf_config_rss_pf(sc); 1192ca853deeSEric Joyner } else 1193ca853deeSEric Joyner device_printf(sc->dev, "VF does not support RSS capability sent by PF.\n"); 1194ca853deeSEric Joyner } 1195ca853deeSEric Joyner 1196ca853deeSEric Joyner /** 1197ca853deeSEric Joyner * iavf_config_promisc - setup promiscuous mode 1198ca853deeSEric Joyner * @sc: device private softc 1199ca853deeSEric Joyner * @flags: promiscuous flags to configure 1200ca853deeSEric Joyner * 1201ca853deeSEric Joyner * Request that promiscuous modes be enabled from the PF 1202ca853deeSEric Joyner * 1203ca853deeSEric Joyner * @returns zero on success, or an error code on failure. 1204ca853deeSEric Joyner */ 1205ca853deeSEric Joyner int 1206ca853deeSEric Joyner iavf_config_promisc(struct iavf_sc *sc, int flags) 1207ca853deeSEric Joyner { 1208d8096b2dSJustin Hibbits if_t ifp = sc->vsi.ifp; 1209ca853deeSEric Joyner 1210ca853deeSEric Joyner sc->promisc_flags = 0; 1211ca853deeSEric Joyner 1212ca853deeSEric Joyner if (flags & IFF_ALLMULTI || 1213ca853deeSEric Joyner if_llmaddr_count(ifp) == MAX_MULTICAST_ADDR) 1214ca853deeSEric Joyner sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC; 1215ca853deeSEric Joyner if (flags & IFF_PROMISC) 1216ca853deeSEric Joyner sc->promisc_flags |= FLAG_VF_UNICAST_PROMISC; 1217ca853deeSEric Joyner 1218ca853deeSEric Joyner iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIGURE_PROMISC); 1219ca853deeSEric Joyner 1220ca853deeSEric Joyner return (0); 1221ca853deeSEric Joyner } 1222ca853deeSEric Joyner 1223ca853deeSEric Joyner /** 1224ca853deeSEric Joyner * iavf_mc_filter_apply - Program a MAC filter for this VF 1225ca853deeSEric Joyner * @arg: pointer to the device softc 1226ca853deeSEric Joyner * @sdl: MAC multicast address 1227ca853deeSEric Joyner * @cnt: unused parameter 1228ca853deeSEric Joyner * 1229ca853deeSEric Joyner * Program a MAC address multicast filter for this device. Intended 1230ca853deeSEric Joyner * to be used with the map-like function if_foreach_llmaddr(). 1231ca853deeSEric Joyner * 1232ca853deeSEric Joyner * @returns 1 on success, or 0 on failure 1233ca853deeSEric Joyner */ 1234ca853deeSEric Joyner static u_int 1235ca853deeSEric Joyner iavf_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int cnt __unused) 1236ca853deeSEric Joyner { 1237ca853deeSEric Joyner struct iavf_sc *sc = (struct iavf_sc *)arg; 1238ca853deeSEric Joyner int error; 1239ca853deeSEric Joyner 1240ca853deeSEric Joyner error = iavf_add_mac_filter(sc, (u8*)LLADDR(sdl), IAVF_FILTER_MC); 1241ca853deeSEric Joyner 1242ca853deeSEric Joyner return (!error); 1243ca853deeSEric Joyner } 1244ca853deeSEric Joyner 1245ca853deeSEric Joyner /** 1246ca853deeSEric Joyner * iavf_init_multi - Initialize multicast address filters 1247ca853deeSEric Joyner * @sc: device private softc 1248ca853deeSEric Joyner * 1249ca853deeSEric Joyner * Called during initialization to reset multicast address filters to a known 1250ca853deeSEric Joyner * fresh state by deleting all currently active filters. 1251ca853deeSEric Joyner */ 1252ca853deeSEric Joyner void 1253ca853deeSEric Joyner iavf_init_multi(struct iavf_sc *sc) 1254ca853deeSEric Joyner { 1255ca853deeSEric Joyner struct iavf_mac_filter *f; 1256ca853deeSEric Joyner int mcnt = 0; 1257ca853deeSEric Joyner 1258ca853deeSEric Joyner /* First clear any multicast filters */ 1259ca853deeSEric Joyner SLIST_FOREACH(f, sc->mac_filters, next) { 1260ca853deeSEric Joyner if ((f->flags & IAVF_FILTER_USED) 1261ca853deeSEric Joyner && (f->flags & IAVF_FILTER_MC)) { 1262ca853deeSEric Joyner f->flags |= IAVF_FILTER_DEL; 1263ca853deeSEric Joyner mcnt++; 1264ca853deeSEric Joyner } 1265ca853deeSEric Joyner } 1266ca853deeSEric Joyner if (mcnt > 0) 1267ca853deeSEric Joyner iavf_send_vc_msg(sc, IAVF_FLAG_AQ_DEL_MAC_FILTER); 1268ca853deeSEric Joyner } 1269ca853deeSEric Joyner 1270ca853deeSEric Joyner /** 1271ca853deeSEric Joyner * iavf_multi_set - Set multicast filters 1272ca853deeSEric Joyner * @sc: device private softc 1273ca853deeSEric Joyner * 1274ca853deeSEric Joyner * Set multicast MAC filters for this device. If there are too many filters, 1275ca853deeSEric Joyner * this will request the device to go into multicast promiscuous mode instead. 1276ca853deeSEric Joyner */ 1277ca853deeSEric Joyner void 1278ca853deeSEric Joyner iavf_multi_set(struct iavf_sc *sc) 1279ca853deeSEric Joyner { 1280ca853deeSEric Joyner if_t ifp = sc->vsi.ifp; 1281ca853deeSEric Joyner int mcnt = 0; 1282ca853deeSEric Joyner 1283ca853deeSEric Joyner IOCTL_DEBUGOUT("iavf_multi_set: begin"); 1284ca853deeSEric Joyner 1285ca853deeSEric Joyner mcnt = if_llmaddr_count(ifp); 1286ca853deeSEric Joyner if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) { 1287ca853deeSEric Joyner /* Delete MC filters and enable mulitcast promisc instead */ 1288ca853deeSEric Joyner iavf_init_multi(sc); 1289ca853deeSEric Joyner sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC; 1290ca853deeSEric Joyner iavf_send_vc_msg(sc, IAVF_FLAG_AQ_CONFIGURE_PROMISC); 1291ca853deeSEric Joyner return; 1292ca853deeSEric Joyner } 1293ca853deeSEric Joyner 1294ca853deeSEric Joyner /* If there aren't too many filters, delete existing MC filters */ 1295ca853deeSEric Joyner iavf_init_multi(sc); 1296ca853deeSEric Joyner 1297ca853deeSEric Joyner /* And (re-)install filters for all mcast addresses */ 1298ca853deeSEric Joyner mcnt = if_foreach_llmaddr(ifp, iavf_mc_filter_apply, sc); 1299ca853deeSEric Joyner 1300ca853deeSEric Joyner if (mcnt > 0) 1301ca853deeSEric Joyner iavf_send_vc_msg(sc, IAVF_FLAG_AQ_ADD_MAC_FILTER); 1302ca853deeSEric Joyner } 1303ca853deeSEric Joyner 1304ca853deeSEric Joyner /** 1305ca853deeSEric Joyner * iavf_add_mac_filter - Add a MAC filter to the sc MAC list 1306ca853deeSEric Joyner * @sc: device private softc 1307ca853deeSEric Joyner * @macaddr: MAC address to add 1308ca853deeSEric Joyner * @flags: filter flags 1309ca853deeSEric Joyner * 1310ca853deeSEric Joyner * Add a new MAC filter to the softc MAC filter list. These will later be sent 1311ca853deeSEric Joyner * to the physical function (and ultimately hardware) via the virtchnl 1312ca853deeSEric Joyner * interface. 1313ca853deeSEric Joyner * 1314ca853deeSEric Joyner * @returns zero on success, EEXIST if the filter already exists, and ENOMEM 1315ca853deeSEric Joyner * if we ran out of memory allocating the filter structure. 1316ca853deeSEric Joyner */ 1317ca853deeSEric Joyner int 1318ca853deeSEric Joyner iavf_add_mac_filter(struct iavf_sc *sc, u8 *macaddr, u16 flags) 1319ca853deeSEric Joyner { 1320ca853deeSEric Joyner struct iavf_mac_filter *f; 1321ca853deeSEric Joyner 1322ca853deeSEric Joyner /* Does one already exist? */ 1323ca853deeSEric Joyner f = iavf_find_mac_filter(sc, macaddr); 1324ca853deeSEric Joyner if (f != NULL) { 1325ca853deeSEric Joyner iavf_dbg_filter(sc, "exists: " MAC_FORMAT "\n", 1326ca853deeSEric Joyner MAC_FORMAT_ARGS(macaddr)); 1327ca853deeSEric Joyner return (EEXIST); 1328ca853deeSEric Joyner } 1329ca853deeSEric Joyner 1330ca853deeSEric Joyner /* If not, get a new empty filter */ 1331ca853deeSEric Joyner f = iavf_get_mac_filter(sc); 1332ca853deeSEric Joyner if (f == NULL) { 1333ca853deeSEric Joyner device_printf(sc->dev, "%s: no filters available!!\n", 1334ca853deeSEric Joyner __func__); 1335ca853deeSEric Joyner return (ENOMEM); 1336ca853deeSEric Joyner } 1337ca853deeSEric Joyner 1338ca853deeSEric Joyner iavf_dbg_filter(sc, "marked: " MAC_FORMAT "\n", 1339ca853deeSEric Joyner MAC_FORMAT_ARGS(macaddr)); 1340ca853deeSEric Joyner 1341ca853deeSEric Joyner bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); 1342ca853deeSEric Joyner f->flags |= (IAVF_FILTER_ADD | IAVF_FILTER_USED); 1343ca853deeSEric Joyner f->flags |= flags; 1344ca853deeSEric Joyner return (0); 1345ca853deeSEric Joyner } 1346ca853deeSEric Joyner 1347ca853deeSEric Joyner /** 1348ca853deeSEric Joyner * iavf_find_mac_filter - Find a MAC filter with the given address 1349ca853deeSEric Joyner * @sc: device private softc 1350ca853deeSEric Joyner * @macaddr: the MAC address to find 1351ca853deeSEric Joyner * 1352ca853deeSEric Joyner * Finds the filter structure in the MAC filter list with the corresponding 1353ca853deeSEric Joyner * MAC address. 1354ca853deeSEric Joyner * 1355ca853deeSEric Joyner * @returns a pointer to the filter structure, or NULL if no such filter 1356ca853deeSEric Joyner * exists in the list yet. 1357ca853deeSEric Joyner */ 1358ca853deeSEric Joyner struct iavf_mac_filter * 1359ca853deeSEric Joyner iavf_find_mac_filter(struct iavf_sc *sc, u8 *macaddr) 1360ca853deeSEric Joyner { 1361ca853deeSEric Joyner struct iavf_mac_filter *f; 1362ca853deeSEric Joyner bool match = FALSE; 1363ca853deeSEric Joyner 1364ca853deeSEric Joyner SLIST_FOREACH(f, sc->mac_filters, next) { 1365ca853deeSEric Joyner if (cmp_etheraddr(f->macaddr, macaddr)) { 1366ca853deeSEric Joyner match = TRUE; 1367ca853deeSEric Joyner break; 1368ca853deeSEric Joyner } 1369ca853deeSEric Joyner } 1370ca853deeSEric Joyner 1371ca853deeSEric Joyner if (!match) 1372ca853deeSEric Joyner f = NULL; 1373ca853deeSEric Joyner return (f); 1374ca853deeSEric Joyner } 1375ca853deeSEric Joyner 1376ca853deeSEric Joyner /** 1377ca853deeSEric Joyner * iavf_get_mac_filter - Get a new MAC address filter 1378ca853deeSEric Joyner * @sc: device private softc 1379ca853deeSEric Joyner * 1380ca853deeSEric Joyner * Allocates a new filter structure and inserts it into the MAC filter list. 1381ca853deeSEric Joyner * 1382ca853deeSEric Joyner * @post the caller must fill in the structure details after calling this 1383ca853deeSEric Joyner * function, but does not need to insert it into the linked list. 1384ca853deeSEric Joyner * 1385ca853deeSEric Joyner * @returns a pointer to the new filter structure, or NULL of we failed to 1386ca853deeSEric Joyner * allocate it. 1387ca853deeSEric Joyner */ 1388ca853deeSEric Joyner struct iavf_mac_filter * 1389ca853deeSEric Joyner iavf_get_mac_filter(struct iavf_sc *sc) 1390ca853deeSEric Joyner { 1391ca853deeSEric Joyner struct iavf_mac_filter *f; 1392ca853deeSEric Joyner 1393ca853deeSEric Joyner f = (struct iavf_mac_filter *)malloc(sizeof(struct iavf_mac_filter), 1394ca853deeSEric Joyner M_IAVF, M_NOWAIT | M_ZERO); 1395ca853deeSEric Joyner if (f) 1396ca853deeSEric Joyner SLIST_INSERT_HEAD(sc->mac_filters, f, next); 1397ca853deeSEric Joyner 1398ca853deeSEric Joyner return (f); 1399ca853deeSEric Joyner } 1400ca853deeSEric Joyner 1401ca853deeSEric Joyner /** 1402ca853deeSEric Joyner * iavf_baudrate_from_link_speed - Convert link speed to baudrate 1403ca853deeSEric Joyner * @sc: device private softc 1404ca853deeSEric Joyner * 1405ca853deeSEric Joyner * @post The link_speed_adv field is in Mbps, so it is multipled by 1406ca853deeSEric Joyner * 1,000,000 before it's returned. 1407ca853deeSEric Joyner * 1408ca853deeSEric Joyner * @returns the adapter link speed in bits/sec 1409ca853deeSEric Joyner */ 1410ca853deeSEric Joyner u64 1411ca853deeSEric Joyner iavf_baudrate_from_link_speed(struct iavf_sc *sc) 1412ca853deeSEric Joyner { 1413ca853deeSEric Joyner if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) 1414ca853deeSEric Joyner return (sc->link_speed_adv * IAVF_ADV_LINK_SPEED_SCALE); 1415ca853deeSEric Joyner else 1416ca853deeSEric Joyner return iavf_max_vc_speed_to_value(sc->link_speed); 1417ca853deeSEric Joyner } 1418ca853deeSEric Joyner 1419ca853deeSEric Joyner /** 1420ca853deeSEric Joyner * iavf_add_vlan_filter - Add a VLAN filter to the softc VLAN list 1421ca853deeSEric Joyner * @sc: device private softc 1422ca853deeSEric Joyner * @vtag: the VLAN id to filter 1423ca853deeSEric Joyner * 1424ca853deeSEric Joyner * Allocate a new VLAN filter structure and insert it into the VLAN list. 1425ca853deeSEric Joyner */ 1426ca853deeSEric Joyner void 1427ca853deeSEric Joyner iavf_add_vlan_filter(struct iavf_sc *sc, u16 vtag) 1428ca853deeSEric Joyner { 1429ca853deeSEric Joyner struct iavf_vlan_filter *v; 1430ca853deeSEric Joyner 1431ca853deeSEric Joyner v = (struct iavf_vlan_filter *)malloc(sizeof(struct iavf_vlan_filter), 1432ca853deeSEric Joyner M_IAVF, M_WAITOK | M_ZERO); 1433ca853deeSEric Joyner SLIST_INSERT_HEAD(sc->vlan_filters, v, next); 1434ca853deeSEric Joyner v->vlan = vtag; 1435ca853deeSEric Joyner v->flags = IAVF_FILTER_ADD; 1436ca853deeSEric Joyner } 1437ca853deeSEric Joyner 1438ca853deeSEric Joyner /** 1439ca853deeSEric Joyner * iavf_mark_del_vlan_filter - Mark a given VLAN id for deletion 1440ca853deeSEric Joyner * @sc: device private softc 1441ca853deeSEric Joyner * @vtag: the VLAN id to delete 1442ca853deeSEric Joyner * 1443ca853deeSEric Joyner * Marks all VLAN filters matching the given vtag for deletion. 1444ca853deeSEric Joyner * 1445ca853deeSEric Joyner * @returns the number of filters marked for deletion. 1446ca853deeSEric Joyner * 1447ca853deeSEric Joyner * @remark the filters are not removed immediately, but will be removed from 1448ca853deeSEric Joyner * the list by another function that synchronizes over the virtchnl interface. 1449ca853deeSEric Joyner */ 1450ca853deeSEric Joyner int 1451ca853deeSEric Joyner iavf_mark_del_vlan_filter(struct iavf_sc *sc, u16 vtag) 1452ca853deeSEric Joyner { 1453ca853deeSEric Joyner struct iavf_vlan_filter *v; 1454ca853deeSEric Joyner int i = 0; 1455ca853deeSEric Joyner 1456ca853deeSEric Joyner SLIST_FOREACH(v, sc->vlan_filters, next) { 1457ca853deeSEric Joyner if (v->vlan == vtag) { 1458ca853deeSEric Joyner v->flags = IAVF_FILTER_DEL; 1459ca853deeSEric Joyner ++i; 1460ca853deeSEric Joyner } 1461ca853deeSEric Joyner } 1462ca853deeSEric Joyner 1463ca853deeSEric Joyner return (i); 1464ca853deeSEric Joyner } 1465ca853deeSEric Joyner 1466ca853deeSEric Joyner /** 1467ca853deeSEric Joyner * iavf_update_msix_devinfo - Fix MSIX values for pci_msix_count() 1468ca853deeSEric Joyner * @dev: pointer to kernel device 1469ca853deeSEric Joyner * 1470ca853deeSEric Joyner * Fix cached MSI-X control register information. This is a workaround 1471ca853deeSEric Joyner * for an issue where VFs spawned in non-passthrough mode on FreeBSD 1472ca853deeSEric Joyner * will have their PCI information cached before the PF driver 1473ca853deeSEric Joyner * finishes updating their PCI information. 1474ca853deeSEric Joyner * 1475ca853deeSEric Joyner * @pre Must be called before pci_msix_count() 1476ca853deeSEric Joyner */ 1477ca853deeSEric Joyner void 1478ca853deeSEric Joyner iavf_update_msix_devinfo(device_t dev) 1479ca853deeSEric Joyner { 1480ca853deeSEric Joyner struct pci_devinfo *dinfo; 1481ca853deeSEric Joyner u32 msix_ctrl; 1482*e53a21abSEric Joyner u8 msix_location; 1483ca853deeSEric Joyner 1484ca853deeSEric Joyner dinfo = (struct pci_devinfo *)device_get_ivars(dev); 1485*e53a21abSEric Joyner msix_location = dinfo->cfg.msix.msix_location; 1486*e53a21abSEric Joyner msix_ctrl = pci_read_config(dev, msix_location + PCIR_MSIX_CTRL, 2); 1487ca853deeSEric Joyner dinfo->cfg.msix.msix_ctrl = msix_ctrl; 1488ca853deeSEric Joyner dinfo->cfg.msix.msix_msgnum = (msix_ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 1489ca853deeSEric Joyner } 1490ca853deeSEric Joyner 1491ca853deeSEric Joyner /** 1492ca853deeSEric Joyner * iavf_disable_queues_with_retries - Send PF multiple DISABLE_QUEUES messages 1493ca853deeSEric Joyner * @sc: device softc 1494ca853deeSEric Joyner * 1495ca853deeSEric Joyner * Send a virtual channel message to the PF to DISABLE_QUEUES, but resend it up 1496ca853deeSEric Joyner * to IAVF_MAX_DIS_Q_RETRY times if the response says that it wasn't 1497ca853deeSEric Joyner * successful. This is intended to workaround a bug that can appear on the PF. 1498ca853deeSEric Joyner */ 1499ca853deeSEric Joyner void 1500ca853deeSEric Joyner iavf_disable_queues_with_retries(struct iavf_sc *sc) 1501ca853deeSEric Joyner { 1502ca853deeSEric Joyner bool in_detach = iavf_driver_is_detaching(sc); 1503ca853deeSEric Joyner int max_attempts = IAVF_MAX_DIS_Q_RETRY; 1504ca853deeSEric Joyner int msg_count = 0; 1505ca853deeSEric Joyner 1506ca853deeSEric Joyner /* While the driver is detaching, it doesn't care if the queue 1507ca853deeSEric Joyner * disable finishes successfully or not. Just send one message 1508ca853deeSEric Joyner * to just notify the PF driver. 1509ca853deeSEric Joyner */ 1510ca853deeSEric Joyner if (in_detach) 1511ca853deeSEric Joyner max_attempts = 1; 1512ca853deeSEric Joyner 1513ca853deeSEric Joyner while ((msg_count < max_attempts) && 1514ca853deeSEric Joyner atomic_load_acq_32(&sc->queues_enabled)) { 1515ca853deeSEric Joyner msg_count++; 1516ca853deeSEric Joyner iavf_send_vc_msg_sleep(sc, IAVF_FLAG_AQ_DISABLE_QUEUES); 1517ca853deeSEric Joyner } 1518ca853deeSEric Joyner 1519ca853deeSEric Joyner /* Possibly print messages about retry attempts and issues */ 1520ca853deeSEric Joyner if (msg_count > 1) 1521ca853deeSEric Joyner iavf_dbg_vc(sc, "DISABLE_QUEUES messages sent: %d\n", 1522ca853deeSEric Joyner msg_count); 1523ca853deeSEric Joyner 1524ca853deeSEric Joyner if (!in_detach && msg_count >= max_attempts) 1525ca853deeSEric Joyner device_printf(sc->dev, "%s: DISABLE_QUEUES may have failed\n", 1526ca853deeSEric Joyner __func__); 1527ca853deeSEric Joyner } 1528